Modding/Creating Custom Ambience Sounds
By: Simon Viklund
Published :02 March 2007

In this example, I'm gonna edit the radio that can be heard in some maps, e.g. mission 2 in the SP campaign, or the Shanty Town MP map, and make it play your favourite music.

Editing an Existing Soundbank 
In this example, I'm gonna edit the radio that can be heard in some maps, e.g. mission 2 in the SP campaign, or the Shanty Town MP map, and make it play your favourite music.
1. Creating the folder
In your GRAW folder, go into local, and create a folder named "english". You will need to copy all the files we're messing with in this folder into the other "language" folders if you want the mod to work in these languages as well. Then, create all the entire folder-and-sub-folder tree that branches out to the soundbank/wavebank you want to edit (corresponging to the folder tree in the "data" folder). In this example we want to edit the radio_sound.xml and radio_wave.xml, which are located in data/sound/environment/radio, so we create local/english/sound/environment/radio.

2. Install Nemon's decompiler
Install Nemons decompiler. You'll need Microsoft .Net to make it work - that download is also linked from the site. Just put Nemon's decompiler exe-file in your graw/Bundles folder - it's not dependent on lying in a certain folder or anything, so just put it where you think it's best suited. I'd prefer the graw/Bundles folder.
3. Check out the bundle file
Start Nemon's decompiler (BundleReader.exe) and click "Open Bundle" in the lower left corner. Go into graw/Bundle folder (if you're not already there) and open the .bundle file containing the soundbank/wavebank you wish to edit. Some soundbanks/wavebanks were not in the retail version and have been added in patches, then that data is available only in the patch.bundle file. Other data was in the retail version of the game and have not been altered by any patch - then that data is only in the quick.bundle file. The data that was in the retail version and has been altered by patching are in both the quick.bundle and patch.bundle file - but needless to say it is the data in the patch.bundle that is used when the game runs. The best way to know whether a soundbank/wavebank has been patched or not is to just open the patch.bundle file, check the data/sound folder and its subfolders, and take notes of everything that is there - if the thing you are about to mod is there, you should mod those files and not the ones in the quick.bundle file.

4. Check out the right *_wave.xml in the bundle file
So now we have the quick.bundle opened (the radio_sound.xml and radio_wave.xml have not been edited in any patch, so in our example the data is only available in the quick.bundle file). In the left hand window, click your way down the folder tree into data/sound/environment, and click the "radio" folder to see a list of the files in that folder, shown in the same window as the folder tree. Clicking on any of those files (we are interested in the .xml files, not the .xml.bin files) will show the content of that file in the right hand window. Do so with the radio_wave.xml (click it, that is).

5. Create your own copy of the *_wave.xml to mod
So there, in the right hand window, you have the xml file that ties in the sound that are supposed to be played by the radio. You'll see a list of .wav files beginning with "illnino_", those are of course the Ill Nino songs played on the radio in the unmodded game. Mark all this data ("<?xml version..." etc. all the way to "</waveank>") with your mouse cursor and copy the text into your favourite text editor (which of course is UltraEdit). Save the file right away in the local/english/sound/environment/radio/ folder you created at stage 1 of this guide. It should, of course, be named "radio_wave.xml".

