SSC - Sound Scripting | An elaborate explanation

Lots of cool and useful tips to mod either serverside or clientside
Post Reply
User avatar
Senshi
Posts: 697
Joined: Sun Oct 18, 2009 1:14 pm
Location: Germany
Contact:

SSC - Sound Scripting | An elaborate explanation

Post by Senshi »

Original by Kerfuffle over here: http://bfmods.com/viewtopic.php?f=6&t=1148&p=8484#p8465
All credits for finding this awesome piece of intel go to him. Sadly he didn't state if he is the original creator as well, so I cannot credit that here.

I just made it fancier and easier to read (BBCode).


HOW TO ADD A NEW SOUNDSCRIPTS INTO BATTLEFIELD: 1942

Overview of a typical soundscript

Below is an example soundscript, in a very small font. We will go over the various codes and sections in chapters to follow. For now, examine the following code and orient yourself to the general layout.

>>When someone is in the driver seat, this sound is played.
** Sound pathname with relative references for mod name and sound quality

Code: Select all

newPatch
####################
### Engine Start ###
####################
load @ROOT/Sound/@RTD/DesertCombat/Humvee/Humvee_Start.wav
minDistance 1
dopplerOff
priority -2
*** Distance Volume ***
beginEffect
controlDestination Volume
controlSource Distance
envelope Ramp
param 50
param 100
param 1
param -1 
endEffect

>> Sound played at low engine output.

Code: Select all

##############
### Lo RPM ###
##############
load @ROOT/Sound/@RTD/DesertCombat/Humvee/Humvee_Low.wav
loop
volume 1
minDistance 2 ** Sound begins fading naturally 2m from source.
relativePosition 0/0/0
priority 8
*** Engine start ***
beginEffect
controlDestination Volume
controlSource Time
envelope Ramp
param 0.2
param 0.8 ** Sound fades from silence to full volume between 0.2 and 0.8 seconds after engine start.
param 0
param 1
endEffect

*** Engine Pitch ***
beginEffect
controlDestination Pitch
controlSource Default
envelope Linear
param 0.9
param 0.8
endEffect
*** Distance Volume ***
beginEffect
controlDestination Volume
controlSource Distance
envelope Ramp
param 15
param 65
param 1
param -1 
endEffect
*** Engine Volume ***
beginEffect
controlDestination Volume
controlSource Default
envelope Ramp
param 0
param .9
param 1
param -1
endEffect

*** Engine stop ***
beginEffect
controlDestination Volume
controlSource TimeRelease
envelope Ramp
param 0
param 0.2 ** Sound fades so silence and terminates 0.2 seconds after after engine stops.
param 1
param -1 
endEffect
>>Sound played after engine picks up speed.

Code: Select all

################
### Hi RPM 1 ###
################
load @ROOT/Sound/@RTD/DesertCombat/Humvee/Humvee_Medium.wav
loop
minDistance 8
relativePosition 0/0/0 ** Sound origin is centered on vehicle. Values are x/y/z.
priority 8
*** Engine start ***
beginEffect
controlDestination Volume
controlSource Time
envelope Ramp
param 0.2
param 0.8
param 0
param 1
endEffect
*** Engine Pitch ***
beginEffect
controlDestination Pitch **Sound pitch is set relative to vehicle speed.
controlSource Speed
envelope Linear
param 0.4
param 0.01
endEffect
*** Distance Volume ***
beginEffect
controlDestination Volume
controlSource Distance
envelope Ramp
param 25
param 150 **Volume ramp that fades sound from full to zero between 25 and 150m.
param 1
param -1 
endEffect
*** Engine Volume ***
beginEffect
controlDestination Volume
controlSource Default
envelope Ramp
param 0
param .2
param 0
param 1
endEffect

*** Engine stop ***
beginEffect
controlDestination Volume
controlSource TimeRelease
envelope Ramp
param 0
param 0.2
param 1
param -1 
endEffect

>>Sound played while engine is at high output.
>>This is a short range sound that only modifies the current engine sound playing in HiRPM1.

