Thread Rating:
  • 0 Vote(s) - 0 Average
  • 1
  • 2
  • 3
  • 4
  • 5
TUTORIAL: In-Game Music with FMOD
#1
[Image: fmod.png]

Introduction
In this tutorial, I will show you the basics of using FMOD to play music and sound effects in your FreeBASIC programs and games. Smile Plasma has done a great job in porting the FMOD headers, which are included with the FreeBASIC release, so you don't have to download anything other than FreeBASIC to get started.

Download Accompanying Tutorial Files

FMOD is an amazing sound library. Their web site is at http://www.fmod.org/. If you're writing a shareware or commercial game using the library, you'll have to dish up a lot of money for the licence (and so you should, if you're going to be getting cash from it! there is a very good discount for shareware developers, rather than commercial, by the way). For freeware games though, which you will probably be making, the licence is free to use! More information about the licences is available on the FMOD web page.

FMOD is capable of playing a vast spectrum of different formats. It can currently load and play these 'music' formats: .MID, .MOD, .S3M, .XM, .IT, .RMI, .SGT and .FSB. It can also load and play these 'static sound' file formats: .WAV, .MP2, .MP3, .OGG and .RAW.


[Image: sep.png]


Before Starting
Before writing any programs using FMOD, you will find the FMOD documentation EXTREMELY useful. It's really easy to use as well. You can download it in .CHM format from here: http://www.cdsoft.co.uk/fbstuff/fmod.chm


[Image: sep.png]


Initialisation
The first thing that we must do is include the relevant header file. To use FMOD's functions, we just need to add this to the top of our program:

[syntax="FreeBASIC"]
'$INCLUDE: 'fmod.bi'
[/syntax]

The next thing that we need is to initialise the library. This is done through the FSOUND_Init function, through which you must specify the sample rate and number of channels that you want. I usually just stick with a sample rate of 48000Hz and 8 channels, which should be plenty. FSOUND_Init also takes one last parameter, through which you can specify some other options. You can look up all of these options in the FSOUND_INIT_FLAGS section of the FMOD reference.

[syntax="FreeBASIC"]
' Initialise FMOD with 48000Hz, 8 channels.
FSOUND_Init(48000, 8, 0)
[/syntax]

Okay, great! Now we're ready to start loading the songs. If you've used FMOD before in C, you will know that to store information about a loaded song, you stored a pointer to an FMUSIC_MODULE structure. Well this isn't needed in FreeBASIC - all we need to do is store the integer, as this effectively acts as the pointer anyway. To save confusion, I will just refer to this pointer as the 'song ID'.

By the way, before exiting, our program should call FSOUND_Close. This will ensure that FMOD has time to clean up all of the memory resources it used and allows it to unload properly.

Our skeleton code is now this:

[syntax="FreeBASIC"]
'$INCLUDE: 'fmod.bi'

FSOUND_Init(48000, 8, 0)

' Main code goes here!

FSOUND_Close
END
[/syntax]


[Image: sep.png]


Loading and Playing Songs
In FMOD, 'songs' are considered to be either MIDI files or modular music (S3M, MOD, XM, etc.). For each song we load, we have to keep a reference to it - this is just done by keeping an integer. Using this reference, we can play the song and deallocate it nicely at the end of our program.

The function we'll be using to load the song is the FMUSIC_LoadSong function, which accepts just one argument: the file name of the song, and returns the reference ID. I will stick to loading the MIDI included in the accompanying tutorial zip archive. This MIDI is originally from Ultima Underworld 2.

[syntax="FreeBASIC"]
DIM backgroundMusic AS INTEGER

backgroundMusic = FMUSIC_LoadSong("uw2-07.mid")
[/syntax]

To check for a loading error, you can just see if the return value is 0.

[syntax="FreeBASIC"]
IF backgroundMusic = 0 THEN
PRINT "Error: Failed to load the MIDI file!"
FSOUND_Close
END
END IF
[/syntax]

There is also a function called FMUSIC_LoadSongEx which gives you more control over the loading process. You can use this function to load the song from memory instead of from a file, or you can tell it to load the song from a specific offset in the file... if you're really interested in using this (e.g. if your game loads data from a .PAK file), read up on the function in the FMOD documentation - there are a lot of optional arguments, so it's not too hard to change your code to load from an archive or memory instead. Smile


Now to play the file, it's just a simple case of calling FMUSIC_PlaySong, passing our song ID as the argument. Although there is one more little thing that we need to know. Inside our main loop, we need to call FSOUND_Update, which tells FMOD to update the sound buffers, etc. - i.e. it tells FMOD to keep playing what it's been told to do!

So now take this as an example:

[syntax="FreeBASIC"]
FMUSIC_PlaySong(backgroundMusic)
WHILE INKEY$ = ""
FSOUND_Update
WEND
[/syntax]

Cool stuff. But what's that? It only plays once? We can fix that using the FMUSIC_SetLooping function. The first argument is the song you want to set looping on and the second is the flag - '0' indicates that the song shouldn't loop and '1' indicates that it should:

