Adding Sounds - By
Asriel
Playing sounds in Quake 3 is really quite easy,
but can seem confusing. So, today we will have a look at basic
sound functionality, and the various options it presents to
you.
Fundamentally, a sound is a temporary entity.
Thus, you ‘create’ the sound by using G_TempEntity. The astute
among you might have noticed a little function tucked away in
g_utils.c called G_Sound. This is ‘wrapper’ for the
functionality the engine exposes in G_TempEntity with the
sound flags. We won’t use this though, we are going to write
our own to make sure you understand sounds.
In
Beryllium, I added a function that could play sounds to every
client in the game, like an announcer. I’ve ripper that right
out, and here it is…
void BroadCastSound() {
char name[MAX_TOKEN_CHARS];
gentity_t *te;
vec3_t origin;
trap_Argv(1, name, sizeof(name));
if(!strlen(name))
return;
origin[0] = origin[1] = origin[2] = 0;
te = G_TempEntity(origin, EV_GLOBAL_SOUND);
te->s.eventParm = G_SoundIndex(name);
te->r.svFlags |= SVF_BROADCAST;
}
This function was designed to be called from the
console, so it extracts the name of the sound from the first
argument on the command. We don’t really want this though, so
we are going to change it so it can be called from anywhere.
We need to make changes so that we can call it with the path
to the file we want to play. I’ve pasted an appropriate change
below, but you might want to see if you can do it alone before
‘cheating’ :).
void BroadCastSound(char *path) {
gentity_t *te;
vec3_t origin;
if(!strlen(path))
return;
origin[0] = origin[1] = origin[2] = 0;
te = G_TempEntity(origin, EV_GLOBAL_SOUND);
te->s.eventParm = G_SoundIndex(name);
te->r.svFlags |= SVF_BROADCAST;
}
Right, lets run through this. A temporary entity is
still an entity, so at the top, we declare an entity type
variable. Now, this is important - origin is the vector
location where the sound will occur. This makes no difference
to our sounds, as we will find out in a moment, but for yours,
it does. You might want to have a sound eminate from a base
when a flag it captured or something (I don’t know, be
creative). This origin is the 3d co-ordinate of the source of
your sound.
Next, we check to see we were actually
given a path. Calling G_SoundIndex without an empty string
seems to cause a Q3 bomb, so this is just a simple check to
save crashing ourselves if we forget to put in a
path.
Right, now we set our origin to 0, 0, 0. This is
because we are going to have a sound have NO falloff, and play
to everyone, so though it needs an origin, it makes no
difference where it is. 0, 0, 0 is as good as any. Next, we
create the entity, at the origin we specified. The type of
this entity is EV_GLOBAL_SOUND, which means it plays to every
connected client. We could have used EV_GENERAL_SOUND, which
would play a ‘normal’ sound that only occurs in the area
around our origin co-ordinate. If you specify this, you’ll
want to give a useful origin, such as the current position of
a player. We’ll discuss how to do this in a
second.
Next up, we set the temp entities parameters to
the index of the sound we want to play. Quake 3 incorporates a
nice caching system, so it doesn’t have to reload the sound
every time its used. This first time G_SoundIndex is called
for a given sound path, it loads the sound, caches (‘stores’)
the it in memory, and assigns it a unique index number. Then,
if the same sound is called again, it returns that number,
rather than having to reload the sound.
Lastly, we send
our sound off to be played, by telling Quake 3 we are ready to
broadcast this entity to all the clients. Next frame, the
sound request will be sent over the network, and all the
clients will hear it! Test this out in your code by
prototyping the function in g_local.h. Just go to the bottom,
and add...
void BroadCastSound(char *path);
Then call it from somewhere with the FULL path of
the sound, something like...
BroadCastSound("sound/bob.wav");
bob.wav can be in a pk3, in a folder called sound,
or if you're not running a pure server, create a folder called
sound, and put them in their. The format of the sound matters.
No stero, and 8 bit work best for me.
Right, just a
couple of things to clear up. There are different ‘channels’
for sounds to play on, so they don’t override each other much.
Have a look at the G_Sound definition in g_utils.c, and calls
to this. Also, have a look at this function and how it has
been called in the game code to see how to set sounds centred
on an entity, rather than the world.
There we go, a
(very) brief and simple run down on how to get sounds into
your mod. Questions comments and rebukes for technical
inaccuracies to adamw@archgrove.co.uk, or
ICQ me on 65572335.
Adam "Asriel" Wright Beryllium Q3
|