Code: Select all

################
### Hi RPM 2 ###
################
load @ROOT/Sound/@RTD/DesertCombat/Humvee/Humvee_High.wav
volume 1
loop **Chosen .wav will loop forever until terminated
minDistance 2
relativePosition 0/0/0
priority 8 **On a scale of –10 to 10, this sound has a priority of 8 when competing for sound channel use with other overlapping sounds.
*** Engine start ***
beginEffect
controlDestination Volume
controlSource Time
envelope Ramp
param 0.2
param 0.8
param 0
param 1
endEffect

*** Engine Pitch ***
beginEffect
controlDestination Pitch
controlSource Default
envelope Linear
param 0.75
param 0.25
endEffect

*** Distance Volume ***
beginEffect
controlDestination Volume
controlSource Distance
envelope Ramp
param 25
param 65
param 1
param -1 
endEffect

*** Engine Volume ***
beginEffect
controlDestination Volume
controlSource Default
envelope Ramp
param 0
param .5 **Engine sound is silent at engine idle and fades to full volume when engine output is at 50%.
param 0
param 1
endEffect

*** Engine stop ***
beginEffect
controlDestination Volume
controlSource TimeRelease
envelope Ramp
param 0
param 0.2
param 1
param -1 
endEffect
>>Sound played while engine is idling.

Code: Select all

############
### Idle ###
############
load @ROOT/Sound/@RTD/DesertCombat/Humvee/Humvee_Idle.wav
loop
minDistance 2
relativePosition 0/0/0
priority 8
*** Engine start ***
beginEffect
controlDestination Volume
controlSource Time
envelope Ramp
param 0.2
param 0.8
param 0
param 1
endEffect

*** Engine Pitch ***
beginEffect
controlDestination Pitch
controlSource Default
envelope Ramp
param 0
param 0.25
param 1
param 0.2
endEffect

*** Engine Volume ***
beginEffect
controlDestination Volume
controlSource Default
envelope Ramp
param 0
param 0.9
param 1
param -1 ** Idle sound begins at full volume and fades to silence as engine approaches 90% output.
endEffect
*** Distance Volume ***
beginEffect
controlDestination Volume
controlSource Distance
envelope Ramp
param 5
param 50
param 1
param -1 
endEffect

*** Engine stop ***
beginEffect
controlDestination Volume
controlSource TimeRelease
envelope Ramp
param 0
param 0.2
param 1
param -1 
endEffect
>>Sound played when drivers seat is abandoned.

Code: Select all

###################
### Engine Stop ###
###################
load @ROOT/Sound/@RTD/DesertCombat/Humvee/Humvee_Stop.wav
minDistance 2
trigger Release **Sound waits to be played until the vehicle is “released”
dopplerOff
priority -2
*** Distance Volume ***
beginEffect
controlDestination Volume
controlSource Distance
envelope Ramp
param 50
param 100
param 1
param -1 
endEffect
Soundscript Titles

Consider the following code:

Code: Select all

###################
### Engine Stop ###
###################
load @ROOT/Sound/@RTD/DesertCombat/Humvee/Humvee_Stop.wav
minDistance 2
The area set in ### is a soundscript title. They are used throughout the soundscript to identify the sections both to the scripter and to the engine itself.

My suggestion is to start with a soundscript from the original BF1942 files and work from there. Use only titles defined in those soundscripts. As we will see later, there is a way to add comments to your soundscripts, which will never interfere with the flow or function of the script. So in my experience it is best to consider soundscript titles a necessary evil. Just use them as they appear in the original files and use your own comments to label the sections as you need.
Soundscript structure
As you can see from the example soundscript above, there is a specific structure that is usually adhered to. A soundscript section will always be initiated by the declaration of a sound, using the load command. If it is an entirely new section, the command newPatch preceeds the load command. Then, sound parameters follow, such as the declaration of loops, stereo, and volume properties. Finally, adjustment ramps are declared, which modify the sound further in accordance to the behavior of the vehicle.