[syntax="FreeBASIC"]
FMUSIC_SetLooping(backgroundMusic, 1)
FMUSIC_PlaySong(backgroundMusic)

WHILE INKEY$ = ""
FSOUND_Update
WEND
[/syntax]

How about stopping songs? You can stop each of the individual songs by using FMUSIC_StopSong, passing the song ID as the argument. Either that, or you can stop -all- of the songs playing by using FMUSIC_StopAllSongs.

Let's try it using a MOD this time (from one of my favourite MOD artists... Nightbeat Smile).

[syntax="FreeBASIC"]
'$INCLUDE: 'fmod.bi'

DIM niceSong AS INTEGER

' 48kHz sample rate, 8 channels.
FSOUND_Init(48000, 8, 0)

niceSong = FMUSIC_LoadSong("CHILDRMX.S3M")
IF niceSong = 0 THEN
PRINT "Error: Failed to load 'CHILDRMX.S3M'!"
FSOUND_Close
END
END IF

' make it loop.
FMUSIC_SetLooping(niceSong, 1)

' play.
FMUSIC_PlaySong(niceSong)
WHILE INKEY$ = ""
FSOUND_Update
WEND

' stop the song and quit.
FMUSIC_StopSong(niceSong)
FSOUND_Close

END
[/syntax]

It's so easy to do! Now you have no excuse not to have music in your games (unless you're a terrible musician and have nobody to help work with you, like me Sad)!

Let's review the process...
  • 1. Initialise FMOD
    2. Load the songs you need
    3. Write the main loop, remembering to call FSOUND_Update each cycle
    4. Unload FMOD

You can play or stop the song any time you want to throughout your main loop... so if you need to change the song each time a level changes, all you have to do is add something like this to your level changing routine:

[syntax="FreeBASIC"]
FMUSIC_StopAllSongs
FMUSIC_PlaySong(newSongID)
[/syntax]

A couple of other useful functions:
  • FMUSIC_IsPlaying - Pass the song ID and it will return 1 if the song is playing, 0 if not.
    FMUSIC_IsFinished - Pass the song ID and it will return 1 if the song has finished, 0 if not.
[Image: sep.png]


Loading and Playing Samples
Samples are considered to be 'static sound' in FMOD... this includes .WAV, .MP2, .MP3, .OGG and .RAW files. The process is very similar to loading and playing songs - there is one advantage though, we don't have to explicitly deallocate the samples ourselves at the end of the program. The FMOD developers realised that this can be a bit of a pain if you're using hundreds of samples in a large game, so they decided to add this automanager for you. There is a way to tell FMOD not to manage the samples for you if you really want - have a look in the reference manual at the FSOUND_Sample_Load function.

Speaking of which, the next function we'll be using is FSOUND_Sample_Load. As you can guess, it loads a sample from a file. This function returns a sample ID, just like the FMUSIC_LoadSong function did. We can use this ID to refer to the sample when playing it.

