Multiplatform GNU Development

Nathanael Anderson

Issue #209, September 2011

Get a guitar synth working with Rock Band 3.

In my ideal world, mixing games and music would result in music games that use real instruments. Harmonix's Rock Band series is the closest mainstream realization of this lofty ideal, except for one major issue. I couldn't plug in my guitar and play pro guitar mode songs out of the box.

Now, before you think this is an impossible task, one important fact should be noted. I play a guitar synthesizer. What this means is my guitar has a hexaphonic pickup that reads and processes every string's signal individually and connects with a 13-pin cable to a guitar processor with midi out. This means my signal is already digital and, therefore, does not require any additional A/D algorithms in my software.

From left to right: custom-built guitar synth, custom-built rack for VG-99, Axon AX-100 and Fantom-XR.

Custom-built guitar synth, built by the author.

The Hardware

I have a few guitars with different 13-pin interfaces that can connect to an Axon AX-100 that has its midi out running to the midi in port on an M-Audio UNO, which gets connected to my Linux box running g2ghpro. The midi out port on the UNO then runs into a PS3 Rock Band adapter and into my PS3. A guitar hexaphonic guitar pickup with 13-pin midi out is required to run g2ghpro. The following lists are of tested hardware that will work:

Pickups:

  • Roland GK-3a.

  • Roland GK-2a.

  • Roland GK-3b.

  • Graph Tech LB-63 (any Graph Tech piezo bridge will work if using the hexpander module).

  • Godin Synth Access guitars.

Guitars with built-in 13-pin capability:

  • Godin LGX-SA.

  • Godin Freeway-SA.

  • Godin LGXT.

  • Roland Ready Fender stratocaster.

  • Brian Moore i8.13.

Guitar-to-midi converters:

  • Axon Ax-100.

  • Roland VG-99.

  • Roland GR-55.

  • Roland GR-20.

Of the listed hardware, I use a Roland VG-99, Axon Ax-100, Godin LGX-SA, Godin LGX with Roland GK-3a and custom-built Ibanez S540 with Graph Tech LB-63 and hexpander.

I've also tested g2ghpro with a Roland GK-3a pickup running into a Roland VG-99. Others have reported using a Roland GK-3a with GR-20 and GK-3b with GR-55 on a bass guitar as well. G2ghpro currently is the only solution for using a real bass guitar in the game, as no official bass guitar controllers have been released at this point.

The Original Controller

Harmonix created two guitar controllers for Rock Band 3 pro guitar mode. The first controller released was the Mustang, which is a “button” controller, with 102 buttons on the frets and six strings over the body of the guitar. When I wrote the initial version of g2ghpro, the Fender Squier Pro Strat wasn't on the market yet, which is the other pro guitar controller that works with the game. So I had midi dumps only from the Mustang to work with.

Midi

In order to understand how the Mustang worked, I first had to understand what the Mustang dumps meant and relate controller actions to messages sent. This required a refresher on the midi standard. Midi has 16 separate channels, and changing the sending channel is done by adding the value of the channel minus one to the message type value. My first example is a midi “note on” message, which has a decimal value of 144 in the first byte for channel 0. To send the same message on channel 6, add 5 to 144.

Example Data

Action: held fret one of low E and picked low E:

TIMESTAMP IN PORT STATUS DATA1 DATA2 CHAN NOTE   EVENT
0023E843    1      --     95    29    00  6 F 2  Note Off 
0023E843    1      --     95    29    7D  6 F 2  Note On 
0023E847    1      --     F0    Buffer: 8 Bytes System Exclusive
SYSX: F0 08 40 0A 05 06 7D F7

The dumps I had found came from a Windows program called Midi Ox, which showed the data in hex. The midi specification shows data in binary, and I was used to seeing this data with aseqdump in decimal. I converted all the examples I had been provided with into decimal so I could understand their behavior. The midi spec states that note on-and-off events contain 3 bytes of data. The first byte is event type plus channel; the second is note number, and the third is velocity. From experience, I've seen that many devices send a velocity event of 0 instead of an actual note off event, which is what the above shows. So, the result after it has been converted to decimal is (note: velocity zero below is really note off):

Type             Channel  Note  Velocity
(Note On 149)    5          41       00 
(Note On 149)    5          41      125

SysEx is short for System Exclusive messages, and they are free-form messages to send data that doesn't fit into the predefined midi message types. Initially, I tried to treat the data from the dumps as a normal midi controller, and I ignored the SysEx data in the dump, which I later realized is why I didn't have any code that made the game react. All game functions react to SysEx messages, not note events. This is why a guitar synthesizer cannot be plugged in to Rock Band and just work. At this point, I requested more dumps, where different frets were pressed down with the same string pressed.

I converted all the dumps I had to decimal and compared SysEx messages to note messages and found a correlation. Here's the resulting structure of the messages (displayed in decimal):

Part         1  2  3  4 5 6  7  8
Sample      240 8 64 10 1 1 43 247

  • Part 1: starting byte of a SysEx message.

  • Part 2, 3, 4: identifiers that this is a SysEx message used by the Mustang.

  • Part 5: message type (1 = set fret position, 5 = play string).

  • Part 6: midi channel (string on the instrument).

  • Part 7: midi note number.

  • Part 8: end SysEx message.

The Software

To explore the message format, I put together a quick program for sending a combination of note events and SysEx messages to the game. I know that the guitar synthesizer hardware required to use the software I was writing isn't very common, so I want to be proactive in removing any limitations to people using it. I've done midi and C++ programming with ALSA under Linux before, but never midi on Windows or OS X, and I wanted to be able to support all three to make the software more accessible.