Soundscript structure and parameters

Here is an example layout of a soundscript section:
- NewPatch
- Load the .wav using the proper path
- Declarations section. Define the priority, master volume, looping, stereo, etc.
- Adjustment ramps. Apply adjustments to pitch and volume according to time, vehicle speed, engine rpms, distance, etc.

You will notice in the example soundscript provided at the beginning, that there can be several sounds loaded under one newPatch command. Keep in mind that newPatch is used to speak to the soundscript interpreter, and defines the functional sections of the soundscript. It separates out a reload section from a firing section, for instance.

Loading a sound also has a functional action, and all commands that follow the loading of a sound are applied to that sound only. Remember that newPatch separates different functional sections within a soundscript, so you may load several sounds within a newPatch section. There is no known limit to the number of sounds you may load for each section.

There is no set rule as to where commands such as stereo, loop, mindistance, etc. must be stated following the load command. For organization’s sake, they are usually all declared immediately following the use of the load command.

As a final note, the location of soundscript sections, separated by newPatch commands, does not seem to be pre-ordained. You should have freedom over placement of the primary soundscript sections. However, it is usually wise to copycat original BF1942 soundscript structure.
Soundscript commands

newPatch Using this command alerts the script interpreter that a new sound section has begun. Use of this command is more important for some sounds than others. For some soundscripts, using many newPatch commands to separate out sections is essential. For others, there is only a need for one of these commands. You need not declare a newPatch for every sound that you load. If you want sounds to be played simultaneously or sequentially, you will usually group them together under one newPatch. The command newPatch is only used to communicate with the interpreter, so it may recognize different sections of the soundscript.

load <path>: The load command calls forth a sound to be played from a given path. Once a sound is loaded, all code that follows will affect that sound, until another load command is issued. The load command can use relative pathnames to automatically pick from a certain path. Here are some examples:
@Root:The root directory of the current mod
@RTD: The sound quality chosen by the player
@Language: The language chosen by the player

stereo: If the sound you are going to use is in stereo, you must alert the script of this. Use of stereo sounds negates any directional quality of the sound. If you are in range to hear it, the sound will always sound as though it occurred at your position.

minDistance <#>: Mindistance is a greatly speculated upon and misunderstood command. In my experience, mindistance is the distance at which the sound begins to naturally lose volume. If you use no volume commands on your sound, the game will still cause it to lose volume over distance. Setting a high mindistance increases the radius at which the sound will maintain high volume on its own.

dopplerOff: Doppler is the raising / lowering of pitch according to the speed at which an object is approaching / departing. The engine assumes that doppler is active unless you deactivate it through use of this command.

priority <#>: Depending on your sound card, you can only have 32-64 sounds playing at one time. In the middle of a firefight there are definitely more sounds being called for than the sound card can handle. Therefore priorities must be set as to which sounds will be heard while others are not. All overlapping sounds are in constant competition for being heard. You assign every sound a priority number ranging from –10 to 10, 10 being highest. There is a priority 11 but that is reserved only for radio commands. Good decisions made on sound priorities are essential for an effective sound environment.
loop: If you want your sound to be played on an infinite loop, you will want to add this command. You can still control the audibility of the sound using other commands and especially with volume ramps and time delays. There is no command to loop a sound a selected number of times. However, with smart use of time / volume parameters you can still have good control over how a sound is played.

relativePosition <x/y/z>: You can define where on the vehicle the sound will originate from. The format of the position is x/y/z (left/right, above/below, forwards/backwards). Care must be taken in the positioning of the sound, as a soundscript is often called from a specific component of the vehicle and not the vehicle itself. For example, a jet engine soundscript is called from the engine, and therefore a position of 0/0/0 will place the sound origin on the center of the engine object.

volume <#>: You may set the sound’s master volume peak directly using this command. The volume value ranges from zero (silent) to one (full volume). All further volume adjustments to the sound will be made relative to the master volume adjustment. So, for example, if a sound’s master volume is set to 0.5, and then is later modified to fade to 0.5 volume in a volume ramp, the end volume will be 0.25.