The FSOUND_Sample_Load function takes a few more arguments than the FMUSIC_LoadSong function though:
  • index The first argument is the 'index'. If you want, you can tell FMOD to use a specific index in its internal list of samples... but that doesn't sound too flexible to me, so we'll tell it to use the next free sample slot. We do this by passing FSOUND_FREE as the 'index' argument.

    name_or_data - The file name to load from (or if you're loading from memory, the offset in memory to load from).

    inputmode - Allows you to specify some optional modes. Leave this as 0 if you're loading from a file for FMOD to figure everything out automatically. If you're loading from memory, pass FSOUND_LOADMEMORY as the value for this argument. If you want to know more about what this argument can be, look up FSOUND_MODES in the FMOD manual.

    offset - If you're loading the sample from a normal file, just leave this as 0. If you're loading it from an archived file, like a .PAK file, set this as the offset within in file you specified as 'name_or_data' where the sample is located.

    length - If loading from a file, leave this as 0. If loading from memory, specify the length of the buffer pointed to by 'name_or_data'.

Okay, so it's not really that bad! Here is the code for loading an MP3.

[syntax="FreeBASIC"]
DIM mySample AS INTEGER

mySample = FSOUND_Sample_Load(FSOUND_FREE, "HC-MainTitle.mp3", 0, 0, 0)
IF mySample = 0 THEN
PRINT "Error: Failed to load the sample!"
FSOUND_Close
END
END IF
[/syntax]

Playing is extremely simple. All we have to use is the FSOUND_PlaySound function, which accepts two arguments: the channel to play the sample in and the sample ID. If, like me, you couldn't really care about which channel the sample plays in, just set the first argument to FSOUND_FREE. FMOD will pick a free one for you. If you find that in your game, some of the sounds aren't playing, try increasing the number of channels you specify in the FMOD initialisation code.

[syntax="FreeBASIC"]
FSOUND_PlaySound(FSOUND_FREE, mySample)
WHILE INKEY$ = ""
FSOUND_Update
WEND
[/syntax]

Remember to call FSOUND_Update as usual.

To stop a sound playing, use FSOUND_StopSound, passing the sample ID as the argument.

If you want the sample to loop, you must set the appropriate sample mode. Do this with the FSOUND_Sample_SetMode function, which requires the sample ID and the mode to set. We'll be setting the FSOUND_LOOP_NORMAL mode (for more modes, look up FSOUND_Sample_SetMode in the FMOD documentation).

[syntax="FreeBASIC"]
FSOUND_Sample_SetMode(mySample, FSOUND_LOOP_NORMAL)
FSOUND_PlaySound(FSOUND_FREE, mySample)

WHILE INKEY$ = ""
FSOUND_Update
WEND
[/syntax]

So now, the full code for loading and playing a sample:

[syntax="FreeBASIC"]
'$INCLUDE: 'fmod.bi'

DIM mySample AS INTEGER

' 48kHz sample rate, 8 channels.
FSOUND_Init(48000, 8, 0)

mySample = FSOUND_Sample_Load(FSOUND_FREE, "HC-MainTitle.mp3", 0, 0, 0)
IF mySample = 0 THEN
PRINT "Error: Failed to load the sample!"
FSOUND_Close
END
END IF

FSOUND_Sample_SetMode(mySample, FSOUND_LOOP_NORMAL)
FSOUND_PlaySound(FSOUND_FREE, mySample)

WHILE INKEY$ = ""
FSOUND_Update
WEND

FSOUND_Close

END
[/syntax]

Beautiful.


[Image: sep.png]


Conclusion
As you can see, using FMOD is extremely simple. It is also a good idea to learn to use FMOD in your games if you're planning on trying to make commercial games in the future; you can distribute freeware while you're learning, then buy a fairly cheap shareware licence. If that takes off, then you could even go for a commercial licence. The licencing has been well designed so that you can hop up to each stage like that.

If anything, you should use FMOD because it's free, it's well-written and it's really, really easy to use. Smile

I hope this inspired at least some people to use FMOD through FreeBASIC. Feedback on the tutorial would be warmly welcomed.

If you'd like to contact me, you can e-mail: c.g.davies@gmail.com
Or visit my site: http://www.cdsoft.co.uk/


-shiftLynx
img]http://www.cdsoft.co.uk/misc/shiftlynx.png[/img]
Reply
#2
Somebody should collect all these snippets that you, bastet, etc write and upload em somewhere.

kool!!!
y smiley is 24 bit.
[Image: anya2.jpg]

Genso's Junkyard:
http://rel.betterwebber.com/
Reply
#3
@relsoft: I will get my own server next month, wait till then. Wink

@shiftlynx: Great Tut ^.^
color=red]Look at you, Hacker. A pathetic creature of meat and bone, panting and sweating as you run through my corridors. How can you challenge a perfect, immortal machine?" - Shodan, AI at Citadel Station orbiting Earth[/color]
Reply
#4
I include the code to the posts that I make in the "accompanying files" archives. Smile Zap added my OpenAL one to FreeBASIC.tk -- it was easy to do with the post code. Wink

Looking forward to see your site, Bastet. Smile

-shiftLynx
img]http://www.cdsoft.co.uk/misc/shiftlynx.png[/img]
Reply
#5
Very nice tut, I'm sure that many people will take advantage of it Smile Keep up the good work.

These are the kind of things that this community needs Smile
SCUMM (the band) on Myspace!
ComputerEmuzone Games Studio
underBASIC, homegrown musicians
[img]http://www.ojodepez-fanzine.net/almacen/yoghourtslover.png[/i
Reply
#6
Damn Straight.

Excellent job. I like the presentation, the language, the delivery etc.

How about some HTML formats? I can host em temporarily for you if you need...email me.
·~¹'°¨°'¹i|¡~æthérFòx~¡|i¹'°¨°'¹~·-
avinash.vora - http://www.avinashv.net
Reply
#7
Quote:FreeBASIC:

FSOUND_PlaySound(FSOUND_FREE, mySample)
WHILE INKEY$ = ""
FSOUND_Update
WEND



Remember to call FSOUND_Update as usual.
strange, when i wrote my music player prog, i didn't use fsound_update, but it still works... :???: maybe it's because i used streams and not samples? :???: :???:
ttp://m0n573r.afraid.org/
Quote:quote: "<+whtiger> you... you don't know which way the earth spins?" ... see... stupidity leads to reverence, reverence to shakiness, shakiness to... the dark side
...phear
Reply
#8
Ok, im total linux rookie so is there any tut how to use FMOD in linux?
Read realrealreal linux rookie :lol: :oops:
url=http://www.ascii-world.com]ASCII-World.com[/url]
Yeah, nick changed from lurah, but bullshit's are the same.
Reply
#9
Sorry to dig this up, I wanted to say good job on the excellent tutorial!


Also, I think it might be good to point out that earlier versions of some music format files such as mod and xm fail to load with the latest versions of fmod.
This can be corrected by opening with a tracker and resaving the file as the same format. Saving as a different format usually destroys the integrity of the track.
Reply


Forum Jump:


Users browsing this thread: 1 Guest(s)