Adventures in Hi-Fi
As I blogged earlier I am writing a game (and yes, it's pretty much playable already).
One thing I didn't mention is that I never wrote a game before. Yeah, I know everyone does it as one of his first projects, but I never did.
So, there are some things I really have no clue about [1], like sound and moving graphics around.
For the graphics stuff, QCanvas is just fine and dandy, but to make things bloop and warble and squeak when the time is right, I found Qt's sound support somewhat depressing.
Come on, NAS? Who uses that? And what about music? I had no idea.
So, I started trying to follow one of my leading principles of development: find a way to make it Someone Else's Problem (TM).
The usual way to do that is finding a library that handles the problem, write minimal glue, stick it to the side of the program, tell the program that's his new arm, and forget about it quickly.
Here's what I found.
Mi Dios!
I thought I should start by adding one of those annoying little tunes every game has. It's just a game tune, I don't want to have to include a 3MB OGG file for it, so I wanted an instrument-based format.
I remembered MIDI tunes. You may know them as ringtones nowadays, but they used to be just cheesy tunes generated by your SBPro's FM generator, not your phone.
In fact, I remember having a little proggie called playmidi, that would do that in Linux.
Well, it seems that in the past few years, either sound cards have forgotten how to play them, they fell out of fashion, or something, because the only things I found that could play MIDI are monstrosities that require a 9MB digital instrument set. And how was I to include that along with my 25KB game???
So, what's next? I had a C64, so...
MOD me up!
MOD files are like MIDI files, only the MOD includes it's own instrument set, called samples, and instructions on how to repeat and alter those samples to make a tune.
Good news: there are nice-sounding, funny MOD files that are about 30KB in size.
Better news: There is a popular library to play them! It's called Mikmod, and your distro has it (and it's a dependency for KDE's multimedia packages too).
Even better news: It has support for playing simple sounds (samples in mod lingo) by calling a couple of functions.
Awesome news: It includes a software mixer so you can just tell it to play this, then play that, then that, and a tune in the background, and everything sounds at the same time.
So, we have a winner. This baby can handle everything I need for the game!
But... is that a snake in your pocket?
I can't find a Python binding for it. I am sure as soon as I post this article someone is going to come up and tell me, here they are, moron! But I just can't find any.
So, I decided to do something I wanted to do already and learn to use Pyrex. Pyrex is a tool to write python extensions, with almost-free access to C libraries, in an almost-python language (only minor syntax differences).
That way, I could write a Python module to use Mikmod.
You know what? It was almost scarily simple [2]. I didn't wrap all of Mikmod [3] because I don't need it, but now I can do stuff for games and apps almost trivially.
Even more: Pyrex has awesome distutils support, so building the extensions, usually a pain in the rear, is trivial (mostly you just copy and delete stuff, with some search and replace).
One thing I found I did nicely is this: Mikmod requires you to call Mikmod_Update every once in a while so it fills the soundcard's buffer with stuff to play. If you don't, it skips.
So, I just started a thread that loops and takes care of it. You don't even have to know about it to use the extension. Oh, sure, if your Mikmod is not threadsafe, it breaks. Well, get a decent Mikmod package, then.
How does it look?
Here's a whole noisy proggie
#Load the modules import mikmod, time #Init the library mikmod.init() #40 voices, 20 for music, 20 for random sounds (overkill) mikmod.setNumVoices(20,20) #Enable sound, starts the thread that pushes sound, too mikmod.enableOutput() #Create a module, that is, a music track module=mikmod.Module("BasicInstinct.mod") #Load two samples, just a couple of noises s1=mikmod.Sample("lost.wav") s2=mikmod.Sample("swap.wav") #Start playing the song module.play() #For the duration of the song, each second, make some noise while module.active(): s1.play() time.sleep(0.5) s2.play() time.sleep(0.5) #Close the mikmod library, stop the thread, etc. mikmod.exit()
Look at pygames or livewire. They do sprites, sound/midi and everything.
http://www.pygame.org/
Oh, the sprites stuff is done. QCanvas is more than good enough for this game.
The sound stuff seems to be a wrapper over SDL_Mixer.
The MIDI support requires a patchset (the usual 9MB monstrosity).
For MODs, SDL_mixer wraps mikmod anyway (according to the rpm -qi stuff, I haven't really looked).
So, I don't see much to gain here :-P
Pygame is extremely powerful for this sort of thing, and it can be patched fairly easily to allow its windows to be embedded into PyKDE's QXEmbed widget on X11. For normal games, that's not too interesting, but SDL has pretty good multimedia support, so it makes a useful "enhanced" canvas. Its event system doesn't interfere with Qt's event loop much, either.
I've yet to compose music for my pygame. Somehow, drawing retro-style sprites is so much easier than composing retro-style music, but I can't wait to try your mikmod module! :-)
I might just do that. Are there any decent MOD file editors available on Linux?
David, i you want a copy, just email me.
My game won´t be released for quite a while yet because there´s a lot of artwork needed, and I want to do it all myself (the game is a gift :-)
Well, my musical talent is null, so I have never even looked ;-)
The real question, do you have a python script or know of one that'll *write* mod files? :) Will mikmod?
I want to work up a python script that'll convert Hydrogen's xml format to mod format, hopefully with samples, so I can write drum lines with Hydrogen and then add additional instruments in a mod editor like Cheesetracker.