randomStartPitch<min/max>: With this command, you may set the sound to be played at a randomly selected pitch every time it is used. The first parameter is the minimum pitch value, the second is the maximum pitch value. It is difficult to explain the mathematics of the pitch parameters, as each follows its own set of rules. But as an example: randomStartPitch 0.75 / 0.25 sets a pitch range from 0.75 of the normal pitch to 1.25 of the normal pitch. The first is a raw factor to be multiplied, the second is to be added to 1 and then multiplied.

stop finishSample: This command is only used in conjunction with looping sounds. It tells the sound to play through the .wav completely before ending, even if the sound source ceases its activity. This is commonly used in automatic firearms so that quick taps of the trigger do not cause “half-shots” to be heard.
randomPlay: This command requires the use of newPatch and at least two loaded sounds. It allows the section to randomly pick between all sounds within.

triggerVolume: This command is only used in conjunction with a time-volume ramp. It prevents a sound from being played immediately upon the execution of a soundscript. Instead, the sound is begun at the defined moment the time-volume ramp is set to raise its volume above zero. If you did not use the triggerVolume command in a time-volume ramp, the sound would begin the moment the soundscript is run, regardless of when it is meant to be played. You would end up with the sound volume being raised from zero in the middle of a playing sound, which in most cases is undesirable.

#include: This command is used to load another soundscript, which is run in parallel with the current script. It’s a great way to save time and effort when multiple soundscripts will be expected to contain identical sections. It also allows for the execution of special soundscript commands that do not work well together. Here is an example of the #include command used for ejected shell cases:

Code: Select all

####################
### Shell Bounce ###
####################
newPatch
#include ../../../Common/Sounds/ShellBounce.ssc
***: Use three subsequent asterisks to begin a comment. These are ignored by the interpreter and are a great way to organize your soundscripts.
Ramps:
Ramps are methods of controlling a sound’s properties in accordance to a specified control entity. You can adjust a sound’s pitch according to the speed of the vehicle, for instance. Or adjust a sound’s volume according to the observer’s distance. Some ramp controls are set and unchanging. Others are dynamic and vary according to vehicle performance or other conditions.
A ramp definition consists of a parameter definition and a parameter set. Consider the following code excerpt:

Code: Select all

*** Start Distance Volume ***
beginEffect
controlDestination Volume
controlSource Distance
envelope Ramp
param 50
param 100
param 0
param 1
endEffect
- Parameter definition: In this area, you specify the source of control and the method of sound adjustment according to that control. In this excerpt you can see the source of control is Distance, which is the method of adjustment for the destination Volume. So as distance changes, volume changes accordingly. Below this section is the parameter set, which defines two points where the control source and control destination coincide. An adjustment ramp is then created using these points as a reference.
- Parameter set: In this area, you specify two points at which you will define the exact values for the control source and control destination. The order of the parameters is:

Param1 : control source point 1
Param2 : control source point 2
Param3 : control destination point 1
Param4 : control destination point 2

So verbally, the code excerpt is saying: at 50m the sound volume is zero, at 100m the sound volume is 1 (full volume).

Using this information, the soundscript creates an adjustment ramp to modify the sound according to its parameters. For points outside of the parameter set, the points assume the last stated value in the parameter set. In other words, the angle of the ramp does not continue beyond the defined start and end points, but rather maintains the same value as the end points. So, in this example, an observer closer than 50m to the sound origin will experience a zero volume level, and an observer beyond 100m will experience a full volume level. The ramp angle does not continue, but rather remains level according to the last stated value in the parameter set.

Now consider the next set of code which immediately follows the above code:

Code: Select all

