Megalaga 9 - Sound
This tutorial is most likely not compatible with versions of SGDK above 1.70. Unfortunately, I simply do not have the capacity or ability to update them right now. Read more about it here. Sorry.
Hold up!If you like 90s platformers, check out my new game Kid Bubblegum!
In space, no one can hear you scream. But you can hear lasers, explosions and video game beeps. That’s just science.
So far our game has been rather quiet. So let’s add some sound to it to spice things up! What would a classic shmup be without beeps and bloops after all?
But first we’ll briefly have to talk about sound drivers. First of all: What is a sound driver? As the name implies, it’s basically a piece of software that deals with the audio side of a Mega Drive game. Without a sound driver there would be no sound. But it also affects the quality of the sound, the possible effects, how many sounds can be played at the same time, whether sound effects can be played over music and even how the music can be composed. Sound drivers are a big deal.
Which might make it seem surprising that companies pretty much had to create their own sound drivers… and there are a lot! You know how some Mega Drive games have amazing music like Streets of Rage while others sound like the Sonic Spinball options screen? A lot of that is due to the sound driver used. Back in the day, composing music for game hardware was as much about programming as it was about actual composing.
But anyway, let’s not get too deep into it. The fact is: Your game needs a sound driver. Luckily, SGDK comes with several you can use, so you don’t have to create your own. Which is very good, because I don’t think writing your own is easy. At all. So in this tutorial I’ll show you how to use one of the included drivers to add sound effects to our game!
Alright, let’s finally get started! We’ll begin by adding a sound for our laser. First we’ll need a sound file. I have prepared one that you can download here:
Create a new folder in your project’s
res folder called
sfx, then copy the content of the downloaded .zip file into it. You might notice that it’s nothing but a regular .wav file, not some sort of special Mega Drive format. And that’s because SGDK will handle the conversion for us! Just like with graphics, you plop in a commonly used file type and SGDK will convert it to whatever it should be. This is awesome as it saves us as lot of time and headaches.
With the sound file in place, it’s time to open up
resources.res to import the file into our project. Do this by adding the following line:
WAV sfx_laser "sfx/laser.wav" 5
We’re importing the file
"sfx/laser.wav" under the name
sfx_laser and tell SGDK that it’s a resource of type
WAV, as we want to use it as a sound effect in our game. We also specify the sound engine we want to use (in our case XGM) by passing in
5. Thanks to Christian for pointing this out! Make sure to check his featured comment below for more information.
We’ve got the sound, now what do we do with it? And what about that whole sound driver thing? Let’s find out!
As I said, SGDK supports various sound drivers. The one we will be using is the XGM driver. This driver was actually written by the creator of SGDK himself, Stephane Dallongeville, and as such is rather powerful while being easy to use. Just for fun, here are some of its features:
- 5 FM + 4 PSG + 4 PCM @14 Khz playback
- 16 priority levels for SFX play through PCM.
- supports music pause / resume commands.
- no size limit for XGM music data or PCM data.
- PCM have their size and address aligned to 256 bytes.
- 100% running on Z80
- protection against DMA contention to preserve good PCM playback quality (not 100% guaranteed depending on the driver load).
Now there is a lot of technical stuff in there that’s not important right now, but what is important for us is that this driver can handle multiple PCM sounds at the same time. PCM is mostly used for sound effects, which is all we’ll be dealing with right now.
But enough with the theory already, let’s make our game go pew pew. Playing sound effects is a two-step process: First we declare a sound, then we play it whenever we want. And to make things easier for us, we’ll use a define. So at the top of
main.c add this define:
#define SFX_LASER 64
Sounds are identified by integers and by using defines we won’t have to memorize them all. We’re also starting at
64 because the first 64 indexes (0 - 63) are reserved for music by the sound driver, so sound effects have to start at 64. Keep that in mind!
Now to declare our sound effect. At the beginning of our
main() function, where we’re doing other basic initialization stuff like
JOY_init(), add the following line:
XGM_setPCM(SFX_LASER, sfx_laser, sizeof(sfx_laser));
XGM_setPCM declares a PCM sample to the sound driver. Without this step we couldn’t play our sound, as our driver wouldn’t even know about it. The first argument is the index of the sound (in our case
64), the second is the resource we want to use; in our case we named the sound
sfx_laser in our
resources.res file. The final argument is the size of the sample in bytes. Luckily C gives us the
sizeof() operator, which will return exactly what we need.
Now that the sound driver knows about our sound, we can play it! We’ve got a nice laser sound, so let’s play it somewhere in
shootBullet (which we probably should have named
shootLaser, but oh well). Near the end of
shootBullet, when we set the position of the bullet sprite and increment
bulletsOnScreen, add this line:
This function does what it says, it’s starts playback of a PCM sample. We tell it the sample ID, which we must have declared first using
XGM_setPCM. Then we define the priority of the sound, which can range from 0 - 15 where 0 is the lowest priority. This comes into play when a sound is supposed to play on a channel that already has a sound playing. If the new sound has a higher priority, it will override the previous sound. Finally, we tell the XGM driver which channel to play our sound on. XGM supports 4 PCM channels, the first of which is usually used for music. So we’ll just play our sound on channel 2, which we access via the define
And…that’s it! Compile the game, shoot a bullet/laser and be amazed at the aural landscape.
As you can see, dealing with sounds has a lot of theory behind it but isn’t that hard to do when you have a tool like SGDK along with a good sound driver. Things will of course get tricky when you’re making a proper game with music and several sounds playing all at once, but it’s still a lot easier to deal with than what the original MD programmers had to deal with back in the 90s.
Now that you know how to implement sounds, you might want to add an explosion sound when you’ve blown up an enemy. So here is one that you can use for some practice:
Remember the 3 basics steps to playing sound effects: Import, declare, play. And once you have a second sound, you can start toying around with the priorities and channels.
If you've got problems or questions, join the official SGDK Discord! It's full of people a lot smarter and skilled than me. Of course you're also welcome to just hang out and have fun!
Join my Discord Server!
Hang out, get news, be excellent!
Want To Buy Me a Coffee?
Coffee rules, and it keeps me going! I'll take beer too, though.
Check out the rest of this tutorial series!