6. Collect the sounds you want to use
Take your favorite CD (or a bunch of songs in mp3 format that you like, however, remember that illegal downloading is theft), rip/convert it to your computer in .wav format (not .mp3 masked as .wav or anything weird, just plain ol' .wav format). To cut the hard disc streaming some slack, you can convert the files to 22 kHz format. In this example I'm ripping Pearl Jam's "Ten". Put the songs in your local/english/sound/environment/radio folder (where your copy of the original bundled radio_wave.xml already is). Name the files in a simple way (no weird non-english characters, also replace spaces with underscore ("_"). My list of .wav files now looks like this:


9. Add your songs to the *_wave.xml file
Go back to the text editor with the radio_wave.xml file. If you are adding more songs than are originally in the radio's playlist (five), you'll have to duplicate the existing lines to get all your songs in there. Note that they should all have a unique "name" tag. I suggest you do as I've done and just call the songs "song01", "song02"... etc. I have eleven Pearl Jam songs I want to be played by the radio, so I add six lines to the existing five, and call the additional songs "song06" through "song11".

10. Clean up the *_wave.xml file
Get rid of all the "quality", "size_before", "size", "compression", "offset" and "bank" tags in all of the xml file - that data will only mess your mod up. After I've done so, my example radio_wave.xml file looks like this:

<?xml version="1.0" encoding="iso-8859-1"?> <wavebank name="radio_wave" dir="data/sound/environment/radio" xmlns:xi="x">
    <wave name="song01" file="pearljam_once.wav" stream="true" />     <wave name="song02" file="pearljam_even_flow.wav" stream="true" />
    <wave name="song03" file="pearljam_alive.wav" stream="true" stream="true" />
    <wave name="song04" file="pearljam_why_go.wav" stream="true" stream="true" />
    <wave name="song05" file="pearljam_black.wav" stream="true" stream="true" />
    <wave name="song06" file="pearljam_jeremy.wav" stream="true" stream="true" />
    <wave name="song07" file="pearljam_ocans.wav" stream="true" stream="true" />
    <wave name="song08" file="pearljam_porch.wav" stream="true" stream="true" />
    <wave name="song09" file="pearljam_garden.wav" stream="true" stream="true" />
    <wave name="song10" file="pearljam_deep.wav" stream="true" stream="true" />
    <wave name="song11" file="pearljam_release.wav" stream="true" stream="true" />

...a neat and tidy little playlist, ain't it? Note that I leave the stream="true" tag in there, as the song files are large, and we don't want them in the RAM. If you're editing some other file, like frogs_wave.xml (to edit the frog sounds) you should get rid of the stream="true" tag as you want to keep the amounts of streams to a minimum, and frog sounds are small enough to fit in the RAM.

11. Create your own copy of the *_sound.xml to mod
Now, go to Nemon's decompiler again, and click on the "radio_sound.xml" file in the left hand window. The contents of that file will now be shown in the right hand window. This is the file that decides how the .wav files listed in the *_wave.xml document are treated when they are called for by the script - this includes gain (audio volume), pitch or pitch randomization attributes, etc. etc. Copy this data into your text editor and save it as "radio_sound.xml" in the same folder as your radio_wave.xml files and .wav files.

12. Edit your newly created copy of the radio_sound.xml file, and add/remove the correct amount of files. In this file, the songs are only referred to as "song01", "song02", etc. - which of course are the names they were given in the radio_wave.xml file. You understand now why it is easier to let go of the actual song titles in that step.

This next part is hard (and lengthy) to describe, but I hope you have some basic programming experience (html at the least, to get some "eye for code") and I'll give it a shot: Look at the bottom of the radio_sound.xml file. There is a tag named <sound name="radio"... Whenever the script calls for the "radio" cue (that is, if you place a sound source in a map, tells it to play the "radio" cue and then start that map), this sound is called for, and the cue then randomizes between either of the cues "radio_a" or "radio_b". The weight tag is to makes sure that in four times out of five, the randomizer chooses the "radio_a" cue - you can use weight tags to make sure there is a larger chance for one or more options to be chosen over the others. The "radio_a" and "radio_b" cues (above the "radio" cue in the xml file) then contain song01 through song04, and song05 respectively. This means that every time a sound source calls for the "radio" cue (every time you start a map with a sound source calling for the "radio" cue (this is only done once as the "radio" cue then loops and is never retriggered)) that sound source becomes either a "radio_a" or "radio_b" cue, and then loops that "playlist" for all eternity. I, however, want a simple radio that doesn't randomize between different playlists, so I slim the code down and reduce the number of cues so that every time the radio is called for, it always plays the Pearl Jam songs in the album order, and then starts over. After editing, my radio_sound.xml file looks like this:

<?xml version="1.0" encoding="iso-8859-1"?> <soundbank name="radio_sound" default_wavebank="radio_wave" xmlns:xi="x">     <sound name="song01" group="ambient_loop" has_custom_distances="true" zero_distance="60" gain="-12" occlusion="false">
        <wave name="song01"/>
    <sound name="song02" group="ambient_loop" has_custom_distances="true" zero_distance="60" gain="-12" occlusion="false">
        <wave name="song02"/>
    <sound name="song03" group="ambient_loop" has_custom_distances="true" zero_distance="60" gain="-12" occlusion="false">
        <wave name="song03"/>
    <sound name="song04" group="ambient_loop" has_custom_distances="true" zero_distance="60" gain="-12" occlusion="false">
        <wave name="song04"/>
    <sound name="song05" group="ambient_loop" has_custom_distances="true" zero_distance="60" gain="-12" occlusion="false">
        <wave name="song05"/>
    <sound name="song06" group="ambient_loop" has_custom_distances="true" zero_distance="60" gain="-12" occlusion="false">
        <wave name="song05"/>
    <sound name="song07" group="ambient_loop" has_custom_distances="true" zero_distance="60" gain="-12" occlusion="false">
        <wave name="song05"/>
    <sound name="song08" group="ambient_loop" has_custom_distances="true" zero_distance="60" gain="-12" occlusion="false">
        <wave name="song05"/>
    <sound name="song09" group="ambient_loop" has_custom_distances="true" zero_distance="60" gain="-12" occlusion="false">
        <wave name="song05"/>
    <sound name="song10" group="ambient_loop" has_custom_distances="true" zero_distance="60" gain="-12" occlusion="false">
        <wave name="song05"/>
    <sound name="song11" group="ambient_loop" has_custom_distances="true" zero_distance="60" gain="-12" occlusion="false">
        <wave name="song05"/>
    <sound name="radio" group="ambient_loop" has_custom_distances="true" zero_distance="60" loop="true" occlusion="false">
            <sound name="song01"/>
            <sound name="song02"/>
            <sound name="song03"/>
            <sound name="song04"/>
            <sound name="song05"/>
            <sound name="song06"/>
            <sound name="song07"/>
            <sound name="song08"/>
            <sound name="song09"/>
            <sound name="song10"/>
            <sound name="song11"/>

If you study the original radio_sound.xml file, or better yet the birds_sound.xml file, you will get a good idea of the possibilities with the *_sound.xml system. The birds_sound.xml is a great example of how sounds can be made more "alive" and not as repetitive, by chopping up the .wav files into short, short pieces and have the xml code piece it together in a random manner each time it is triggered, to make each bird call sound different from the other (or, rather, be a new combination of the same set of chopped up sounds). This is all possible with the help of "random pitch" attributes, sounds that randomize to

All set and done - now run the game and start a one player LAN server hosting the Shanty Town map, where there should be a radio in the Echo zone. Head there and listen to your playlist being heard from the radio. The muffle and echo effect added to the original sounds, to make it sound like the radio really is heard from inside a building, you have to add yourself with the help of a sound editing program, such as Sony Sound Forge.

Here is a list of some of the different attributes you can give a sound tag. To learn about more attibutes, browse the sound folders with Nemon's decompiler and just chek out what attributes are used in some of the *_sound.xml files. If you have questions, ask me here in the forum.

Sets the pitch of the sample, 1 unit = The step between a white key and the next black key on a piano. "12" is one octave up, "-12" is one octave down. Pitch can be set from -60 to 60. Pitch the original .wav file rather than using this attribute.

Random Pitch
Applies a random pitch value on top of the general pitch value. This means that if the general pitch value is set to "-10", and the random pitch is set to "2", the pitch will randomize between -12 and -8. I usually set general pitch to "0", and random pitch to no higher than 1, maybe 2.

Gain 0 is the loudest a sound should be played - if you push it above that (e.g. gain="10" you risk creating distortion - it's better to maximize the gain in the sound's .wav file.

Defines what group the sound belongs to, and inherits certain attributes from. Groups are edited in the data/sound/sound_settings.xml file.

Zero Distance
Defines the distance (in meters) at which the rolloff of the sample reaches inaudible value. In other word, it defines how far from the sound source the sound can be heard. Exlplosions should have a very high Zero Distance value, the buzz of a lamp should have a very low Zero Distance value.

Self describing. Default is no loop, so if you omitt the tag, the sound will not loop.

I extend this list as you come with questions about other attributes. Alright, let's immediately go on to the next tutorial!

The Seven Step Program to create an entirely new soundbank/wavebank setup

Now, if you want to have custom music for your own map, you can add that with the procedure described above, together with some additional attribute tweaking. In that case, you preferably don't want to mod the original radio sound/wavebanks, but rather add an entirely new soundbank and wavebank to the game - or you will have two layers of music playing simultaneously (both the original GRAW music, and your own custom music) in every SP map that has a radio. So, it's better to create your own, new soundbank and wavebank, and connect that to sound sources that are only in your own custom map. In this example we will create a soundbank/wavebank setup that plays a song from "The Rock - Original Motion Picture Soundtrack" on your level. Here's how:

1. Use Nemon's decompiler to open any wavebank, copy that data to your favourite text editor (which of course is UltraEdit) and save that as custom_music01_wave.xml in the local/english/sound/music/custom_music01 folder that you simultaneously create (always use numbers in the name of file types that you suspect you will create more of, hence the "01" in the file name - you might want to have another custom song for another custom map in the future).

2. Rip your copy of "The Rock - Original Motion Picture Soundtrack" (remember, illegal downloading is theft) and save the first track as therock_track01.wav in your newly created local/english/sound/music/custom_music01 folder. If you can, convert it to 22 kHz so that the file isn't such a chore for the computer to stream (we don't want a several minutes long song in the RAM).

3. Edit the custom_music01_wave.xml file so that it contains only the tag that "brings" your .wav file "into it". The "name" attribute should be whatever you want to call your wave bank (preferably a describing name and/or on that is easy to remember), I choose "custom_music01_wave". Also, the "dir" attribute should be the non-existing data folder that corresponds to your existing local/english/sound/music/custom_music01 folder - see below how it should look. Note that you don't need to create a dummy folder in the data/sound/.. folder of your GRAW installation - the game will realize anyway that the sound data isn't there, and look for it in the local/english/sound/.. folder instead.

 <?xml version="1.0" encoding="iso-8859-1"?> <wavebank name="custom_music01_wave" dir="data/sound/music/custom_music01" xmlns:xi="x">
    <wave name="custom_song01" file="therock_track01.wav" stream="true" />

4. Use Nemon's decompiler to browse through the sound folders and find a suitable soundbank - in my example I am only going to create a simple sound bank with only one cue playing only one music .wav file, so data/sound/music/menu_music/music_menu_sound.xml is a perfect .xml file to start from. Copy that data to your favourite text editor (which of course is UltraEdit) and save that as custom_music01_sound.xml in the local/english/sound/music/custom_music01/ folder where your custom_music01_wave.xml and therock_track01.wav file already lie.

5. Edit the newly created custom_music01_sound.xml file so that the default_wavebank attribute names your custom wave file (in my example "custom_music01_wave").

 <?xml version="1.0" encoding="iso-8859-1"?> <soundbank name="custom_music01_sound" default_wavebank="custom_music01_wave" xmlns:xi="x">
    <sound name="custom_music01" group="music" zero_distance="10.0" pitch="0" loop="true" positioning="2d" attenuation="none" occlusion="false" reference_distance="1.0">
        <wave name="custom_music01"/>

Look at the attributes of the sound tag above. It would have been nice if you could set the group attribute to "music", which would make it earn all attributes of that music group - mainly the connection to the "music volume" slider in the game's setup menu, and high priority (which is very high for music). However, I just now realized that it is not only an MP map's lack of event manager script that stops it from playing music - for some reason one of our programmers have set any cue with the group="music" attribute to mute on MP maps. I suggest you give your custom music cues the attribute group="ambient_loop", in which case it will at least get a very high priority - however, no one will be able to turn the music off, which kinda sucks! I'll see if this can be patched.

Furthermore, the zero_distance="10.0" attribute means nothing as attenuation is set to "none" - this means that the sound does not get weaker the farther the listener is from the sound source. Pitch is of course set to "0" as you want the music to be played in its original pitch.

The attribute "loop" is set to "true" because I want the .wav file to start over every time it reaches the end. If you're skilled you can edit the .wav file and make the end of the file blend perfeclty with the beginning of the file, making the music loop seamlessly, without ever going silent.

The "positioning" attribute is what makes this sound cue different from the sound cues of the radio cue we created in the first example: Now we're making a 2d cue, so that the music always is in the listeners ear, as opposed to being heard from a position in the world around him/her. Occlusion should be false so that EAX doesn't muffle the sound as soon as an occluder (static object or large dynamic object) comes between the listener and the sound source. You want that to happen if you're creating a yak sound cue to add atmosphere to your Himalayan MP map, but not for music - which is what I'm making in this example.

As no one will be able to turn the music off, make sure it isn't too loud and too much "in your face" (or maybe here it would be "in your ear"). Use the "gain" attribute (use: gain="-10") to do so. "0" is maximum volume, and -100 is the lowest (although the sound's volume has become so low it's inaudible much earlier than that, I'd guess at about -40).

6. Go into the editor, load the map where you want your custom sound, place a sound source where you want it. Iin my example we're adding a cue that plays music that is supposed to be heard all over the level, and takes no occluders or falloff into account, so it doesn't matter at all where we place that sound source. In the "cue" text box, write the name of your custom cue. For me, that's "custom_music01" (the "name" attribute of the sound in my cursom_music01_sound.xml file, see stage 5 of this tutorial).

7. Ok, we're almost there but not quite yet: As we are adding a new soundbank and wavebank as opposed to just modding existing ones, we need to let the game know what we have added. This is done in the sound_settings.xml file in the data/sound/ folder. In the "wavebanks" tag, duplicate any element and edit it to match the custom *_wave.xml file you want to add, and do the same for your *_sound.xml in the "soundbanks" tag. For me, I would have to add this line of code in the "wavebanks" tag:

<wavebank path="data\sound\music\custom_music01\custom_music01_wave.xml"/> well as add this line of code in the "soundbanks" tag:

<soundbank path="data\sound\music\custom_music01\custom_music01_sound.xml"/>

Now, run GRAW and start your custom level - and listen to the music.

Hope this helps.