*** Distance Volume ***
beginEffect
controlDestination Volume
controlSource Distance
envelope Ramp
param 200
param 300
param 1
param -1
endEffect
This ramp continues full folume out to 200m. Then, the volume diminishes to zero at 300m. Note the use of –1 instead of zero to end the sound. This is called terminating the sound. It tells the sound engine that no sound will occur outside of the designated range. This is different than telling the engine that volume is zero beyond the designated range. Without terminating the sound, it will continue to infinity and occupy sound channels throughout the map.
IMPORTANT NOTE: You must terminate all sounds. Failure to do this will result in loss of available sound channels across the map. If enough active sounds are not given termination commands, you will experience massive loss of sound channels in-game.

Here is a description of the many sound ramps that occur in BF1942. This is just a sampling of the more common ramp codes. Others may exist and it seems that many in-game variables may be used to control a ramp.
Time delay:

Code: Select all

*** Time Volume ***
beginEffect
controlDestination Volume
controlSource Time
envelope Ramp
param 0.77
param 0.77
param 0
param 1 
endEffect
trigger Volume
This ramp is used when a sound should not be played until a designated amount of time has passed. In this example, the sound will be played 0.77 seconds after the sound triggering event has occurred.

Note the use of trigger Volume immediately after the ramp. This command is used in conjunction with time delay ramps. It forces the sound to start when the given time has passed, instead of letting the sound start immediately. If this ramp was missing the trigger Volume command, you would not hear the sound from the beginning, but rather from the 0.77 second mark of the .wav. This command will almost always be used in a time delay ramp.

Engine activity volume ramp:

Code: Select all

*** Engine Volume ***
beginEffect
controlDestination Volume
controlSource Default
envelope Ramp
param 0
param 0.75
param 0.25
param 1
endEffect 
This ramp is used when a sound should be louder / quieter according to a vehicle’s engine performance. Many vehicle soundscripts use an array of sounds with such volume ramps, each sound crossfading with another as the engine power picks up.

Note the controlSource is listed as Default. While there is no absolute documentation on the exact meaning of Default, it seems to be a combination of engine RPM and vehicle speed. The range is from 0 (an idle vehicle) to 1 (a vehicle at maximum power and speed).

This specific ramp tells the sound to play at 25% when the vehicle is stopped, and increase to full volume when the vehicle engine reaches 75% of it’s full power.

Engine RPM pitch ramp:

Code: Select all

*** Engine Pitch ***
beginEffect
controlDestination Pitch
controlSource Extern #map<Engine::Rpm>
envelope Ramp
param .2
param .6
param 0.70
param 0.30
endEffect 
This ramp is used primarily for aircraft to increase / decrease a sound’s pitch according to engine RPM. This ramp is commonly used to adjust an aircraft engine’s pitch as the pilot increases throttle.
Note the controlSource is listed as Extern #map<Engine::Rpm>. This control source is a variable taken directly from the vehicle’s engine properties. It ranges from 0 (at zero throttle) to 1 (full throttle).

Pitch ramps have parameters that are a bit difficult to interpret. The two parameters are offsets from the standard value of 1 (which is normal pitch). It is best to think of the pitch parameters graphically, as they make little sense mathematically. Let me demonstrate:

This particular ramp is set to param3: 0.7 and param4: 0.3. This means that when the vehicle is at .2 throttle, the pitch will be at 70% of normal. When the vehicle is at .6 throttle, the pitch will be at 130% of normal. Parameter 3 is the actual multiplier of the pitch when the control source is at parameter 1. Parameter 4 is the multiplier above normal pitch when the control source is at parameter 2. So you would consider a parameter 4 value of 0.3 to mean the pitch is multiplied by 1.3.

