Sep 30, 2008

Ruby Scoping Gotcha

One little thing you may need to remember when coding in Ruby. Consider this little program:
myArr2D = [ [2, 2], [2, 2] ]

myArr2D.each do |m|
x = m.map { |m| m * 2 }

puts m.class.to_s
end
Intuitively, this should output this:
Array
Array
However it outputs this:
Fixnum
Fixnum
What happens here is that the variable m in the map block overshadows the outer variable m, so that whenever you access the variable m after the call to map, you're accessing the inner variable. This might lead to some unexpected side effects, so make sure you keep it in mind...

Sep 29, 2008

Vimperator

A few days ago on a previous post I posted about how I was getting used to Vim and was liking it. A commenter mentioned Vimperator, which is a Vim-like plugin for Firefox. It basically takes Firefox and gives it a Vim-like interface.

It's pretty good. One may wonder why you would want to use something like this for a web browser, which is something that is inherently a mouse-based application.

If you think about it, what are the main things you do with a web browser? Open URLs, scroll, type text into text areas, and click links. At least that's what I mainly do. What Vimperator does is put most of these into keyboard commands.

For typing a URL, instead of pressing Alt+T (which is what I believe the shortcut was) you push 'o'. It is a much less awkward shortcut. What it does is begin entering the :open command, and then you type what it is you want. It even combines the address field with the search field, so that if you enter something that isn't a web page it sends you to a Google search. It's also nice because it has tab-completion.

For typing things into input boxes or text areas, and for clicking links, you have "hints mode". Press 'f', and it pops up a little number next to all the interactive components on your screen. You then hit the number and it acts as though you clicked the component (to open something in another tab, use 'F' instead). Pretty neat! The only problem with it that I've found is that in GMail half the "links" are actually span tags with onclick attached to them. This confuses Vimperator, as it doesn't realize that they are interactive components and doesn't give them numbers in hints mode. Note that you can still use everything the way you used to.

Finally, scrolling works the way it always has, but you can also use the hjkl shortcuts too to move around the page. Sounds useless, but saves you the effort from moving your hand all the way over to the arrow keys, and then having to move your hand back when you're done scrolling.

My other Firefox plugins like Firebug, Greasemonkey, HTML Validator, they all work as they used to.

It's probably not for everybody, it is a power tool. By default it takes away all the stuff at the top like the back button, menu bar, etc. You can get these back, but it is not the default. I wouldn't recommend it to people who don't want to take the few minutes or so to get used to it. I've had people sit down at my computer when I had Vimperator enabled and had no clue how to type in a URL (just press 'o'). So that's your warning. I like it, but you may not.

UPDATE: I stopped using Vimperator because it makes Firefox very slow. For a while I just thought it was Firefox, but it ended up being Vimperator so I scrapped it.

Sep 28, 2008

JRuby and SQLite

I've heard some fuss about JRuby not supporting SQLite. Personally, this doesn't bother me since I've stuck with MySQL, but some people might be interested. Here's how to get it working (this is for Ubuntu, but I don't think it'd be that different on other systems so long as you know how to edit files and install gems).
jruby -S gem install activerecord-jdbcsqlite3-adapter
This installs the JDBC Sqlite adapter, and should include any dependencies. If it doesn't, you need:
jruby -S gem install jdbc-sqlite3
After that, just edit config/database.yml to use the jdbcsqlite3 adapter instead of the normal one:
development:
adapter: jdbcsqlite3
database: db/development.sqlite3
timeout: 5000
Presto! You're done.

Note that I'm assuming you're using Rails here, if not then you don't need the activerecord gem.

Sep 27, 2008

Ubuntu Game Experiment

On occasion I like to revisit the Linux gaming scene. No, it is not because I like to see horrible failures, rather I've thought of an interesting experiment.

