Second Helping of Pi

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 πŸ˜€ ).

15 thoughts on “Second Helping of Pi

  1. These are brilliant, thank you so much! Having a slight issue with my Raspi though… on the GB emulator (which is all I’ve tried thus far), the picture is too large and is cropped off the screen. Is it hardcoded to 1080p or something?

  2. I confirm that, I had the same issue, and it was fixed after installing the latest github kernel.
    Now I just need to find a bunch of good old roms πŸ˜‰

  3. Gcat,

    I’d like to be able to do what you did some day, for now I’m just an end user. Thanx for making this available for the public, it really gave me a couple hours of fun learning new stuff. It was my first time ever compiling something from source (although without the config & install steps apparently, very convenient thanx) on linux.

    I can confirm this to work on Wheezy, although I had to make some slight changes to the Makefiles (I tried both GameBoy and SMS emulators). They run quite smoothly, I must say. This is what I did (don’t know if it’s cool / safe what I’ve done, not a big Linux guru):

    Line:
    LDFLAGS+=-L$(SDKSTAGE)/opt/vc/lib/ -lGLESv2 -lEGL -lopenmaxil -lbcm_host /opt/vc/src/hello_pi/libs/libilclient.a

    changed to:
    LDFLAGS+=-L$(SDKSTAGE)/opt/vc/lib/ -lGLESv2 -lEGL -lopenmaxil -lbcm_host /opt/vc/src/hello_pi/libs/ilclient/libilclient.a

    and line:
    INCLUDES+=-I$(SDKSTAGE)/opt/vc/include/ -I./ -I/opt/vc/src/hello_pi/libs

    changed to:
    INCLUDES+=-I$(SDKSTAGE)/opt/vc/include/ -I./ -I/opt/vc/src/hello_pi/libs -I/opt/vc/include/interface/vcos/pthreads -I/opt/vc/src/hello_pi/libs/ilclient

    Maybe it helps somebody. Both emulators run fine on my Pi. Thanx again, can’t wait for an update that adds some music and sound to the mix!

    Cheers!

    • Thanks, interesting to know it works on the latest version πŸ™‚ might update it so it will work on both.

      The music and sound should be there, BTW… by default it will go to the HDMI, but you can pass the “-a” switch to make it go to the headphone socket instead.

      • Read your post thoroughly, and saw that sound should indeed work. Did not notice it working yesterday, but maybe that could be Wheezy (?). I’ll try what you said (also with headphone) and report back later…!

      • Reporting back to tell you that sound does indeed work under Wheezy for both emulators, but I needed to uncomment the following line in the configuration file (/boot/config.txt):

        hdmi_drive=2

        Apparently on my HD Ready 720p Philips TV, HDMI1 input is in DVI mode by default (??). I found this over here:

        http://elinux.org/R-Pi_Troubleshooting#Sound_does_not_work_with_an_HDMI_monitor

        It really is an enjoyable experience, this morning I played some Sonic with my 4 year old son, wonderful!

        I’d like to add either an old Rumblepad 2 (without the rumbling because of the power requirements over USB) or a PS3 controller or something to the mix via powered USB hub.

        Have you ever tried a joypad or a controller with one of your emulators? Do you have any tips / pointers about how to get started on this? It should probably be done thru some 3rd party program that translates button mashes into keystrokes, maybe you have an idea.

        • Glad to hear you and your son are having fun πŸ˜€
          I’ve never actually tried a proper controller, no… I’m not sure how they work. If it’s possible to configure them to act like a USB keyboard and just send key presses, they should work without any modifications to the emulators. Anything else, though, and I would probably need to add specific support for them…

  4. Thanks for all your hard work. I’ve been looking around and I can’t find how to fix this. When I run make,

    I get

    /opt/vc/include/interface/vcos/vcos_type.h:37:33: fatal error: vcos_platform_types.h: no such file or directory compilation terminated.
    make: *** [emulator.o] error 1

    You think you can steer me in the right direction?

  5. Hey, when I try and compile I get this error, can you steer me in the right direction πŸ™‚

    emulator.c:33:22: fatal error: ilclient.h: No such file or directory
    compilation terminated.
    make: *** [emulator.o] Error 1

    • Hi… it looks as if it’s not finding the libraries for accessing the GPU. Which distro and version are you using? The location was correct for the Raspbian distro, but I have to confess I haven’t updated for a while, they might have moved the libraries around again.

Leave a Reply

Your email address will not be published. Required fields are marked *

This site uses Akismet to reduce spam. Learn how your comment data is processed.