Soundscript tips
Here are some important soundscripting tips to bear in mind.
- All soundscript commands are CASE SENSITIVE! Never forget this. Sound paths need not be in the proper case. Everything else in your soundscript must be properly capitalized.
- Priority is god in soundscripting. Reserve high priorities for sounds that should always be heard over others. Do not let distant sounds have high priorities. Break up a sound into several different priorities according to distance.
- As mentioned before, always terminate your sounds. Doublecheck your soundscript for termination errors before deeming it complete.
- Stereo sounds have their use, but they are of limited worthiness. The best time to use a stereo sound is when you want to ensure a sound is always centered on the player’s ears. They are used for 1st person view in many weapons for this reason, to disregard slight variance in positioning. Don’t forget that a stereo sound is twice the file size as a mono. Use them sparingly.
- If two of the same sound overlap, they will cause a phaser effect that is usually unwanted. Keep in mind all the sound radii for each .wav, and try to avoid overlapping the same .wav. For some vehicles, the phaser effect is desirable. Multiple propeller planes fall into this category.
- Remember that mindistance has its own inherit volume / distance ramp that you have no control over. If your sound is too quiet at a distance, even if your volume ramp is not set to reduce volume, consider increasing the mindistance value.
- A soundscripter is always dependant on the coder to include his soundscripts in the object he is preparing his scripts for. Work with the coder to determine what components of a vehicle need a soundscript attached to them.
- Be wary of multiple engined vehicles if you only want a single soundscript to handle the engine sound. The coder must ensure only one soundscript is called for.
- If you want a sound to follow a projectile, you will call for a soundscript in the projectile’s physics.con file. Looping sounds behave better for projectiles. Even if a sound is long and will not loop properly, still set it to loop. Otherwise the soundscript distance properties will only be calculated once and not be updated as the projectile moves. If a sound does not loop well and you want to deactivate it as soon as it reaches the end of the .wav, use a time / volume ramp to terminate it.
- For vehicle engines, consider using a single engine sound set for a broad pitch range depending on the engine power. Then overlay several smaller looping sounds that activate at different RPM levels. You can conserve considerable file size by using this method. Reserve a unique sound for engine idle.
exe
Posts: 60
Joined: Wed Feb 08, 2012 10:04 pm

Re: SSC - Sound Scripting | An elaborate explanation

Post by exe »

This is such a great and helpful tutorial, strange how Kerfuffle made only one post in this forum. :?

Anyway my question is: Does anyone know which priority the game uses if it's not set for a sound?
exe
Posts: 60
Joined: Wed Feb 08, 2012 10:04 pm

Re: SSC - Sound Scripting | An elaborate explanation

Post by exe »

Senshi wrote:[...]
randomStartPitch<min/max>: With this command, you may set the sound to be played at a randomly selected pitch every time it is used. The first parameter is the minimum pitch value, the second is the maximum pitch value. It is difficult to explain the mathematics of the pitch parameters, as each follows its own set of rules. But as an example: randomStartPitch 0.75 / 0.25 sets a pitch range from 0.75 of the normal pitch to 1.25 of the normal pitch. The first is a raw factor to be multiplied, the second is to be added to 1 and then multiplied.
[...]
That part is not 100% true, if you use randomStartPitch 0.75 / 0.25 that means your pitch will be between 0.25 and 1.25. From default "1" the minimum of the pitch range is created by subtracting the first number, maximum by adding the second.
User avatar
Swaffy
Posts: 1715
Joined: Sun Aug 29, 2010 9:25 pm
Location: Cibolo, Texas

Re: SSC - Sound Scripting | An elaborate explanation

Post by Swaffy »

exe wrote:
Senshi wrote:[...]
randomStartPitch<min/max>: With this command, you may set the sound to be played at a randomly selected pitch every time it is used. The first parameter is the minimum pitch value, the second is the maximum pitch value. It is difficult to explain the mathematics of the pitch parameters, as each follows its own set of rules. But as an example: randomStartPitch 0.75 / 0.25 sets a pitch range from 0.75 of the normal pitch to 1.25 of the normal pitch. The first is a raw factor to be multiplied, the second is to be added to 1 and then multiplied.
[...]
That part is not 100% true, if you use randomStartPitch 0.75 / 0.25 that means your pitch will be between 0.25 and 1.25. From default "1" the minimum of the pitch range is created by subtracting the first number, maximum by adding the second.
This makes more sense. I'ev been curious about this for a long time, I always just did "randomStartPitch 0 / 0" on the code. XD
Instead of removing the line like I should...
(Forum Thread|Download) Swaffy'sMod v0.34 | Download link to come Soon™
Post Reply