The SoundEngine module

As the previous section of this chapter shows, the basics of using s3eSound are actually fairly straightforward. The main issue that we have to deal with as developers is the fact that s3eSound can only support raw uncompressed 16-bit PCM samples, which means it is our responsibility to get the sound data into memory so it can be played.

One of the most common file formats for storing sound samples is the WAV file, so wouldn't it be great if we could use this format to store our sound effects? Wouldn't it also be great if we could load these files into memory using the same resource manager code that we've used for textures and 3D models?

The answer to our prayers is the SoundEngine module, which is a layer that sits on top of s3eSound and allows us to easily load and access sound effects using the resource manager.

The SoundEngine module doesn't just stop there though. It also wraps up the s3eSound calls we've learnt about in this chapter and it allows us to support a further sound format that can be stored in WAV files—namely the compressed IMA ADPCM type. This is particularly useful given that sound sample data can be quite large in size; so this format helps us claw back some memory space at the expense of a slight drop in sound quality.

The following sections give a brief introduction to using this module, but for full details you should refer to the source and header files to see all the functionality SoundEngine has to offer. The sound example project accompanying this chapter also makes use of this module, so take a look at that to learn more.

Adding the SoundEngine module to a project

The SoundEngine module actually ships with the Marmalade SDK, but it lives, awkwardly, in the examples directory. The easiest way to solve this is to just copy the entire SoundEngine directory to the directory where your project resides and then reference it by adding SoundEngine to your MKB files subprojects. This is the same approach we used with the GUI and Localise modules that were introduced in the sample code for the previous chapter.

Note

The location of the SoundEngine module in the examples folder means it isn't really considered part of the main Marmalade SDK. In practice it is highly unlikely that the SoundEngine code will suddenly disappear from the SDK, since the s3eSound API is unlikely to change drastically from what it is now; so you shouldn't have any concerns about using it directly in your own projects. If you prefer to write your own code, SoundEngine does at least serve the purpose of being a very good example of how to use the s3eSound API.

With the module added to our project, we can include the file IwSound.h in our code to make use of it. A call to IwSoundInit is needed to set everything up and a call to IwSoundTerminate cleans up at the end of our program.

We must also add a custom resource handler to allow WAV files to be loaded by the resource manager. The following code snippet will do the trick:

IwGetResManager()->AddHandler(new CIwResHandlerWAV);

Finally, there is a manager class that takes care of all sound-related events and we must ensure that we call the Update method of this class somewhere within the main game loop. We do this with the following line of code:

IwGetSoundManager()->Update();

Loading and accessing sound resources

To load a WAV file all we have to do is add a reference to its filename into a GROUP file, though we still need to do a little more in order to be able to play the sound back. What we need to do is declare an instance of the class CIwSoundSpec.

This class allows us to reference a particular sound sample by name and lets us set a volume and pitch to play the sound at. We can also specify whether or not we want the sound to loop (note that SoundEngine currently provides no way of specifying the number of times to loop the sound; we can only indicate continuous looping). Here's an example definition:

CIwSoundSpec
{
  name gun1
  data gun_shot1

  // Play at the default pitch for the sample
  pitch 1.0

  // Play at half volume
  vol 0.5

  // Do we want this sound to loop?
  looping false
}

The pitch and vol (volume) parameters are specified as fractional scales, where 1.0 indicates the default pitch or volume level of a sound. We can also specify a range for both these parameters that allows a random value to be chosen when starting the sound. Specifying a range for the pitch can be quite useful to add a bit of variety to the sound effects in your game without having to add lots of slightly different sound samples.

The example below shows how to specify ranges for the volume and pitch:

CIwSoundSpec
{
  name gun2
  data gun_shot2

  // Choose a random pitch when playing this sound
  pitchMin 0.9
  pitchMax 1.1

  // Choose a random volume when playing this sound
  volMin 0.9
  volMax 1.1

  // Do we want this sound to loop?
  looping false
}

Another useful class that we have access to is CIwSoundGroup. This allows us to collect a number of different sound effects together and pause, resume, stop, or alter the volume or pitch of any that are currently being played all at the same time. Note that a sound group only allows a single volume or pitch value to be specified, not a random range:

CIwSoundGroup
{
   name guns

   // Reduce volume of all gun sounds by a half
   vol 0.5

   // Include the gun1 sound in this group
   addSpec gun1
}

Sounds can be added to groups using the addSpec keyword, or alternatively you can add CIwSoundSpec to a group when it is defined by using the group keyword followed by the group name, in its definition. We can use either method, but the group or sound must have been declared before we make reference to it.

To access a sound specification or group, we just load the GROUP file and retrieve them using the resource manager in the normal way. Here's an example:

IwGetResManager()->LoadGroup("sounds.group");
CIwSoundSpec* lpGunSpec = static_cast<CIwSoundSpec*>(
  IwGetResManager()->GetResNamed("gun1", "CIwSoundSpec"));
CIwSoundGroup* lpGunsGroup = static_cast<CIwSoundGroup*>(
  IwGetResManager()->GetResNamed("guns", "CIwSoundGroup"));

Playing, stopping, and altering sound parameters

Once we have hold of a pointer to CIwSoundSpec we can start playing it by calling the Play method, which will do all the behind-the-scenes stuff of allocating a free channel and setting volume and playback speed. The Play method can be passed an optional parameter, which is an instance of the class CIwSoundParams, that allows the volume and pitch to be modified when starting the sound.

The Play method returns a pointer to a CIwSoundInst class, which has methods to allow that single instance of the sound to have its volume or pitch modified, and also provides methods called Pause, Resume, and Stop, which should be self explanatory! If no free sound channel is available, the Play method will return NULL.

If we have a pointer to CIwSoundGroup we can affect all currently playing instances of sounds contained within it. Again there are Pause, Resume, and Stop methods that do what you would expect, plus there are the methods SetVol and SetPitch that will scale the current volume and pitch of the sounds. These methods use the value IW_GEOM_ONE (4096) to indicate a scale of one.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
18.116.62.168