Linux will not catch up to Windows or consoles in terms of hard-core games, at least in the next few years. These games take a lot of manpower to produce, and if the leaders of that manpower do not want to release on Linux, then it won't get released on Linux. Even under wine, the performance sucks a bit - I have Oblivion and Guild Wars working fine under wine right now, but they get a much lower FPS. I'd rather just reboot to Windows and use my graphics card to its full potential (I paid for it didn't I?).

I think too many people are trying to get the hardcore gamers to switch to Linux by making their games work. Personally, I think this is a bad idea. Hardcore gamers are among the biggest bitches I've ever seen, just go on Battle.net or something and listen to them talk. It's retarded. Why would we want these people polluting Ubuntu forums with their crap?

What more focus should be put on is the other 90% of gamers. The ones who like Frozen Bubble or Those Funny Funguloids, and only play once in a while - among this 90% are those people called girls, which last I checked are severely lacking in the Linux world.

Anyway, the moral of my story is that instead of targeting the niche market of hardcore gamers as would-be Linux converts, why not focus on everybody else?

Sep 25, 2008

Rails Fixtures Order

So I've been having some trouble with Rails and fixtures. What I have in my fixtures are two tables, we'll call them t1 and t2. There is also a join table between these two tables, which has some info about the relationship between rows in the two tables.

Now suppose I have n1 fixtures for t1, and n2 fixtures for t2. That means there are O(n1n2) fixtures in the join table, in my case I have an entry for every pair. It would be a huge pain in the ass to enter all that data into the fixture manually. So what I do is just
t1 = Table1.find(:all)
t2 = Table2.find(:all)
t1.each do |r1|
t2.each do |r2|
#output fixture YAML
end
end
There is one problem with this. If the fixtures for Table1 and/or Table2 are not run before the fixture for JoinTable, then you're going to run into problems.

There are two things to do. The first one is in any controller test class, when you put your fixtures thing at the top, you put it like this:
fixtures :table1, :table2
fixtures :join_table
This seems fairly intuitive, but my first intuition was to put it like this:
fixtures :table1, :table2, :join_table
Then I had an epic brain fart trying to figure out why it wasn't working.

The second thing you need to do only needs to be done if you use the db:fixtures:load rake task. What this does is it loads your fixtures into your development database, which is very handy for coding. When you're in the development phase of your app, you don't need to create new migrations for your DB, just edit the old migration, and run db:migrate:reset. Makes things cleaner and easier to follow IMO.

However, this loads things in alphabetical order. You could name all your tables to be in the order that they should be loaded, but this is slightly annoying. The solution is to tweak your environment.rb file. Just add (EDIT: the other one didn't always work for me, I changed this so it does work):
ENV["FIXTURES"] ||= "table1,table2,join_table"
to config/environment.rb, and you will get the correct loading order.

EDIT: Always remember that when you add a new model, you'll need to manually add it to this list or your fixtures for that model will not be loaded. Learned this one the hard way, wondering why the fixtures were being loaded properly for tests, but not for the dev database.

EDIT (again): This doesn't always work, but it seems to work more often than if you didn't put this. The best option would be to load in fixtures, load whatever time-dependent stuff you have manually, and write a small script to export the DB into the YAML fixtures. That's what I ended up having to do finally, and it works like a charm.
Another thing if you don't want to do this is to create another script to do it for you. So instead of doing the normal rake task, you can have a script like this:
`rake db:fixtures:load`

# run whatever tasks you need ...
Run this script with script/runner so that it has access to your Rails models and what-not, and you'll be able to generate data automatically. You'll also have to load your file in from test/test_helper.rb during the setup() method so that your fixtures get loaded properly into tests.

Sep 24, 2008

WEBrick and Authentication

Picture this scenario: You are working on a Rails project. Your team (not just dev people, but any others like marketers, etc.) is distributed, so you're not all in the same office - and hence can't have any sort of internal network. You have a server somewhere for centralizing things via SVN, and you put other tools on it like Trac. That kind of thing is pretty easy, and with Apache you can just throw up some AuthType Basic stuff to keep unwelcomes out.

However, I want to make it so that the development version of the web app is viewable to non-dev people. Now for dev people, it's a requirement that they can get the code onto their machine and use it without relying on the central server to do work. So they have to be able to get MySQL up and running, install Ruby (or in the case of my project, JRuby), and anything else. But for the non-techies, how do they get everything up and running? They're probably running Windows too (it's funny, the entire dev team that I'm working with runs Mac, except me, who runs Ubuntu), which means that installing MySQL and all that will be a pain in the ass.

The first thought is maybe use Glassfish or something to deploy the semi-finished app, and then put some password lock. But that sounds like a lot of work. You need to WAR that shit up, and re-deploy it every time you do an update. Not cool. Why not just use WEBrick, which comes with every Rails project, and is as simple as going 'jruby script/server'?

The problem is when you want to password protect everything. Ideally, we don't want to have to make code changes. We want it so that on our local machines, we don't have to enter a password to see the site.

The first solution was to use Apache for authentication, then proxy over to WEBrick, who's port (3000) is not open to the outside world. This would work in theory, except that mod_proxy gets invoked before any authentication can happen. So even with the auth statements in there, it still just proxies over to WEBrick without asking for anything. Not cool.

Next solution: authenticate, then rewrite. Put in some authentication stuff, then mod_rewrite everything to localhost:3000. Authentication worked, rewrite didn't. I have no idea why. I would put in [P], but that would give a 404. Using anything else would result in a direct rewrite, and would redirect you to your own localhost:3000, which obviously would not give anything unless you had WEBrick running on your local machine (good thing it wasn't, or I would've been mightily confused until I looked at the address bar).

So my final solution was to modify the code. This in itself was a pain in the ass. There are many different ways to use HTTP authentication with rails. Rails has it baked in to use HTTP authentication, but not to use our htpasswd file. This meant that everybody had to have another username and password that was stored with the application just to access this little thing. As a coder, I find this level of duplication revolting, and so I attempt to write a little bit of code to check our htpasswd file to see if it's the right password entered. On Linux, by default, htpasswd uses the system's crypt() function to encrypt thing, which in Ruby translates to System#crypt. It unfortunate takes a salt to encrypt things (well, fortunately for security reasons, unfortunately for me since I didn't know the salt). I couldn't figure out the salt, so that ended up being wasted effort.

Then I found this beautiful thing. It is a plugin for Rails that lets you use an htpasswd file for HTTP authentication. It probably does more than that, but this is exactly what I wanted - well almost, I didn't want to make any code changes, but c'est la vie. It was one line of code:
htpasswd :file => '/path/to/passwords'
Put that in app/controllers/application.rb, and you've got your password locking. Now I can make WEBrick accessible to the world, and only the people with a username/password can see anything. Awesome.

I learned a lot during this adventure, about Apache and Rails Authentication and (rant alert!) how frigging useless #rubyonrails is when you have anything slightly advanced to do. I've spent a fair bit of time in there, and can answer the majority of questions people ask, because for the most part they are asking the questions because they're too lazy to read a good Rails book or google for an answer (which is what I do sometimes when I don't immediately know the answer). Every time I have asked something in there it has been something relatively advanced, and the response is either "figure it out for yourself", or silence. The first is a reasonable enough answer, given the standard questions that get asked in there, but not entirely helpful...what do they think I've spent the last hour or so trying to do? Silence is ok too, since if you don't know the answer then you're not expected to say anything. But still, both results are pretty useless.

What is still on the table: How to get WEBrick to run as a daemon with JRuby. The JRuby implementation has disabled the use of fork(), so using the -d flag for WEBrick is not an option. I'll have to write a daemon script or something.

Sep 22, 2008

Vim, revisited

A few months ago (just over 3 in fact) I posted about having begun to learn vi1. Since then, I've learned a lot about it, discovered several plugins, and many times attempt to hit Esc after typing into Firefox. Or use hjkl to navigate in a text area. The only other program I now use to edit text is OpenOffice, mainly because it's a little difficult to get fancy charts and things into Vim. Also I submitted a paper in monospaced font with no formatting, the prof might be a little annoyed. You might think it overkill to use Vim for something simple like jotting down notes, but the funny thing is that Vim starts a fair bit faster than any other graphical text editor on my machine, like GEdit or Kate.

I've replaced my IDEs with it. I used to use Quanta, but it is slow to boot, and is once in a while unstable. Once in a while it will crash when I use the built-in FTP. And when I mean crash, it not only crashes Quanta, but the entire X server goes down. Slightly annoying.

Your productivity is improved by a fair bit when you start using this. Due to the mode-based editing, it is much easier to type commands than using Ctrl/Shift/Alt/some-combination-of-the-three, especially when you want more complex things. Want to delete a line? Press dd. Swap two characters? xp. One I use a lot is Ctrl+6 (or Ctrl+^ without pressing Shift), which opens the last file you had open. Kinda like how in Half-life you press q to get to the last weapon. On that note, I wonder how games would play if you could differentiate between q and Q... I guess you wouldn't be able to use Shift for sprint anymore.

You can even record a set of keystrokes, and bind that set of keystrokes to a key: press q, then the key, call it k. Every key you type will be recorded. Then press q to stop recording. Then later on when you want to use that recording, press @ then k. My only problem with this is that @ is a little awkward to do over and over, but there is probably a rebinding of keys.

It doesn't just end with the keyboard shortcuts. There are plenty of plugins for Vim. I have three favourites:
- VTreeExplore - it is a window in Vim (btw in Vim you can split windows, just like most fancy editors) that shows a directory tree. Very handy. Others have written about it too.
- Surround - when typing contexts (like dw or d$, which are delete word and delete from-cursor-to-end-of-line, respectively) you now can use s, which affects the surroundings around a bit of text. Type ds( to delete the parentheses around something. Type cs{[ to switch the curly brackets to square brackets.
- Vim's Rails plugin - This does more than just syntax highlighting. It adds some very helpful things for file navigation (something that is a fair bit annoying in Vim). If your cursor is over a model or controller name, you can press gf to go to that file. If you're in a view or model, press :Rcontroller (this uses tab auto-completion too, so just type :Rcont and hit tab) to jump to the controller. Similarily for jumping to models. If you're in a controller action, you can jump to the view. It's all pretty handy, and there are probably plenty of shortcuts that I don't know about. You can read here to learn more about Vim+Rails.
Note: I know at least one person is going to mention Textmate. Two things: I don't use a Mac (nor do I intend to any time soon), and I don't like to pay for software.

So it's been over 3 months and I'm not turning back. In fact, this was pretty much the case after a few weeks, and I am continually learning more. I recommend it to any programmer. You can also try Emacs too, I think it does the same kind of stuff and it is mostly a matter of preference - kinda like Ruby vs. Python ;).

1 Technically, it's GVim, which is the graphical version of Vim, which is an open-source remake of an older text editor called vi, but these are just details.

Sep 18, 2008

The 64-bit Revolution

I've been wondering recently, how long did it take after 32-bit processors came out for everyone to switch to 32-bit? 64-bit processors have been out for quite some time now, and pretty much any new computer you buy nowadays is 64-bit. Yet the support for 64-bit systems, while growing, is still fairly limited - unless you're in Ubuntu, in which case pretty much everything works, I'm told Flash is a big pain to set up in Gentoo for 64-bit versions of the OS.

In my efforts with FreeGamage, I discovered many games which wouldn't work right on 64-bit. I dig through the code a bit and a lot of the time it's because they assume pointer sizes are the same as int sizes, which on my machine they are not. Pointers are 64-bit, ints are 32-bit. This leads to some problems, as they'll assign a pointer value to an int value, which cuts off the higher 8 bytes and then there are segmentation faults when they attempt to convert the int back into a pointer and dereference it. This is bad practice, but it doesn't stop people from doing it.

I believe that the big switch to 64-bit computing probably won't come for a while. Why? What are the benefits of switching to 64-bit? It's hard to say, but I don't know if it is that much faster than 32-bit. You lose compatibility with many 32-bit programs. You need different drivers - even in Windows this is a problem.

The major limitation of 32-bit that I can see is when it comes to RAM. Let's do a little math. In theory, a 32-bit register (ie. the memory address register used to access RAM) can hold 232 possible combinations. 232 = 22 * 230 = 4 * 230. As most of us geeks know, 230 is the size of a gigabyte. So the maximum amount of RAM that can be accessed by a 32-bit register is 4GB. In practice, I'm guessing it is slightly smaller than this because Windows XP on my desktop can only see 3.2GB, when the system has 4GB. On a 64-bit system, you can theoretically have up to 16 * 260 = 16EB of RAM. We don't even see EB in practice yet, not even on a hard-drive. Hell, we don't even see PB in practice yet, which is 0.1% of an EB. EB is exabyte, which is a million TB, or a billion GB. That's a lot of RAM. Maybe we'll see EB hard-drives by 2020, but RAM is still pretty far away.

Because of the limitations on RAM, anywhere you see RAM intensive processes, you should see it switching over to 64-bit. On the desktop, I'm thinking one of the first ones to do this will be games. Games demand gobs and gobs of RAM, and coupled with Vista, which also demands gobs and gobs of RAM, you're probably going to be hitting your 32-bit peak pretty quickly. A nice 64-bit system will be able to handle all the RAM that games will require in the next few years or so.

Sep 15, 2008

Coding Tests in Interviews

I'm reading this Slashdot article about IT professionals being tested on the interview. There seems to be two minds about this, some people hate it and thing that it's disrespectful, others think it is mandatory. What about you?

I'll be honest, I've never been asked to write code in an interview (as far as I can remember). This is probably because either I did so poorly on the pre-code sections that they didn't even want to bother, or I did so well on the pre-code sections that it was just assumed I could code. One company I worked for started giving coding questions after I had started, but I never had to take it (I probably would have mucked up a few questions).

This is a difficult question to ask. The argument Slashdot puts forward is that companies don't ask other professionals these kinds of questions on the interview, so why should they ask IT professionals? It seems fairly disrespectful, they say. If somebody has several years experience, a degree, certifications, etc. it should be a fairly good indication that they can code.

On the other hand, there are a lot of bad coders out there. Some of them even made it through university. Imagine random guy Joe in high school, with excellent interpersonal skills and a passing interest in computers. He hears one day through some survey that graduates of computer science (or a related discipline that has computer or software in its name) get paid a fair bit more than everybody else. He goes to school to study this stuff, picks a school with a relatively easy program, and squeaks through with 50's. He goes off and works for some smallish company for a while doing simple in-house software, doesn't do it too well but they keep him around anyway because as mentioned before, he's a nice guy. He's now got a few years experience under his belt, plus a shiny degree, which can pad up his resume fairly well (it'd probably look better than mine).

Now Joe goes and applies at a new place, hoping for a higher paycheque. What happens if they don't give him code samples? He could probably get in fairly easily. He's got experience, he's got a degree, and he's a nice guy. What more could you want? Well, Joe can't write a program that swaps the values of two variables. Nor can he write FizzBuzz. Yet he gets the job over some new grad hotshot who went through with A's but has no real work experience.

So this is a perfectly good reason as to why companies would give coding tests during interviews. Do I blame them? Not really. However, it does depend on the coding questions. For the company I mentioned above (which happened to be the first job I got out of university), they give a question on CSS, on how to make it so that a box on a web page can have rounded corners, but be able to expand and fit any amount of text. Pretty easy right? I probably wouldn't have gotten it. My CSS skills when I graduated were sadly lacking - I'm still not incredible with it, makes me wonder why I'm a web programmer. I probably would have given some crap with <img> tags relatively positioned a bit, with some IE specific file somewhere. I didn't know about the whole background-image field. Yet it took about 2 minutes looking at how someone else did it for me to be able to replicate it. Some coding tests, from what I've seen, fail to take into account that people are capable of learning.

This is where the 3-month probation period comes in. I think that this time is good enough for both the company and the employee to see if they are a good fit for one another. If the coder sucks, then the company can let them go after the 3 months. If the company sucks, the coder can leave. It's not perfect, but it is a whole lot better than letting the interview alone decide everything.

Sep 14, 2008

Checking out Xubuntu

There's a computer at work that is a little bit slower than my home computer. The CPU isn't much slower, but there's a lot less RAM.

I've noticed that while coding, the system was eating up a lot of memory. A lot of it was coming from GNOME itself, and compiz. So I installed the xubuntu-desktop package and am now trying out XFCE.

It's blazing fast! Runs really well. There are a lot less features than in GNOME which is expected, but everything is very clean.

The one thing that really surprised me is that the default Xubuntu look is a bit cooler than the default Ubuntu look. I kinda liked it and didn't even bother changing it!

So if you have an older PC that you would like to stick Ubuntu on (maybe your grandma's, I know how much Linux users love to do this), the Xubuntu is definitely something worth checking out. Be careful though, I think the system requirements for Windows XP are still lower than Xubuntu, so you might actually be making their computer slower by sticking Linux on it.

On another note, I hate to put ads on my blog, but if anybody knows a good Rubyist in Montreal (or a good web developer willing to learn Ruby), let me know. I'm looking for someone to join my team.

Sep 1, 2008

Rock Band Drums in Linux

I announced some time ago that I had gotten a Wii, and the other day, I finally found Rock Band for it (they released it back in June, but unfortunately they didn't ship it with French manuals so they didn't get it in Quebec at the major retailers, had to go to a smaller game shop to get it).

One thing I noticed about it is that all the instruments are USB devices. So of course, the geek in me wonders, "Hmm, maybe I could hook that up to my computer...". So I tried it. I used the drums, since they're my favourite instrument in the game.

To get Linux to recognize it was simple for me. I just plugged it in. You can try it for yourself, type "lsusb" with the drums plugged in, and when they're not. You should see a line that disappears. I get this:
Bus 002 Device 006: ID 1bad:0005
It doesn't say what it is, but that's no biggie.

UPDATE (Nov. 13, 2008): In Intrepid 64-bit, the joystick no longer works. If you're having problems, click here. Also I've written a follow-up post if you actually want to download something to look at.

Now the hard part is to get it to work with your programs (it's not actually that hard). The funny thing is that the drum kit is actually a joystick, at least as far as the computer knows. In effect, the little D-pad is the joystick and all the drums/buttons/pedal are buttons. So you can use anything that interfaces with a joystick in order to use the drums in your program. I used SDL for this, which is a library for simple access to devices.

In order to use SDL to access your drums, you need a platform that supports SDL. Fortunately SDL is supported on a wide variety of platforms, so you should be OK. For this tutorial I'll be talking about Ubuntu Linux with g++, as that is what I used.
Next, you need a language with bindings to SDL. This is a lot of languages. I used C++, but you could write it in Haskell if you wanted to.

I make no guarantees about the drum kits for other systems like PS3 or XBox 360. I'm using the Wii version. I also don't know if it will give the same values for Windows or Mac OSX (don't see why it wouldn't).

So let's start. We'll do a bit of initialization:
#include <SDL.h>
#include <SDL_mixer.h>
#include <iostream>

using namespace std;

int main(){
if (SDL_Init(SDL_INIT_JOYSTICK | SDL_INIT_VIDEO | SDL_INIT_AUDIO) < 0){
cout << "Something messed up. :(" <<endl;
exit(1);
}

atexit(SDL_Quit);
What this does is initalizes SDL. We want to initialize the joystick so that we can access the drums, we want to initialize video so we can create a window (for some reason the events were messed up when I didn't have a window) and you'll want sound if you actually want to play sounds with your drums. Then we tell the system to call SDL_Quit when the program exits. This is good to clean up after ourselves.
Note that I include the SDL_mixer library, this makes it a lot easier to play sounds.

Now we want to initialize the joystick. It's really easy. I'm going to skip error checking and assume you only have one joystick plugged in and that it will work the first try. If you have multiple joysticks plugged in (or devices that pretend to be joysticks, like the drums), you can use SDL_NumJoysticks() to see how many you have. Then you can iterate over them and call SDL_JoystickName() to see the name of the joystick. Choose the one that says "Nintendo Wii Drum Kit" or something like that in it.
//here I assume you have the joystick at 0,
//if not replace it with a different number
SDL_Joystick * joystick = SDL_JoystickOpen(0);

//make it so that events are triggered for joysticks
SDL_JoystickEventState(SDL_ENABLE);
Ok, so our joystick is enabled. Let's load some sounds now. You can see the docs for the SDL_mixer functions here if you want to know what they're doing.
Mix_Chunk * sounds[5];
const char * waves[] = {"bass.wav", "crash.wav", "hihat.wav",
"snare.wav", "kick.wav"};

if (Mix_OpenAudio(22050, AUDIO_S16SYS, 2, 4096) != 0){
cout <<"Couldn't open audio device: " <<Mix_GetError()
<<endl;
exit(1);
}

for (int i = 0; i < 5; i++){
sounds[i] = Mix_LoadWAV(waves[i]);

if (sounds[i] == NULL)
cout <<"Loading sound " <<waves[i] <<" failed:"
<<Mix_GetError() <<endl;
}
Here we set 5 sounds to load. This corresponds to the 5 buttons for the drum kit. I put it in an order that I used on the drums once upon a time, but you can do whatever you want. You could even make it beep or quack when you hit one.
We make a call to Mix_OpenAudio(), which initializes the mixer, tells it what frequency we want, how many channels, etc. This lets us make sound.
We then load in all the WAV data into 5 sounds with a call to Mix_LoadWAV().

One last thing to initialize. We need to create a window:
SDL_Surface * window = SDL_SetVideoMode(800, 600, 32, SDL_SWSURFACE);
Done. We have initialized everything, now let's get ready to rock! We need to set up an event handling structure and check for drum events. The way the drums work is it sends a number for each button. The numbers are like this:
0: blue
1: green
2: red
3: yellow
4: foot pedal

There is one catch though. The numbers 0-3 also correspond to the 1, A, B and 2 buttons respectively so to differentiate, the drum kit also sends a 7 every time you hit one of the pads (but not the pedal). So when you hit the blue one, you actually receive two buttons: a 0, then a 7.

We need to do a little magic to keep track of what button was hit. I do this by recording the last button that was hit, and then when a 7 is received, I know that it was a pad and that I should play a sound (unless it was a 4, in which case I don't wait for a 7 after).

Let's set up the event loop:
SDL_Event evt;
bool loop = true;
int last_btn = 0;

while (loop){
if (SDL_PollEvent(&evt)){ //check for event
if (evt.type == SDL_QUIT){
//close button, quit
loop = false;
}else if (evt.type == SDL_JOYBUTTONDOWN){
//joystick button hit, let's play
if (evt.jbutton.button == 7) //pad
Mix_PlayChannel(-1, sounds[last_btn], 0);
else if (evt.jbutton.button == 4) //pedal
Mix_PlayChannel(-1, sounds[4], 0);
else
last_btn = evt.jbutton.button;
}
}
}
In our example, we handle events by polling. There are other ways to do events with SDL, but this is the best way for games in my opinion.
We check to see if there is an event by calling SDL_PollEvent(). If there is, the function returns true and puts the info into our evt structure.
There are only two events we care about, SDL_QUIT and SDL_JOYBUTTONDOWN (we could use the joystick axes events to check to see if people used the D-pad, but we just want to play drums). If we get a quit event, then we just tell the loop to stop going and then go on with it. If it is a joystick button down event, it means someone hit something. We then want to check to see what was hit. If it is a 7, it means we have just hit a pad and the last_btn variable holds whatever pad it was. We make a call to Mix_PlayChannel() to play our WAV file.
If the button was a 4, it was the pedal, so play the pedal sound (which should be at sounds[4]).
Finally, if it was anything else, just store the value and be done with it.

Now we need to clean up:
for (int i = 0; i < 5; i++)
Mix_FreeChunk(sounds[i]);
Mix_CloseAudio();

// remember to use the same number here
// as you did with SDL_JoystickOpen()
SDL_JoystickClose(0);
And we're done! To compile with g++ you use the following command, assuming your code was in drums.cpp:
g++ `pkg-config --libs --cflags sdl` -lSDL_mixer drums.cpp -o drums
Then:
./drums
Now you should get a little black window pop up, and when you have it selected your drums should play sounds (so long as you have the WAV files in the same folder as the executable, you can get some good tracks here).

So yeah, Frets on Fire with drums anyone?

Let me know if you have any questions.

Update Nov. 12, 2008: Intrepid uses a HAL that doesn't use the Wii Drums properly. To fix it, you have to tell X what to do. However, keep in mind that if you don't follow these directions to the letter, you may run into big problems.

First, install the driver:
sudo apt-get install xserver-xorg-input-joystick
Backup your xorg.conf file:
cd /etc/X11
sudo cp xorg.conf xorg.conf.bak
You'll need to see what the kernel is loading your joystick as. Do this:
lshal > before   (with drums not plugged in)
lshal > after (with drums plugged in)
diff before after | grep event
This will output some stuff about the drums. You should see somewhere that it says /dev/input/event6 or something with a different number (event4, event5, etc.). Remember this number.

Next you'll need to make some tweaks to xorg.conf. Type:
gedit xorg.conf
You'll see a bunch of commented out sections, uncomment those (except for the actual comments). Before those add this, replacing event6 with whatever you had above:
Section "ServerFlags"
Option "AutoAddDevices" "False"
EndSection

Section "InputDevice"
Identifier "Configured Joystick"
Driver "joystick"
Option "Device" "/dev/input/event6"
EndSection

If you don't know what you're doing, write the following down on a piece of paper:
sudo cp /etc/X11/xorg.conf.bak /etc/X11/xorg.conf
If you mess up, this will get your system back. If things die and you can't log in, press Ctrl+Alt+F1 to switch to a terminal, log in normally, and type the stuff above. Then restart your computer.

Log out and log in again (assuming all went well) and you should be able to use the drums as a joystick again.