From past experience with RtMidi, I knew it was written in portable C++, while supporting Windows, Linux and OS X.

The home page for RtMidi provides detailed, easy-to-read documentation, with examples for many basic midi tasks. Copy-and-paste examples are provided that give a base from which to start working, along with ready-to-compile demos provided in the tests directory in the RtMidi source code.

A good place to start with RtMidi is the bundled code in the tests directory. I started by modifying midiout.cpp and tried sending different SysEx messages based on my data dumps until finally I ended up with the following:


std::vector<unsigned char> sysExMessage;
sysExMessage.push_back( 240);
sysExMessage.push_back( 8 );
sysExMessage.push_back( 64 );
sysExMessage.push_back( 10  );
sysExMessage.push_back( 1); // 1 sets fret position, 
                            // 5 to play the current string
sysExMessage.push_back( channel + 1 ); // channel
sysExMessage.push_back( note );
sysExMessage.push_back( 247 );
midiout->sendMessage( &sysExMessage );

With that SysEx message, I was able to toggle fret position and strings played in the game. The actual logic to make this work was less than 100 lines. The full code is available in the Subversion repository for game2midi in g2ghpro.cpp.

RtMidi currently has issues processing active sensing messages that came from my Roland gear, which the author is aware of. A flag is provided to filter out active sensing messages. Setting ignoreTypes to true on your midi input object's third parameter will work around the issue until it is resolved—for example:

midiin->ignoreTypes( false, false, true);

The main missing feature of RtMidi, as far as the Linux pro audio world is concerned, is no jack-midi support.

The RtMidi documentation listed compiler flags for all three operating systems to link the required libraries, so all that was left for me to do was figure out how to compile under Windows.

Supporting Other Operating Systems

I hadn't touched a Windows development IDE in more than ten years, and I wanted to keep the same code base for all three operating systems. Somewhere during the past few years, I heard mention of MinGW (Minimalist GNU for Windows). As I am familiar developing in a GNU/Linux environment, this sounded like what I needed. To bring your Linux dev environment to Windows, use mingw-get-inst, and do a full installation. This will provide you with the MinGW Shell, bundled with many standard GNU tools, including SSH. Next, install TortoiseSVN, which is a Subversion client that integrates with the Windows shell. Checkout and commit actions are accessed by right-clicking on folders in Explorer to keep files in sync. The MinGW shell allows for changing drives' letters like a standard DOS shell with cd C:.

The next problem is how to build the code based on operating system. Let's look at two options: Makefiles and autotools. First, let's look at basic Makefile-based builds and compare the differences by platform:

# Makefile.linux

all: 
        mkdir -p deps
        g++ -DHAVE_CONFIG_H -I. -I.. -g -O2 -D__LINUX_ALSASEQ__ 
        ↪-g -O2 -MT midiio.o -MD -MP -MF deps/RtMidi.Tpo 
        ↪-c -o RtMidi.o RtMidi.cpp
        g++ -DHAVE_CONFIG_H -I. -I.. -g -O2 -D__LINUX_ALSASEQ__ 
        ↪-g -O2 -MT -midiio.o -MD -MP -MF deps/midiio.TPO 
        ↪-c -o midiio.o midiio.cpp
        g++ -g -O2 -o midiio RtMidi.o midiio.o -lasound

# Makefile.mingw

all: 
        mkdir -p deps
        g++ -DHAVE_CONFIG_H -I. -I.. -g -O2 -D__WINDOWS_MM__ 
        ↪-g -O2 -MT RtMidi.o -MD -MP -MF deps/RtMidi.Tpo 
        ↪-c -o RtMidi.o RtMidi.cpp
        g++ -DHAVE_CONFIG_H -I. -I.. -g -O2 -D__WINDOWS_MM__ 
        ↪-g -O2 -MT -midiio.o -MD -MP -MF deps/midiio.TPO 
        ↪-c -o midiio.o midiio.cpp
        g++ -g -Wl,--enable-auto-import -O2 -o midiio RtMidi.o 
        ↪midiio.o -lwinmm 

The library I used, rtmidi, requires that the platform be defined, so for Linux, define -D__LINUX_ALSASEQ__, and for Windows, define -D__WINDOWS__MM__. The last step in each is the linking phase, where you specify system libraries to link to the binary. To enable a clean build under Windows, I had to add -Wl,--enable-auto-import, so functions would be auto-imported.

Now, let's look at autotools-based builds. Usually when an autotools-based build is committed to version control, only non-generated files are committed, which includes configure.ac, Makefile.am and src/Makefile.am. The standard practice is to create an autogen.sh script that will call the files to generate configure, Makefile and other required files from *.ac and *.am files:

# Autogen.sh
#!/bin/sh
aclocal
autoreconf
automake --add-missing --copy
autoreconf
libtoolize -f --automake

configure.ac (Listing 1) contains host-based auto-detection and is where to specify which host-based libraries to check for and link against.

Full code for these examples can be downloaded from the game2midi project's Subversion repository in the basic-midi-io-example folder.

Conclusion

Using GNU libraries and tools can help reduce the time and effort required in supporting multiple platforms. I hope this article encourages you to consider adding multiplatform support to a current or future open-source project.

Nathanael Anderson has been a UNIX systems administrator for five years. Family, coding and all things guitar keep him active. Feel free to contact him on his blog at wirelessdreamer.com.