Table of Contents
ArmA 2 Vehicle Sound Config Tutorial
ArmA 2 Forum, ArmA 2 Home, ArmA 2 Config, ArmA 2 File Formats, ArmA 2 Missions, ArmA 2 3D Modeling, ArmA 2 Scripting, ArmA 2 Terrain, ArmA 2 Texturing, ArmA 2 Tools
ArmA 2 Vehicle Sound Config Tutorial by Project Reality Mod
Introduction
Vehicles are complex sound making objects with many different sound layers working together, responding to different parameters, such as speed, engine revs, road surface etc. Our aim is to try and recreate this vibrant experience instead of settling for a simple pitched loop. This has been the approach BIS has largely taken too, although I intend to extend it. To begin with we need to understand the syntax and organization of the code we are dealing with. In every vehicle class we have a number of parameters relating to sound, we shall begin by describing a set which deal with the effect the vehicles has on incoming sound filtering and dampening.
Inside Sound Coeficient
Arma syntax:
insideSoundCoef = x ; // x E [0 , 1] values range between 0 and 1
This parameter controls how much the vehicle dampens the volume of incoming engine and movement sounds. Set to 1 the parameter provides no dampening of engine sounds and set to 0 it provides total dampening. In the video clip below we have it set to 1 in the first half and set to 0 in the second.
youtube 7ymOzrFifdY
The idea in the case of the Warrior is to simulate the volume dampening effect of the armour and the headphones worn, so we set it to around 0.6. This is subtle but gives leeway to allow for heavier dampening to be applied to more heavily armoured vehicles.
Occlude Sounds When In, Obstruct Sounds When In
Arma syntax:
occludeSoundsWhenIn = x ; // x values range between 0 and 1
obstructSoundsWhenIn = x ; // x values range between 0 and 1
The first parameter, occludeSoundsWhenIn, is a measure of how well sealed the vehicle is, and this effects direct and indirect paths of sound. The second parameter, obstructSoundsWhenIn, relates to how the direct sound path is affected by the obstruction of the vehicle, and leaves the echoes unfiltered. However I have to say that the difference between these two parameters is very difficult to discern. It may be because I have never managed to get reverb or echo effects from the engine, however as can be heard in the video below (the impact sounds in the video of the HE ammo are different and cycle, so unfortunately this may add a little confusion), there is a subtle difference between them, but I will leave this up to you the reader, to decide and experiment with. Worthy of noting is that the parameters effect both sound coming into the vehicle and sound coming out of the vehicle (the shell loading sounds can be heard in exterior view when the parameters are both set to 1, but not when they are lowered).
youtube TjW0-klUGS4
Other Filtering Parameters
There are a final few parameters to do with the filtering of sound which I have never had any effect from, so they may be set up dependent or they may be enabled in a future update to the engine. These are …
outsideSoundFilter obstructSoundLFRatio occludeSoundLFRatio
It would seem these parameters are to do with being able to alter how much the lower frequencies transmit through an object, and I would welcome any information on how they work.
Start, Stop, Get In, Get Out
Next in our list of parameters we have the sounds for the engine starting and stopping, both internally and externally, and the sounds for getting in and getting out.
soundGetIn[] = {"path\to\my\sound",0.562341,1 }; soundGetOut[] = {"path\to\my\sound",0.562341,1,60 };
The get in and get out sounds demonstrate a difference in the syntax of the internal and external sound data structures. The get in sound is an internal sound and has the syntax
soundGetIn[] = {"path\to\my\sound", relativeVol, pitch};
The path to sound is self explanatory, the relative volume is how loud this sound is in relation to other sounds , that is in a quiet environment relative volume levels greater than it this sound would be heard well and would dominate the mix, but in a loud environment with relative volume levels greater than it, it would be quieter than other sounds and may even be dropped if the simultaneous sample ceiling is arrived at. The pitch is a factor of the speed of the sample, so 1 is normal pitch , 0.5 would be half speed and an octave down and 2 would be double speed and an octave up. Best results are achieved with pitch settings between 0.6 and 1.5.
The external sound data structure has a slightly different syntax …
soundGetOut[] = {"path\to\my\sound", relativeVol, pitch, fadeDist};
It is the same as the internal sound except for the addition of a 4th parameter, fade distance. This is the distance over which the external sound will fade to nothing.
This basic sound data format is one found throughout the engine and vehicle sound configs, and it is repeated for our Engine Stop/Start Internal/External sounds.
soundEngineOnInt[] = {"path\to\my\sound ",1.000000,1.000000 }; soundEngineOnExt[] = {"path\to\my\sound ",2.511890,1.000000,500 }; soundEngineOffInt[] = {"path\to\my\sound ",1.000000,1.000000 }; soundEngineOffExt[] = {"path\to\my\sound ",1.258930,1.000000,500 };
These are self explanatory. The only thing to remember is that the engine initiates both the idle loop and the start sound simultaneously, and one plays over the other to start with. The start sounds is a one shot sound whereas the idle sounds loops. So the best results are achieved with a start sound that complements the idle loop and fades itself out.
Crash Sounds
The next set of sound data structures in our vehicle configs are the crash sounds. The basic format for these is one which is found elsewhere such as impact sounds in ammo configs, and has a basic structure which consists of a set of related sound samples which are played back randomly.
An example of the format is …
soundCrash0[] = {"path\to\my\sound", relativeVolume, pitch, fadeDistance }; soundCrash1[] = {" path\to\my\sound ", relativeVolume, pitch, fadeDistance }; soundCrash2[] = {" path\to\my\sound ", relativeVolume, pitch, fadeDistance }; soundCrash3[] = {" path\to\my\sound ", relativeVolume, pitch, fadeDistance }; soundsCrash[] = {"soundCrash0",0.25,"soundCrash1",0.25,"soundCrash2",0.25,"soundCrash3",0.25};
The format for the sound references is one which we are familiar with by now, common for external sounds. The array at the bottom though is new. What happens here is that our previously declared four sound references are now placed in a new 'master' array, along with a floating point number which represents the probability that sound will be played. In this case 0.25 means that each sound will have a 25% chance that it will play back. The values should all be a floating point fraction of 1 and the total values in the array should add up to 1 (think of it as 100% / 100).
One thing to note about the random playback of sounds, is that unless the present sound in the array has finished playing, then retriggering will merely trigger that same sound again, and not select a new one through the random process. What this means is that if you have long sound files, then you may not experience randomness if the sound file gets triggered rapidly. There seem to be 3 main classes of vehicle collision sounds and they are (categories are self explanatory).
soundBuildingCrash[] soundWoodCrash[] soundArmorCrash[]
Sound Events Class
The sound events class contains inner classes that relate to sounds that are triggered by events in the vehicle. At the moment in BIS files this is solely used for acceleration sounds which are triggered according to an expression parameter, however I do wonder if this class may be used for other 'triggered' sounds. This may be a subject of later exploration.
The present syntax for the acceleration sound events is as follows.
class AccelerationIn { sound[] = {"path\to\my\sound",relativeVolume, pitch }; limit = 0.150000; expression = "engineOn*(1-camPos) * 3 * gmeterZ*((speed factor[1.5, 15]) min (speed factor[15, 1.5]))"; }; class AccelerationOut { sound[] = {"path\to\my\sound",relativeVolume, pitch, fadeDistance }; limit = 0.150000; expression = "engineOn*camPos * 3 * gmeterZ*((speed factor[1.5, 15]) min (speed factor[15, 1.5]))"; };
The sound[] array is fairly self explanatory, as we have covered these parameters earlier, the only thing to notice is that the inside acceleration sound does not have a fade over distance parameter (as you would expect, as it's the sound heard internally from a 1st person perspective).
Next we have this variable called 'limit'. I have to say that I am unsure what exactly this refers to or how it exactly works, but I have a rough idea. It appears to place a limitation on how often or frequently the sound will trigger, the lower this value the more often the sound will happen. The BIS setting of 0.15 seems to be a reasonably good one, this can be lowered or raised slightly (and here we are talking by +/- 0.05 → 0.1 ) to suit a particular vehicle.
The final variable is 'expression'. This controls the volume of the sound, and consists of a number of 1-0 variables (these are variables that take either 1 or 0, and in a mathematical expression that involves multiplication when they take a value of 0 the whole expression takes a value of 0), combined with a range value and sometimes a scalar. You will notice that the outside expression has 'camPos' and the inside expression has '(1 - camPos)'. When the internal view is active, camPos = 0, and when the external view is active camPos = 1. We also have engineOn as a parameter in both, in other words if the engine is off the value will be 0 and the sound will never play.
The 'gmeterZ' parameter is tied to an animation source of the vehicle. Different vehicles have different animation sources (and this topic is beyond the scope of a sound tutorial), and these values can be used by the sound classes to effect the volume or expression of a sound. In this case 'gmeterZ' refers to the g-forces, which is essentially acceleration (in a land vehicle). So this means that the greater the G-Force the greater the acceleration sound.
A list of all the animation sources in the arma engine can be found on this page here …
Model Config - Bohemia Interactive Community
Our final expression value is based around the vehicle speed (in meters per second, NOT kilometers an hour which is what the speed readout in game shows. 1km/hr = 0.27 m/s, 1 m/s = 3.6km/hr). We also have a function happening here, activated by the key word 'factor'. What this does is (in the example above) , is to set the value to 0 when speed is 1.5 m/s and the value to 1 when speed is 15 m/s, and then scales the values between 0 and 1. We also have a repetition of the factoring, but the opposite way around, and linked to our first factor by the keyword 'min'. What this does is set our next factoring to be 0 at 15m/s and 1 at 1.5 m/s, and then takes the minimum value between this and the previous one. So we end up with a value which is 0 at 1.5 m/s and 0 at 15 m/s and about 0.5 at around 7 m/s. I will explain this process in more detail in the wheeled vehicle tutorial. This way we tune the speed area that an acceleration sound will play in.
Sound Class
Last but not least, we come to the main sound class of the vehicle configs. This is where the engine and movement sounds of the vehicle are dealt with. Inside this class we have two sets of sounds, one for the internal sounds and one for the external sounds. The main categories of sounds found in here are as follows …
class Engine { sound[] = {"path/to/my/sound ",relVolume, pitch, fadeDistance }; frequency = "( randomizer*0.05 + 0.95 )*rpm"; volume = "engineOn*camPos*(rpm factor[0.25, 0.95])"; };
This is the main class for the external engine sound. We start with a sound data reference whose format we are familiar with, then we have a new parameter frequency.
Frequency will take a floating point number value, and this multiplier will affect the pitch (or speed) of the sound file. Inside the quotation marks we have a mathematical expression which will resolve to this floating point value. The keyword “randomizer” creates a random floating point value between 0 and 1, and this is then multiplied (scaled) by 0.05 and added to 0.95 … giving a ranged value between [ 0.95, 1.00]. However this randomizer value is only resolved once at the object instantiation, so what this means is this random effect is applied differently to different vehicles meaning that no two should have their engine sounds at quite the same pitch. This will reduce the incidence of 'phasing' when many vehicles are together. Finally our slightly random pitch is multiplied by rpm, this is revolutions per minute and is the rotational speed of the engine. Its pretty much the base sound of a vehicle and the gears will range through this as speed increases.
The third parameter is volume. This is controlled in a similar fashion to the acceleration expression, with a set of 1-0 variables. The first “engineOn” is 1 when the engine is on, meaning when the engine is off the sound will not play … which is what we want ! The next variable camPos we have come across before and it plays the same roll. This variable is set to 1 on an external view and so this variable sets our sound to be an external one.
Finally we have the keyword rpm with a factor expression. What this does is set expression evaluation to 0 when rpm is the first value in the factor expression and 1 when rpm is the second value in the factor expression. So in our case volume is 0 when rpm has a value of 0.25 or lower and 1 when it has a value of 0.95 or higher and it will scale the values in between.
So why does our engine volume start off at 0 ? Well that is because we have an idle loop that plays and as that fades out, this fades in.
class IdleOut { sound[] = {"path/to/my/sound ",relVolume, pitch, fadeDistance }; frequency = "1"; volume = "engineOn*camPos*(rpm factor[0.4, 0.15])"; };
Our Idle loop is of an identical format to the main engine loop, except the frequency is set to 1 (as the engine is not moving the vehicle), and the factor expression in the volume parameter has the highest value first. This does what you would expect it too, it means that at a rpm value of 0.4 or higher the expression evaluates to 0, and at a rpm value of 0.15 or lower the expression evaluates to 1. The values scale in between.
So this is how our engine loop fades in out of the idle loop.
There are a couple more sound categories controlled by different params. The first is the “noise” loop.
class NoiseOut { sound[] = {"path/to/my/sound ",relVolume, pitch, fadeDistance }; frequency = "1"; volume = "camPos*(angVelocity max 0.04)*(speed factor[4, 15])"; };
The volume parameters here has new keyword “angVelocity” and a new factor expression of “speed”. angVelocity is angular velocity and refers to the 'yaw' of the vehicle, or how fast its rotating in the x-y plane. This can be used to raise the volume of a noise loop, simulating things rolling around or banging inside the vehicle. The max keyword here caps the value so it cannot get too high. The speed factor ramps up the volume as the speed increases.
Finally we have a set of parameters which differ on tracked and wheeled vehicles, for the contact sounds of the tracks or wheels with different ground surfaces. I will deal with these and much more in later tutorials. All these parameters are now repeated for internal sounds in the vehicle, and once again it?s the “camPos” variable (set to (1-camPos) ) which controls this aspect of hearing the sound. The only difference in the internal syntax is the fadeDistance is omitted from the sound data structure.
And that brings us to the end of the introduction into vehicle sound configs.
Source realitymod.com