Playing Music in SGDK

Posted July 6, 2020

Playing music in SGDK might actually be a lot easier than you think. So let’s quickly look at how it works and create ourselves a little disco, what do you say? Create a new SGDK project and let’s go!

Getting The Groove

First of all we gotta get ourselves some music to play. You can of course compose your own, using a tool like Deflemask, but for the sake of this tutorial we’ll just grab a song from another game. There are many websites out there that archive old chiptune music, including of course music for the Mega Drive. But here is the first thing that you have to watch out for.

Mega Drive music comes in different formats, like .gym and others. SGDK only supports files in VGM, XGM or XGC formats.

So go ahead and grab yourself a .vgm file (or one of the others), then stick it in the resources folder of your project. (If you don’t have .vgm files sitting around and can’t find any online, then SGDK actually comes with some. Check out the sample\xgmplayer\res folder in your main SGDK folder!)

Next we’ll import the music file by adding it to our resources file, probably called resources.res. Add the following line to import the music file:

XGM track1 "musicfile.vgm" -1

You’ll of course have to change musicfile.vgm to whatever the name of your music file is. You can also change track1 to whatever you want, I’m just keeping things neutral here. Finally, the -1 tells SGDK to figure out the timing (NTSC or PAL) of the music automatically. Should your track play at the wrong speed, you can force NTSC with 0 or PAL with 1. Thanks to Disqus Ghost for pointing that out!

Lay It On Me

Now that we’ve got the music loaded and ready, it’s time to spin up that turntable! And that’s a very quick process, as playing music in SGDK actually only takes two lines of code. Add them to your main() function:


As the name implies, XGM_setLoopNumber sets how often a track should loop. A value of -1 means “infinitely” (but actually just 255 times), a value of 0 will only play a track once. With 1 it would play the track once and then loop it one more time, 2 would play the track a total of three times, and so on.

And XGM_startPlay, well…that plays the music you specify! So if you compile and run the game now, you should be hearing your track.

Pause, Resume and Disco!

That was simple enough, but let’s go a little step further just for fun. First, add a new variable to the top of your main.c file:

bool paused = FALSE;

Then, directly below it, create an array of colors for a little disco light effect:

u16 colors[6] = {

You can of course pick any colors you want, I just went with some very simple ones.

Finally, create a joypad callback so we can control the playback of our music a little. This is what the whole thing looks like:

void myJoyHandler(u16 joy, u16 changed, u16 state){
    if(changed & state & BUTTON_START){
        if(paused == FALSE){
            paused = TRUE;
        } else{
            paused = FALSE;

The code should be rather self-explanatory. If we press START on the joypad, the music will either pause or resume, depending on whether it’s already playing or not. SGDK gives us the XGM_pausePlay() and XGM_resumePlay() functions to easily accomplish that.

Implement your joypad callback at the beginning of your main function:


And now you should be able to pause/resume the playback with a quick press of the Start button! Go ahead and try it out if you want.

Finally, let’s add a little pizazz. After setting the loop number and playing the music, draw some text on screen:

VDP_drawText("Welcome to Disco Zone!", 9,13);

Then define two variables directly below that. We’ll use them in a second:

u8 currentColor = 0;
u8 ticker = 0;

Now let’s get some colors going! Inside the game loop (that is, inside the while(1) loop) add this chunk of code:

if(paused == FALSE){
    if (ticker == 60)
        ticker = 0;
        if (currentColor < 5)
            currentColor = 0;
        VDP_setPaletteColor(15, colors[currentColor]);

Let’s step through it. First of all, this logic is only handled if the track is not paused; so the light show stops along with the music. Then we increase a ticker by 1 on each frame, and when one second has passed (because our amazing program runs at 60fps, naturally) we reset it to 0 to prevent overflows. And then the magic happens: currentColor will point to the color in our colors array that we currently want to display. We increase that value if there are still more colors in the array (we defined a total of 6 colors, so the maximum index is 5) or reset it to 0 if we’re already displaying the last color of the array.

Then we use VDP_setPaletteColor to grab the color we want from the array and apply it to the text. (If you’re not quite sure how that works, check out my tutorial on the topic of text color!) And if you want a really disorienting disco experience (and don’t suffer from epilepsy) replace the index 15 with 0.

Now compile the rom, run it and get funky! Or groovy, or rock out, or whatever you do to the music you picked.


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!

Take It to the Next Level!

Become an excellent patron on Patreon and snatch yourself some kickass perks such as early access, early builds, exclusive updates and more!

You will also be added to the Wall of Excellent People!

Check out the rest of this tutorial series!

  • Creating Graphics for the Mega Drive
  • How to Quickly Generate C Prototype Functions in VSCode
  • Color Swapping
  • 4 Programs For Creating Mega Drive Graphics
  • Editing the Rom Header
  • Simple Game States
  • Creating a Simple Menu
  • Changing The Text Color in SGDK
  • Playing Music in SGDK
  • Converting VGZ to VGM
  • Processing Resets
  • Drawing Tiles From Code
  • Make a Text Crawl, Streets of Rage Style
  • Scrolling Maps
  • Placing Tiles
  • Simple Animated Tiles in SGDK
  • Simple Password System
  • By using the Disqus service you confirm that you have read and agreed to the privacy policy.

    comments powered by Disqus