Cutting Your Teeth on FMOD Part 1: Build environment, initialization and playing sounds
FMOD by Firelight Technologies Pty Ltd. is a cross-platform audio API used in – among other things – many commercial games such as Crysis, Diablo 3, Guild Wars, Guitar Hero, League of Legends, Second Life, StarCraft II, Tomb Raider, World of Warcraft and many others. It is in many ways an indsutry-wide gold standard in audio engines, and as such, knowing how to use it will come in very handy if you are coding games professionally. In the first part of this series, we’ll look at how to get C++ applications using FMOD to compile, how to set up the sound system at the start of your application, and how to play MP3s (although you can use any supported format you wish).
Note: The SimpleFMOD library contains all of the source code and pre-compiled executables for the examples in this series.
Getting Started
First, download the FMOD Ex Programmers API. You’ll want the latest Stable version. After the installation completes, open Visual Studio and create an empty Win32 console project.
Right-click on the project node in Solution Explorer, select Properties, choose VC++ Directories in the left-hand pane and add the following directory paths:
Include Directories: C:\Program Files (x86)\FMOD SoundSystem\FMOD Programmers API Windows\api\inc
Library Directories: C:\Program Files (x86)\FMOD SoundSystem\FMOD Programmers API Windows\api\lib
In the Linker -> Input section, add fmodex_vc.lib to the Additional Dependencies.
Finally, when your application runs, you’ll need fmodex.dll to be in the same folder as your exe file, so to make things simple you can add a post-build event to copy this automatically from the FMOD API directory to your target folder when the build succeeds. Go to Build Events -> Post-build Event and set the Command Line as follows:
copy /y “C:\Program Files (x86)\FMOD SoundSystem\FMOD Programmers API Windows\api\fmodex.dll” “$(OutputPath)”
When you start writing your application, you’ll want to include the following headers:
#include "fmod.hpp" #include "fmod_errors.h" #include
Since most FMOD functions return an error code, it is also handy to have some kind of error checking function you can wrap around all the calls, like this:
void FMODErrorCheck(FMOD_RESULT result) { if (result != FMOD_OK) { std::cout << "FMOD error! (" << result << ") " << FMOD_ErrorString(result) << std::endl; exit(-1); } }
Initializing FMOD
The following code is adapted from the ‘Getting Started with FMOD for Windows’ PDF file which is included with the API and can be found in your Windows Start Menu under FMOD Sound System. I have made some small tweaks and added further explanation below.
First we’ll want to get a pointer to FMOD::System
, which is the base interface from which all the other FMOD objects are created:
FMOD::System *system; FMOD_RESULT result; unsigned int version; int numDrivers; FMOD_SPEAKERMODE speakerMode; FMOD_CAPS caps; char name[256]; // Create FMOD interface object result = FMOD::System_Create(&system); FMODErrorCheck(result);
Then we want to check that the version of the DLL is the same as the libraries we compiled against:
// Check version result = system->getVersion(&version); FMODErrorCheck(result); if (version < FMOD_VERSION) { std::cout << "Error! You are using an old version of FMOD " << version << ". This program requires " << FMOD_VERSION << std::endl; return 0; }
Next, count the number of sound cards in the system, and if there are no sound cards present, disable sound output altogether:
// Get number of sound cards result = system->getNumDrivers(&numDrivers); FMODErrorCheck(result); // No sound cards (disable sound) if (numDrivers == 0) { result = system->setOutput(FMOD_OUTPUTTYPE_NOSOUND); FMODErrorCheck(result); }
If there is one sound card, get the speaker mode (stereo, 5.1, 7.1 etc.) that the user has selected in Control Panel, and set FMOD’s speaker output mode to match. The first parameter is the driver ID – where 0 is the first enumerated sound card (driver) and numDrivers - 1
is the last. The third parameter receives the default sound frequency; we have set this to zero here as we’re not interested in retrieving this data.
// At least one sound card else { // Get the capabilities of the default (0) sound card result = system->getDriverCaps(0, &caps, 0, &speakerMode); FMODErrorCheck(result); // Set the speaker mode to match that in Control Panel result = system->setSpeakerMode(speakerMode); FMODErrorCheck(result);
If hardware acceleration is disabled in Control Panel, we need to make the software buffer larger than the default to help guard against skipping and stuttering. The first parameter specifies the number of samples in the buffer, and the second parameter specifies the number of buffers (which are used in a ring). Therefore the total number of samples to be used for software buffering is the product (multiplication) of the two numbers.
// Increase buffer size if user has Acceleration slider set to off if (caps & FMOD_CAPS_HARDWARE_EMULATED) { result = system->setDSPBufferSize(1024, 10); FMODErrorCheck(result); }
The following is a kludge for SigmaTel sound drivers. We first get the name of the first enumerated sound card driver by specifying zero as the first parameter to getDriverInfo
(the 4th parameter receives the device GUID which we ignore here). If it contains the string ‘SigmaTel’, the output format is changed to PCM floating point, and all the other format settings are left as the sound card’s current settings.
// Get name of driver result = system->getDriverInfo(0, name, 256, 0); FMODErrorCheck(result); // SigmaTel sound devices crackle for some reason if the format is PCM 16-bit. // PCM floating point output seems to solve it. if (strstr(name, "SigmaTel")) { result = system->setSoftwareFormat(48000, FMOD_SOUND_FORMAT_PCMFLOAT, 0, 0, FMOD_DSP_RESAMPLER_LINEAR); FMODErrorCheck(result); } }
We have now done all the necessary pre-requisite legwork and we can now initialize the sound system:
// Initialise FMOD result = system->init(100, FMOD_INIT_NORMAL, 0);
The first parameter defines the number of virtual channels to use. This can essentially be any number: whenever you start to play a new sound or stream, FMOD will (by default) pick any available free channel. The number of actual hardware channels (voices) available is irrelevant as FMOD will downmix where needed to give the illusion of more channels playing than there actually are in the hardware. So just pick any number that is more than the total amount of sounds that will ever be playing simultaneously in your application. If you choose a number lower than this, channels will get re-used and already running sounds will get cut off and replaced by new ones if you try to start a sound when all channels are busy (the oldest used channel is re-used first).
The second parameter gives initialization parameters and the third number specifies driver-specific information (the example given in the documentation is a filename when using the WAV-writer). The initialization parameter will usually be FMOD_INIT_NORMAL
, but for example if you are developing for PlayStation 3, you might use a parameter like FMOD_INIT_PS3_PREFERDTS
to prefer DTS output over Dolby Digital.
If the speaker mode we selected earlier is for some strange reason invalid, init()
will return FMOD_ERR_OUTPUT_CREATEBUFFER
. In this case, we reset the speaker mode to a safe fallback option – namely stereo sound – and call init()
again.
// If the selected speaker mode isn't supported by this sound card, switch it back to stereo if (result == FMOD_ERR_OUTPUT_CREATEBUFFER) { result = system->setSpeakerMode(FMOD_SPEAKERMODE_STEREO); FMODErrorCheck(result); result = system->init(100, FMOD_INIT_NORMAL, 0); } FMODErrorCheck(result);
All of the code above should be included in every application you write which uses FMOD. With this boilerplate code out of the way, we can get to the business of making some noise!
Playing sounds and songs
There are two main ways to get audio into FMOD – createSound
and createStream
. createSound
loads a sound file into memory in its entirety, and decompresses it if necessary, whereas createStream
opens a file and just buffers it a piece at a time, decompressing each buffered segment on the fly during playback. Each option has its advantages and disadvantages, but in general music should be streamed since decompressing an MP3 or Vorbis file of some minutes length in memory will consume some 10s of megabytes, whereas sound effects that will be used repeatedly and are relatively short can be loaded into memory for quick access.
To load a sound into memory:
FMOD::Sound *audio; system->createSound("Audio.mp3", FMOD_DEFAULT, 0, &audio);
To open a stream:
FMOD::Sound *audioStream; system->createStream("Audio.mp3", FMOD_DEFAULT, 0, &audioStream);
The first parameter is the relative pathname of the file to open and the 4th parameter is a pointer to an FMOD::Sound
pointer that receives the resource handle of the audio. Under normal circumstances the 2nd and 3rd parameters should be left as FMOD_DEFAULT
and 0
(the 2nd is the mode in which to open the audio, the 3rd is an extended information structure used in special cases – we will come to this in Part 3 of the series).
Playing a one-shot sound
To play a sound that doesn’t loop and which you don’t otherwise need any control over, call:
system->playSound(FMOD_CHANNEL_FREE, audio, false, 0);
This is the same whether you are playing a sound or a stream; you use playSound
in both cases. FMOD_CHANNEL_FREE
causes FMOD to choose any available unused virtual channel on which to play the sound as mentioned earlier. The 2nd parameter is the audio to play. The third parameter specifies whether the sound should be started paused or not. This is useful when you wish to make changes to the sound before it begins to play.
If you need control of the sound after it starts, use the 4th parameter to receive the handle of the channel that the sound was assigned to:
FMOD::Channel *channel; system->playSound(FMOD_CHANNEL_FREE, audio, false, &channel);
These calls are non-blocking so they return as soon as they are processed and the sound plays in the background (in a separate thread).
Manipulating the channel
Once a sound is playing and you have the channel handle, all future interactions with that sound take place through the channel. For example, to make a sound loop repeatedly:
channel->setMode(FMOD_LOOP_NORMAL); channel->setLoopCount(-1);
To toggle the pause state of the sound:
bool isPaused; channel->getPaused(&isPaused); channel->setPaused(!isPaused);
To change the sound volume, specify a float value from 0.0 to 1.0, eg for half volume:
channel->setVolume(0.5f);
Per-frame update
Although it’s only needed on certain devices and in certain environments, it is best to call FMOD’s update function on each frame (or cycle of your application’s main loop):
system->update();
This causes OSs such as Android to be able to accept incoming phone calls and other notifications.
Releasing resources
Release the FMOD interface when you are finished with it (generally, when the application is exiting):
system->release();
This will cause all channels to stop playing, and for the channels and main interface to be released. Channels therefore don’t need to be released when the application ends, but sounds should be released when you’re done with them (thanks to David Gouveia for the correction!):
audio->release();
Don’t forget to error check
Everything above should be wrapped in calls to our FMODErrorCheck()
function above or some other error-trapping construct. I have just omitted this in the examples for clarity.
Demo application
All of the techniques shown in this article can be seen in this FMOD Demo console application, which shows how to open and play sounds and streams and how to do a smooth volume fade from one track to another. Full source code and the compiled executable are included. The source code can also be seen here for your convenience:
#include "fmod.hpp" #include "fmod_errors.h" #include <iostream> #include <Windows.h> #define _USE_MATH_DEFINES #include <math.h> void FMODErrorCheck(FMOD_RESULT result) { if (result != FMOD_OK) { std::cout << "FMOD error! (" << result << ") " << FMOD_ErrorString(result) << std::endl; exit(-1); } } int main() { // ================================================================================================ // Application-independent initialization // ================================================================================================ FMOD::System *system; FMOD_RESULT result; unsigned int version; int numDrivers; FMOD_SPEAKERMODE speakerMode; FMOD_CAPS caps; char name[256]; // Create FMOD interface object result = FMOD::System_Create(&system); FMODErrorCheck(result); // Check version result = system->getVersion(&version); FMODErrorCheck(result); if (version < FMOD_VERSION) { std::cout << "Error! You are using an old version of FMOD " << version << ". This program requires " << FMOD_VERSION << std::endl; return 0; } // Get number of sound cards result = system->getNumDrivers(&numDrivers); FMODErrorCheck(result); // No sound cards (disable sound) if (numDrivers == 0) { result = system->setOutput(FMOD_OUTPUTTYPE_NOSOUND); FMODErrorCheck(result); } // At least one sound card else { // Get the capabilities of the default (0) sound card result = system->getDriverCaps(0, &caps, 0, &speakerMode); FMODErrorCheck(result); // Set the speaker mode to match that in Control Panel result = system->setSpeakerMode(speakerMode); FMODErrorCheck(result); // Increase buffer size if user has Acceleration slider set to off if (caps & FMOD_CAPS_HARDWARE_EMULATED) { result = system->setDSPBufferSize(1024, 10); FMODErrorCheck(result); } // Get name of driver result = system->getDriverInfo(0, name, 256, 0); FMODErrorCheck(result); // SigmaTel sound devices crackle for some reason if the format is PCM 16-bit. // PCM floating point output seems to solve it. if (strstr(name, "SigmaTel")) { result = system->setSoftwareFormat(48000, FMOD_SOUND_FORMAT_PCMFLOAT, 0, 0, FMOD_DSP_RESAMPLER_LINEAR); FMODErrorCheck(result); } } // Initialise FMOD result = system->init(100, FMOD_INIT_NORMAL, 0); // If the selected speaker mode isn't supported by this sound card, switch it back to stereo if (result == FMOD_ERR_OUTPUT_CREATEBUFFER) { result = system->setSpeakerMode(FMOD_SPEAKERMODE_STEREO); FMODErrorCheck(result); result = system->init(100, FMOD_INIT_NORMAL, 0); } FMODErrorCheck(result); // ================================================================================================ // Application-specific code // ================================================================================================ bool quit = false; bool fading = false; int fadeLength = 3000; int fadeStartTick; // Open music as a stream FMOD::Sound *song1, *song2, *effect; result = system->createStream("Song1.mp3", FMOD_DEFAULT, 0, &song1); FMODErrorCheck(result); result = system->createStream("Song2.mp3", FMOD_DEFAULT, 0, &song2); FMODErrorCheck(result); // Load sound effects into memory (not streaming) result = system->createSound("Effect.mp3", FMOD_DEFAULT, 0, &effect); FMODErrorCheck(result); // Assign each song to a channel and start them paused FMOD::Channel *channel1, *channel2; result = system->playSound(FMOD_CHANNEL_FREE, song1, true, &channel1); FMODErrorCheck(result); result = system->playSound(FMOD_CHANNEL_FREE, song2, true, &channel2); FMODErrorCheck(result); // Songs should repeat forever channel1->setLoopCount(-1); channel2->setLoopCount(-1); // Print instructions std::cout << "FMOD Simple Demo - (c) Katy Coe 2012 - www.djkaty.com" << std::endl << "=====================================================" << std::endl << std::endl << "Press:" << std::endl << std::endl << " 1 - Toggle song 1 pause on/off" << std::endl << " 2 - Toggle song 2 pause on/off" << std::endl << " F - Fade from song 1 to song 2" << std::endl << " S - Play one-shot sound effect" << std::endl << " Q - Quit" << std::endl; while (!quit) { // Per-frame FMOD update FMODErrorCheck(system->update()); // Q - Quit if (GetAsyncKeyState('Q')) quit = true; // 1 - Toggle song 1 pause state if (GetAsyncKeyState('1')) { bool isPaused; channel1->getPaused(&isPaused); channel1->setPaused(!isPaused); while (GetAsyncKeyState('1')); } // 2 - Toggle song 2 pause state if (GetAsyncKeyState('2')) { bool isPaused; channel2->getPaused(&isPaused); channel2->setPaused(!isPaused); while (GetAsyncKeyState('2')); } // F - Begin fade from song 1 to song 2 if (GetAsyncKeyState('F')) { channel1->setVolume(1.0f); channel2->setVolume(0.0f); channel1->setPaused(false); channel2->setPaused(false); fading = true; fadeStartTick = GetTickCount(); while (GetAsyncKeyState('F')); } // Play one-shot sound effect (without storing channel handle) if (GetAsyncKeyState('S')) { system->playSound(FMOD_CHANNEL_FREE, effect, false, 0); while (GetAsyncKeyState('S')); } // Fade function if fade is in progress if (fading) { // Get volume from 0.0f - 1.0f depending on number of milliseconds elapsed since fade started float volume = min(static_cast<float>(GetTickCount() - fadeStartTick) / fadeLength, 1.0f); // Fade is over if song 2 has reached full volume if (volume == 1.0f) { fading = false; channel1->setPaused(true); channel1->setVolume(1.0f); } // Translate linear volume into a smooth sine-squared fade effect volume = static_cast<float>(sin(volume * M_PI / 2)); volume *= volume; // Fade song 1 out and song 2 in channel1->setVolume(1.0f - volume); channel2->setVolume(volume); } } // Free resources FMODErrorCheck(song1->release()); FMODErrorCheck(song2->release()); FMODErrorCheck(effect->release()); FMODErrorCheck(system->release()); }
For A Quick & Dirty Solution
I have made a simple FMOD library which wraps all of the code above and the code in subsequent parts of the series up into an easy-to-use class. Check out the link for more information.
Coming Up…
In Part 2 of our series on FMOD we will take a look at channel groups. I hope you found this tutorial introduction useful!
I’m a software developer with very limited work capacity due to having the debilitating illness M.E. – please read my article Dying with M.E. as a Software Developer and donate to the crowdfund to help me with my bucket list if you found this article useful. Thank you so much!
Hello Katy!
Are you sure about the bit about releasing the system also releasing the loaded sound objects? I’m somewhat confused by the documentation, which I quote:
“Call System::release to close the output device and free all memory associated with that object. Channels are stopped, but sounds are not released. You will have to free them first. You do not have to stop channels yourself. You can of course do it if you want, it is just redundant, but releasing sounds is good programming practice anyway. ”
The second sentence seems to make clear that sounds are not released automatically, and must therefore be tracked and released manually before the system. This seems counter intuitive though, and the last sentence adds to the confusion.
Hey David,
It looks like you are right, I went back to the FMOD documentation last night and saw those paragraphs too. But if you go to the documentation for System::close(), which is called by System::release(), it says:
“Closing the output renders objects created with this system object invalid. Make sure any sounds, channelgroups, geometry and dsp objects are released before closing the system object.”
So it would appear that while you don’t have to release the channels, you do have to release the sounds. Well spotted! I will update the blog post when I get a moment.
Oh, I’m also glad you just quoted that bit from the close() method, since it made me notice that channel groups also need to be released. I made the assumption that they worked the same as regular channels and did not need to be released.
Blog post updated, thanks 🙂
By the way, if you ever feel like writing another part for this series, one thing that you could describe is how to write directly to the audio buffer for some low level audio programming.
I already had some experience doing that in other APIs such as XNA and Flash, but it took me more time than it should to figure out how to do it in FMOD – I couldn’t find much about it in the documentation, and forgot to look into the example projects. For the record, here’s what I did.
The process turned out to be creating a *looping stream* with the FMOD_OPENUSER flag and a custom FMOD_CREATESOUNDEXINFO object using a PCM read callback set to write the data to it.
Besides this callback, I also needed to specify the size of the info structure, the format of the audio (e.g. PCM16 or PCMFLOAT), the default frequency (44100), the number of channels (2), the size of the decode buffer (depends), and the length of the stream, which I set to the equivalent of five seconds of audio (frequency * bitrate * channels * 5).
I’m always open to suggestions 🙂 Although it depends mostly on my time and health (the last 2 years, mostly the latter). I’ve never tried that in FMOD but I’m glad you threw in some pointers to save me the head-scratching if I do decide to write about that. I’ve done that in one API and it was many years ago (might have been a WAV writer for Winamp, can’t quite remember), I seem to remember it was basically a case of running it in a separate thread and making sure the buffer never under-ran.
If you really want me to blog about that for others and you have a source code sample, feel free to post it on pastebin and I’ll re-factor it with comments and explanations. No promises on a timeline 🙂
I did not get around to implementing any significant sample for this, as I was mostly just playing around. But the following FMOD official example is a good starting point, although it can be trimmed a lot.
http://pastie.org/6219417
And here’s the callback I used to produce a sine wave with controllable volume and frequency (in this case it was in C#):
http://pastie.org/6219478
Doesn’t look as traumatic as I was expecting. I’ve saved the source files so I may take a look at that when I’ve caught up with all the platform game articles. Thanks!
I’ve spent the night writing a couple of nice clean examples using the official demo code, your C# example, and some other bits and pieces I found on the interwebs, and added some other example sounds (sawtooth, square wave and white noise). I’ll get around to blogging it in the next few days hopefully 🙂
Could you tell me if there is any C++ specific gotcha which would make it preferable to do:
FMOD_RESULT result = whatever();
FMODErrorCheck(result);
Instead of:
FMODErrorCheck(whatever());
Or is it just a matter of style?
Unless you want to use result later (in which case you need to do the first version), or you want to be really pedantic about allocating 4 bytes on the stack until result goes out of scope, it is as far as I know purely a matter of personal preference 🙂
Any idea whether it’s possible to drive 2 soundcards with 1 FMOD program?
I haven’t tried it but I believe that is perfectly possible. You just need to create (as far as I know) multiple instances of FMOD::System and assign each one to a different sound card. The documentation for System_Create states “Use this function to create 1, or multiple instances of FMOD System objects” which I assume means you can run more than one FMOD engine from the same process. Presumably any sounds you want to play on two or more sound cards have to be loaded twice or more as each sound is owned by a single FMOD::System instance, but I haven’t checked.
Call System::getNumDrivers to get the number of (logical) sound cards on the system, ie. the number of outputs. Call System::getDriverInfo to get the name of each device. Each device has an ID in FMOD from zero to n-1 where n is the output of System::getNumDrivers. When you have selected the sound cards you want to use, call System::setDriver(int driverID) to re-direct all output to the desired device.
Hope that helps!
Realizing it’s been almost exactly a year, note that I’ve tried this only today, and indeed it works! I have 2 soundcards and am able to drive both independently this way.
Wow, a year already, feels like I wrote this article last month! Good to know it works that way 🙂
Hello, I’m a student from South Korea. I am trying to use FMOD in the platform of MFC.
This is Almost my first time of using a library such as FMOD.
My first goal is to Play a music of Audio.mp3. I have saved a music file named Audio.mp3 in my Project folder. However, error occured when I’m using the function system->createSound / createStream / playSound
My first prediction was that, I couldn’t understand of including Post Built Event. copy /y “C:\Program Files (x86)\FMOD SoundSystem\FMOD Programmers API Windows\api\fmodex.dll” “$(OutputPath)”
Eventhough I have Copied my Post Built Event same as above, an error was sent in the OutputPath. Do i need to Change the OutputPath?
If the Post Built Event had nothing to do with compliling, what should have been the problem..? I’d be waiting for your advice. T_T..
void CMy111Dlg::OnBnClickedButton1()
{
InitFMOD();
}
void CMy111Dlg::ERRCHECK(FMOD_RESULT result)
{
CString strText;
if(result!=FMOD_OK)
{
strText.Format(_T(“FMOD 오류”),FMOD_ErrorString(result));
MessageBox(strText,_T(“FMOD error!!”),MB_OK);
num++;
exit(-1);
}
}
void CMy111Dlg::InitFMOD(void)
{
result = FMOD::System_Create(&system);
ERRCHECK(result);
result = system->init(100, FMOD_INIT_NORMAL, 0);
ERRCHECK(result);
result = system->getVersion(&version);
ERRCHECK(result);
if(versioncreateSound(“Audio.mp3”, FMOD_DEFAULT, 0, &audio);
ERRCHECK(result);
FMOD::Sound *audioStream;
result = system->createStream(“Audio.mp3”, FMOD_DEFAULT, 0, &audioStream);
ERRCHECK(result);
FMOD::Channel *channel;
result = system->playSound(FMOD_CHANNEL_FREE, audio, false,0);
ERRCHECK(result);
}
So, did it compile or not? And what was the error?
Also the code contains a call to ‘versioncreateSound’; that won’t compile ofcourse (but that seems too trivial to be your problem).
I’ve copied another source of mine. The source i’ve used was
void CMy111Dlg::InitFMOD(void)
{
result = FMOD::System_Create(&system);
ERRCHECK(result);
result = system->init(100, FMOD_INIT_NORMAL, 0);
ERRCHECK(result);
result = system->getVersion(&version);
ERRCHECK(result);
if(versioncreateSound(“Audio.mp3”, FMOD_DEFAULT, 0, &audio);
ERRCHECK(result);
FMOD::Sound *audioStream;
result = system->createStream(“Audio.mp3”, FMOD_DEFAULT, 0, &audioStream);
ERRCHECK(result);
FMOD::Channel *channel;
result = system->playSound(FMOD_CHANNEL_FREE, audio, false,0);
ERRCHECK(result);
}
In the compiling process there was no errors. However, when i executed my program.
The ERRCHECK(result) function sent me that a problem had occured during createSound / createStream / playSound.
If i had the ERRCHECK(result) line deleted and executed my program.
A popup messagebox was sent that there was a critical problem and the program was terminated.
Thank you for replying 🙂
I’ve used result = system->createSound(“Audio.mp3”, FMOD_DEFAULT, 0, &audio); !!!!
when i Post my comment it is transfered to if(versioncreateSound……. I don’t know why;;
Ok, but also this:
result = system->playSound(FMOD_CHANNEL_FREE, audio, false,0);
I’m not sure sure if playSound() accepts a 0 for the channel to return. Better to pass &channel rather than 0. I debug mode you should get a call stack where you can check which call (in your code) exactly gave the crash, so you can check the arguments/variables being used.
I’ve found my problem;……
My Audio.mp3 file was named incorrectly..T_T
When I have another problem I’d like adivce.
Heya there! I’d like to ask a simple question( but with a possible complex answer). I’ve been following this tutorial, but half-way through I stopped because it’s late at night and I don’t want to waste time.
My simple purpose was to have a car engine acceleration done that I could control how I’d like. Through a couple of google searches I’ve arrived at this tutorial: http://www.youtube.com/watch?v=G7zvzH4nPuA
This prove to be a promising path to follow, so I ended up having some engine sounds and doing that. Next I downloaded the API.
The problem is that I want to somehow integrate the Designer project with a C++ program written with the FMOD API. Is this easy or really hard? As in the video, I would only need to control the “RPM” value. Can you point me to some resources\tutorials or if it isn’t that hard, can you please suggest me something from the reference?
Please keep in mind that I’m quite a beginner.
I’m sorry, I don’t have any experience with the FMOD Designer, only the code side… perhaps another reader can help you 🙂
It’s not that hard, but not particularly easy.
I would recommend checking the official car engine sample that comes with FMOD Designer and reading the documentation. If I remember correctly, the sound event is composed by two layers – one for when the engine is under load (i.e. accelerating), and another for when it is not (i.e. decelerating). Then there is a “load” parameter that you set from your game which determines which of the two layers should be used, with a 50/50 mix of both in the middle. Then, on the horizontal axis comes the “rpm” parameter. There are four or five different sounds recorded at different rpm values, all placed side by side on the layers. These sounds overlap a bit and cross-fade so that the transitions are smoother, and they use the “auto-pitch” feature of FMOD Designer which basically increases the pitch gradually based on the value of the “rpm” value.
So, what I suggest is that you start with the official car engine sample that comes with FMOD Designer, save that in a project and load the project into your game. Then what you need to do is update the “rpm” and “load” parameters based on values coming from your game. The main problem will probably be making the rpm and load values vary consistently and in a realistic fashion.
Loading a FMOD designer project, playing a sound event and changing parameters is easy and very similar to initializing the regular audio system and playing a regular sound. It’s something like:
// Create an event system object
FMOD::EventSystem* eventSystem;
FMOD::EventSystem_Create(&eventSystem);
// Initialize the event system and load the project
eventSystem->init(100, FMOD_INIT_NORMAL, 0, FMOD_EVENT_INIT_NORMAL);
eventSystem->load(“project.fev”, 0, 0);
…
// Get a reference to the event
FMOD::Event* event;
eventSystem->getEvent(“ProjectName/EventGroupName/EventName”,
FMOD_EVENT_DEFAULT, &event);
// Begin playing the event
event->start();
…
// Get a reference to the parameter
FMOD::EventParameter* parameter;
event->getParameter(“ParameterName”, ¶meter);
// Change the value of the parameter
parameter->setValue(2.0f);
…
// Update event system every frame
eventSystem->update();
// Release event system when we are done
eventSystem->release();
Is there a way to tell when a sound finishes playing in FMOD?
Love the blog btw Katy
Yes, you can poll the channel on which the sound is being played with Channel::isPlaying(bool *playing) which sets the pointer to false when the sound has finished playing. You need to fetch the sound’s channel when you call playSound() to be able to poll the correct channel.
Thanks for the compliments!
There’s also an event based solution 🙂 Use the Channel::setCallback() method to register a callback on the channel that is playing the sound. Then there is a parameter on your callback function which tells you the type of the callback, and all you have to do is check if it corresponds to FMOD_CHANNEL_CALLBACKTYPE_END and handle it accordingly.
Nice. I was looking in the docs for the previous poster for an event but I looked at FMODCREATESOUNDEX or whatever it’s called and couldn’t find one.
Trying to use your tutorial to get started… The FMOD_CAPS is reading as undefined. I have tried including all the headers in the fmod pack but it is still not working. Do you know which header this thing is in?
You should include the main header fmod.hpp (for the C++ interface), that’s the only one you need and FMOD_CAPS will then be defined 🙂
I have included fmod.hpp, FMOD_CAPS is still not working for me.
Then I could only suggest that your download was somehow corrupt. Uninstall the FMOD API altogether and download the latest version from fmod.org and try again. I promise you that FMOD_CAPS is defined in that header 🙂
I still can’t get FMOD_CAPS to respond. Perhaps you can tell me how to properly install/link the fmod API files to VS2012 (I am making a game with openGL atm), I did see some .a files in the low-level api folder, I don’t know what to do with those. Currently, I am simply putting the fmod folders into my c/program files(x86)/VC/bin, etc. Is there something else I need to do?
Define ‘not working’? In C++ I do this:
FMOD_CAPS caps;
// Try to use system default speakermode
fmodSystem->getDriverCaps(0,&caps,0,&systemSpeakerMode);
The FMOD_CAPS type comes from fmod.h. If you want to check if you’re including that .h files, why not insert an #error line somewhere? At the top should give you a clue whether you’re including the right file. Near the ‘FMOD_CAPS’ typedef in fmod.h would give you a clue whether the preprocessor gets to the typedef.
By not working, I mean that VS is reading FMOD_CAPS as undefined, even though I have #include “fmod.hpp”, which should have “fmod.h” (I’ve tried including “fmod.h” too without success). How would you use an #error line? I haven’t heard of this feature before.
#error works just like the other #’s (#ifdef etc). So you get:
#ifdef FMOD_H
#error we are here
#endif
This gives a compiler error, which is useful in tracking which (if any) part of the .h is actually processed. This can give clues as to why it never passes the FMOD_CAPS line. If you don’t get an error at all even if you put an ‘#error’ line at the top, this means you’re not including the file that you think you are!
Note that I use this in Visual Studio; not sure if other compilers support it. Very handy though.
I downloaded the demo, tried to run it and got
Any idea why?
Probably that you tried to compile it as a Windows application so it was looking for WinMain() as the entry point. Change the configuration to Console application instead.
Sounds like you didn’t include WinMain() in your project – which you don’t need because the example is a console application, so just change the project type to Console Application and you should be good to go 🙂
Katy.
Hello again, Katy!
I wonder if you could help me – programming in Linux with FMOD worked fine for me, but now I wanted to try to port my code onto Windows. So I changed some Linux’s functions to ones working under Windows, pasted whole code into Visual Studio 2010. Then I included everything as you have said at the beginning of this tutorial to MVS. I also included stdafx.h at the beginning of all includes due to the fact that precompiled headers should be included that way.
Nonetheless, building solution still won’t work. I’m getting errors like:
And then a lot of errors pertaining to not being able to identify used FMOD functions. I have never used Visual Studio before so I need someone’s guidance with my problem. What should I do?
Thank you in advance.
Winged
Problem solved. I did not notice that I’d included fmod.h instead of fmod.hpp ;x
hey, I copy pasted your demo but I don’t hear any sound. No errors, it compiles and everything, I just can’t hear the .mp3 I specified ! any clues ? great blog btw !
Check that the demo is outputting the sound on a channel on your sound card that you can actually hear, ie. the front speakers or headphones 🙂
how do you do that ? with
system->playSound(FMOD_CHANNEL_FREE, audio, false,0);
?
thanks!
Enumerate the playback drivers and check their names to see which one corresponds to your speakers/headphones. I haven’t tested this code but try something like:
Once you’ve found the ID of the driver you want to output on, use:
Note that a value of 0 (zero) uses the OS-default driver as determined in your sound settings in Control Panel.
Katy.
Hello,katy,i come from China and i am just confused about the statement ” while (GetAsyncKeyState(‘2’));” and so on.Could you give me some details about it?
That line simply stalls the code until the user releases the ‘2’ key, so that the action of pressing 2 is only triggered once each time it is pressed rather than repeatedly. Hope that helps!
Hi, Katy i have configure all the above settings in my VS2013 but still am getting an error message can you help me out on this….
1>—— Build started: Project: again1, Configuration: Debug Win32 ——
1> Parse Error
1> The filename, directory name, or volume label syntax is incorrect.
1>C:\Program Files (x86)\MSBuild\Microsoft.Cpp\v4.0\V120\Microsoft.CppCommon.targets(122,5): error MSB3073: The command “xcopy /y “C:\FMOD\
1>C:\Program Files (x86)\MSBuild\Microsoft.Cpp\v4.0\V120\Microsoft.CppCommon.targets(122,5): error MSB3073: api\fmodex.dll” “c:\users\hack1on1\documents\visual studio 2013\Projects\again1\Debug\”
1>C:\Program Files (x86)\MSBuild\Microsoft.Cpp\v4.0\V120\Microsoft.CppCommon.targets(122,5): error MSB3073: :VCEnd” exited with code 123.
========== Build: 0 succeeded, 1 failed, 0 up-to-date, 0 skipped ==========
It’ll be great if you can find out the solution…. Regards
Here’s the step i did with my VS2013 Am I missing something?? And i did copy and paste “fmodex.dll” in my working folder… But still am getting an error link like identifier not found, undeclared identifier and so and so….please help…
First step = http://s16.postimg.org/o121enm1h/fmod1.png
Second step = http://s27.postimg.org/5to2roco3/fmod2.png
Third step = http://s9.postimg.org/zbqylgqy7/fmod3.png
Final step = http://s30.postimg.org/vv8nbqww1/fmod4.png
here’s the other trouble am having for a quite long time http://s1.postimg.org/3q8ae9k73/OMG.png
And to be totally honest i don’t think am having a problem linking my library file’s cause am getting a perfect output

[quote]
Per-frame update
Although it’s only needed on certain devices and in certain environments, it is best to call FMOD’s update function on each frame (or cycle of your application’s main loop):
system->update();
This causes OSs such as Android to be able to accept incoming phone calls and other notifications.
[/quote]
I’ve found that on macOS, forgetting to call update() on the system will result in no sounds being played after 64 times:
https://qa.fmod.com/t/why-my-sounds-could-only-play-64-times/14179
The answer there says that it’s required for channel management. So it’s certainly not an edge case.
Oh, and another thing: callbacks rely on update() being called, too:
https://www.fmod.com/docs/api/content/generated/FMOD_CHANNELCONTROL_CALLBACK.html
Yes, Update() is the whole synchronization step between user requests and audio code. Don’t skip it even if it seems ok