Unsurprisingly, I found a few spare hours this weekend to work more on the Raspberry Pi. (Though I was very restrained and didn’t work on it non-stop… did still go dancing one night and out for a walk to take some nice photos yesterday afternoon. I know what it does to my mood if I spend a whole weekend cooped up coding, even if I am tempted to at the time).
First I finished up the Master System emulator. I added in a border to stop the graphics going off the edge of the screen, then turned my attention to the more challenging requirements: keyboard input, sound, and timing.
Getting input from the keyboard isn’t usually a particularly challenging thing to do… not for most programs, anyway. But for console emulators it’s a bit more involved, for two reasons:
- we want to be able to detect when a key is released, as well as when it’s pressed
- we want to be able to detect multiple keys being pressed at once (for example, the right arrow and the jump key)
I tried various ways of doing this – firstly, the way I used in emulators I’d written for Windows previously: the SDL library (this library can do lots of handy things and keyboard input is only one of them). But although the library was installed on the Raspberry Pi and I was able to link to it, I couldn’t detect any keyboard activity with it. Eventually I found out you can perform some arcane Linux system calls to switch the keyboard into a different mode where it will give you the information I needed. This only works from the real command line, not from X Windows, but it was better than nothing. (You also have to be very careful to switch the keyboard back to its normal mode when your program exits, otherwise the computer will be stuck in a strange state where none of the keys do what they’re supposed to do, with probably no way out other than turning it off and on again!). I still want to find a way to make it work in X Windows, but that’s a project for another day.
(I wrote a more technical blog post here about the keyboard code in case anyone wants to use it).
While reading the keyboard turned out to be a bit harder than I’d hoped, this was more than made up for by how easy it was to get the sound working. In fact I found I was able to re-use most of the code from the audio playing example program that came with the Pi. The only slight strangeness was that it seems to only support 16 or 32 bits per sample rather than the more standard 8 or 16, but it’s easy enough to convert the 8 bit samples generated by my Master System sound code to 16 bit. I didn’t know whether the Pi was expecting signed or unsigned samples, but the din of horribly distorted noise that greeted me the first time I tested the emulator with sound confirmed that it was the opposite of whatever I was giving it. That was easy enough to fix too.
As for the timing, it turned out to be a non-issue – the sound playing code will block until it’s ready for the next batch of sound data anyway, so this will keep the emulation running at the correct speed. (Actually it’s a non-issue for another reason as well, but I’ll get to that later).
(It’s amazing how enormous the pixels look now. I’m sure they never did when I was playing with a real Master System on a telly almost as big back in the 90s. I suspect it was just the general blurriness of TVs back then that masked how low resolution the graphics really are).
Since my first Raspberry Pi emulator had been easier than expected, I decided to port another one – my Android Gameboy emulator should be do-able by welding the head of Raspberry Pi-specific code I’d just written for the Master System one onto the body of behind-the-scenes code from the original Android version of the Gameboy and making a few important tweaks to make them look as if they match up. So that was what I did.
“This’ll be a breeze”, I smugly thought. “I’ll be done in a few minutes!”. But it wasn’t quite that easy…
I was mostly done in a few minutes (well, maybe half an hour) – graphics were working and I could play Tetris or Mario. But the sound was horrible. Really horrible. Not just normal-Gameboy-music level of horrible… something was clearly very wrong with it. I checked and double checked the code over and over but still couldn’t see the bug. I hadn’t changed the sound output code very much from the Master System, apart from changing the sample rate slightly and switching from mono to stereo. I switched back to mono again. No change. I tried a more standard sample rate (22050Hz instead of 18480Hz). Nope, now it’s horrible and completely the wrong pitch.
I puzzled over this one for a long time. I tried various other things I could think of, rewriting the code in different and increasingly unlikely ways, but nothing seemed to make a difference. The only thing I established was that the sound buffer was either not being completely filled or was underflowing – when I tried filling it with a constant value instead of the Gameboy’s sound output, I still got the horrible noise (a constant value should give silence). But why??
Eventually I cracked it, and learnt something in the process. I noticed that Mario seemed to be running a little bit slower than it should, and I wondered if the emulator was not actually running fast enough to process a frame before the sound buffer ran out. That would certainly explain the sound problem… but didn’t seem like it should be happening. The same emulator code had no trouble reaching full speed on my slower HTC Wildfire, it should be no problem for the Pi to manage it as well. On a hunch, I tried reducing the sound sample rate quite a lot. Finally a change! Sure, the game was running slower and the music was now sounding like a tape recorder with a dying battery… but for the first time the horrible noise was gone! Then I had a thought: what if the graphics code is locking to the frame rate of the TV? The Gameboy screen updates at 60Hz, but UK TVs only update at 50Hz. Trying to display 60 frames in a second when each frame is waiting one-fiftieth of a second is not likely to work very well. Sure enough, only outputting every second frame (so running at 30 frames per second instead of 60) cured the problem completely. It had never occurred to me that this could happen… I was so used to programming PCs, where the monitors have all run at 60Hz or more for decades, that I forgot the little Pi connected to my TV would be different.
Anyway… I decided to tidy up the code and release it in case it’s of interest to anyone. So if you head on over to my emulators page, you can now download the source code of both emulators for the Raspberry Pi along with detailed instructions for using them. Enjoy 🙂
(A word of warning… I wouldn’t say they were examples of good programming practise. The CPU cores and graphics and sound rendering code are written in ARM assembly language, which I only did because I wanted to learn it at the time – C would be a better idea if you wanted to write an emulator that’s easy to maintain and extend, and probably would be fast enough to emulate the old 8-bit systems).
(Another word of warning… I have some more things in the pipeline that might be more interesting than these two 😀 ).