<< Newer Article #181 Older >>

Upcoming Changes, part 2

If there's one area that's been sadly neglected in MAME, it's been outputs. Most game PCBs have some means of communicating to the outside world, and while for the most part these outgoing signals are not important from a gameplay perspective, it is not in keeping with the spirit of a documentation project to neglect them as much as we have in the past. Over the years, a couple of standard outputs have been supported: 3 LED outputs have been commonly mapped to the num lock, caps lock, and scroll lock LEDs on your keyboard, and generic support coin counters has been present for a while now. When the old artwork system was introduced, it provided another means of connecting outputs to some kind of visual representation. But nothing tied any of this together. Furthermore, there was no generic means of supporting arbitrary outputs, like the pinball knocker in Q*Bert or other oddities.

In order to help rectify this situation, as of MAME 0.107u4 there is now a generic output support system. It's actually quite simple. You assign each output a name, and the driver calls a new function output_set_value() with the updated value. All the drivers that previously used artwork to indicate the state of an output have been changed to use this new function instead, and the new renderer now queries the output system to get the current state. In addition, the existing LED system now routes all of its outputs through this mechanism, using the names "led0", "led1", "led2", etc. However, a few outputs such as coin counters and ticket dispensing are not reflected this way. You'll see why in a moment.

So you're thinking to yourself, well, what good is this new system? Sure, internally this will help us properly document how the outputs behave on various games, but why make a big deal out of it? Well, if you've ever wanted to hook up a real pinball knocker to fire in Q*Bert or ever tried hacking MAME to route some output to an external connection, this is where it gets interesting.

In addition to keeping track of all the output states, the new output module also allows various components to register for notification when one of these states changes. In the Windows build, the OSD layer does just this, listening for changes in the outputs, and then providing a brand new mechanism for exposing these states to other applications running on your machine. This mechanism takes the form of a few simple custom windows messages that are sent to specially written listener clients. Writing a new client is quite straightforward, and I've even taken the liberty of writing an example client to show exactly how it's done.

Which is why I've removed the keyboard LED support from the Windows builds of MAME.

See, the keyboard LED support is a big hack, and as you all know, I'm not a big fan of hacks. But wait, all is not lost. I took this opportunity to write a little sample output listener client called ledutil.exe. Run this program in the background while MAME is running and you will have your keyboard LED support back. ledutil.exe simply uses the newly provided messages from MAME to do exactly what the old keyboard LED support used to do, but completely external to MAME. If you really like the keyboard LEDs, I recommend you just copy ledutil.exe into your startup folder and never worry about it again.

Here's a basic rundown of how the external messaging works:

When MAME starts up, it broadcasts a message (I call it OM_MAME_START) to all windows in the system letting them know what's going on. All non-listening applications will just ignore this message, but if you've written an app that knows about this message, you can listen for it and respond. Once you get the OM_MAME_START message, you need to respond to MAME in order to register to receive notifications by sending back an OM_MAME_REGISTER_CLIENT message. This tells MAME that you want to hear about changes in any of the outputs.

At this point, you'll start getting some OM_MAME_UPDATE_STATE messages. These messages contain the ID of an output and its current value. But wait, aren't outputs specified by name? Yes, but due to the limits of Windows messages, you only have a couple of integers to pass back and forth, so you will just get an ID.

The first time you see an ID, you'll want to figure out what name it maps to. In order to do that, you'll send MAME an OM_MAME_GET_ID_STRING message, which it will respond to with a standard WM_COPYDATA message. The WM_COPYDATA message is unique in that you can pass larger amounts of data between applications with it. In this case, MAME will respond with a copydata_id_string structure, which contains the ID you requested along with a string containing the output name. You should cache this ID-to-name mapping in your program so that you don't have to keep asking MAME what each ID is.

When you're finished listening, you can send MAME an OM_MAME_UNREGISTER_CLIENT message to tell it to stop sending you stuff. And when MAME shuts down, it will broadcast an OM_MAME_STOP message in case you need to reset any of your state back to normal (for keyboard LEDs we restore the original state at that time). This is also the signal to flush the cache of ID-to-name mappings that you have been accumulating.

And that's pretty much it. It sounds more complicated when I describe it here, but it's actually rather straightforward. The ledutil.c source code in the windows directory is set up in a way that you can change a couple of constants at the top, snip away the LED-specific code at the bottom, and drop in your own implementation which doesn't have to worry about a lot of the details.

I'm hoping this new functionality will inspire some of the BYOAC folks to update their MAME hacks to use this new solution instead, and come up with some other new cool ideas. I'm also hoping it will inspire folks documenting the outputs better in MAME proper, which is something I've been wanting to see for quite some time.