/////////
// SoundController.js
//
// This script controls the sound for a car. It automatically creates the needed AudioSources, and ensures
// that only a certain number of sound are played at any time, by limiting the number of OneShot
// audio clip that can be played at any time. This is to ensure that it does not play more sounds than Unity
// can handle.
// The script handles the sound for the engine, both idle and running, gearshifts, skidding and crashing.
// PlayOneShot is used for the non-looping sounds are needed. A separate AudioSource is create for the OneShot
// AudioClips, since the should not be affected by the pitch-changes applied to other AudioSources.
var listener : GameObject;
private var car : Car;
var D : AudioClip = null;
var DVolume : float = 1.0;
var E : AudioClip = null;
var EVolume : float = 1.0;
var F : AudioClip = null;
var FVolume : float = 1.0;
var K : AudioClip = null;
var KVolume : float = 1.0;
var L : AudioClip = null;
var LVolume : float = 1.0;
var wind : AudioClip = null;
var windVolume : float = 1.0;
var tunnelSound : AudioClip = null;
var tunnelVolume : float = 1.0;
var crashLowSpeedSound : AudioClip = null;
var crashLowVolume : float = 1.0;
var crashHighSpeedSound : AudioClip = null;
var crashHighVolume : float = 1.0;
var skidSound : AudioClip = null;
var BackgroundMusic : AudioClip = null;
var BackgroundMusicVolume : float = 0.6;
private var DAudio : AudioSource = null;
private var EAudio : AudioSource = null;
private var FAudio : AudioSource = null;
private var KAudio : AudioSource = null;
private var LAudio : AudioSource = null;
private var tunnelAudio : AudioSource = null;
private var windAudio : AudioSource = null;
private var skidAudio : AudioSource = null;
private var carAudio : AudioSource = null;
private var backgroundMusic : AudioSource = null;
private var carMaxSpeed : float = 55.0;
private var gearShiftTime : float = 0.1;
private var shiftingGear : boolean = false;
private var gearShiftsStarted : int = 0;
private var crashesStarted : int = 0;
private var crashTime : float = 0.2;
private var oneShotLimit : int = 8;
private var idleFadeStartSpeed : float = 3.0;
private var idleFadeStopSpeed : float = 10.0;
private var idleFadeSpeedDiff : float = 7.0;
private var speedFadeStartSpeed : float = 0.0;
private var speedFadeStopSpeed : float = 8.0;
private var speedFadeSpeedDiff : float = 8.0;
private var soundsSet : boolean = false;
private var inputFactor : float = 0;
private var gear : int = 0;
private var topGear : int = 6;
private var idlePitch : float = 0.7;
private var startPitch : float = 0.85;
private var lowPitch : float = 1.17;
private var medPitch : float = 1.25;
private var highPitchFirst : float = 1.65;
private var highPitchSecond : float = 1.76;
private var highPitchThird : float = 1.80;
private var highPitchFourth : float = 1.86;
private var shiftPitch : float = 1.44;
private var prevPitchFactor : float = 0;
// Create the needed AudioSources
function Awake()
{
car = transform.GetComponent(Car);
DVolume *= 0.2;
EVolume *= 0.2;
FVolume *= 0.2;
KVolume *= 0.5;
LVolume *= 0.2;
windVolume *= 0.2;
DAudio = listener.AddComponent(AudioSource);
DAudio.loop = true;
DAudio.playOnAwake = true;
DAudio.clip = D;
DAudio.volume = DVolume;
EAudio = listener.AddComponent(AudioSource);
EAudio.loop = true;
EAudio.playOnAwake = true;
EAudio.clip = E;
EAudio.volume = EVolume;
FAudio = listener.AddComponent(AudioSource);
FAudio.loop = true;
FAudio.playOnAwake = true;
FAudio.clip = F;
FAudio.volume = FVolume;
KAudio = listener.AddComponent(AudioSource);
KAudio.loop = true;
KAudio.playOnAwake = true;
KAudio.clip = K;
KAudio.volume = KVolume;
LAudio = listener.AddComponent(AudioSource);
LAudio.loop = true;
LAudio.playOnAwake = true;
LAudio.clip = L;
LAudio.volume = LVolume;
windAudio = listener.AddComponent(AudioSource);
windAudio.loop = true;
windAudio.playOnAwake = true;
windAudio.clip = wind;
windAudio.volume = windVolume;
tunnelAudio = listener.AddComponent(AudioSource);
tunnelAudio.loop = true;
tunnelAudio.playOnAwake = false;
tunnelAudio.clip = tunnelSound;
// tunnelAudio.maxVolume = tunnelVolume;
tunnelAudio.volume = tunnelVolume;
skidAudio = listener.AddComponent(AudioSource);
skidAudio.loop = true;
skidAudio.playOnAwake = true;
skidAudio.clip = skidSound;
skidAudio.volume = 0.0;
carAudio = listener.AddComponent(AudioSource);
carAudio.loop = false;
carAudio.playOnAwake = false;
carAudio.Stop();
crashTime = Mathf.Max(crashLowSpeedSound.length, crashHighSpeedSound.length);
soundsSet = false;
idleFadeSpeedDiff = idleFadeStopSpeed - idleFadeStartSpeed;
speedFadeSpeedDiff = speedFadeStopSpeed - speedFadeStartSpeed;
backgroundMusic = listener.AddComponent(AudioSource);
backgroundMusic.loop = true;
backgroundMusic.playOnAwake = true;
backgroundMusic.clip = BackgroundMusic;
// backgroundMusic.maxVolume = BackgroundMusicVolume;
// backgroundMusic.minVolume = BackgroundMusicVolume;
backgroundMusic.volume = BackgroundMusicVolume;
}
function Update()
{
var carSpeed : float = car.rigidbody.velocity.magnitude;
var carSpeedFactor : float = Mathf.Clamp01(carSpeed / car.topSpeed);
KAudio.volume = Mathf.Lerp(0, KVolume, carSpeedFactor);
windAudio.volume = Mathf.Lerp(0, windVolume, carSpeedFactor * 2);
if(shiftingGear)
return;
var pitchFactor : float = Sinerp(0, topGear, carSpeedFactor);
var newGear : int = pitchFactor;
pitchFactor -= newGear;
var throttleFactor : float = pitchFactor;
pitchFactor *= 0.3;
pitchFactor += throttleFactor * (0.7) * Mathf.Clamp01(car.throttle * 2);
if(newGear != gear)
{
if(newGear > gear)
GearShift(prevPitchFactor, pitchFactor, gear, true);
else
GearShift(prevPitchFactor, pitchFactor, gear, false);
gear = newGear;
}
else
{
var newPitch : float = 0;
if(gear == 0)
newPitch = Mathf.Lerp(idlePitch, highPitchFirst, pitchFactor);
else
if(gear == 1)
newPitch = Mathf.Lerp(startPitch, highPitchSecond, pitchFactor);
else
if(gear == 2)
newPitch = Mathf.Lerp(lowPitch, highPitchThird, pitchFactor);
else
newPitch = Mathf.Lerp(medPitch, highPitchFourth, pitchFactor);
SetPitch(newPitch);
SetVolume(newPitch);
}
prevPitchFactor = pitchFactor;
}
function Coserp(start : float, end : float, value : float) : float
{
return Mathf.Lerp(start, end, 1.0 - Mathf.Cos(value * Mathf.PI * 0.5));
}
function Sinerp(start : float, end : float, value : float) : float
{
return Mathf.Lerp(start, end, Mathf.Sin(value * Mathf.PI * 0.5));
}
function SetPitch(pitch : float)
{
DAudio.pitch = pitch;
EAudio.pitch = pitch;
FAudio.pitch = pitch;
LAudio.pitch = pitch;
tunnelAudio.pitch = pitch;
}
function SetVolume(pitch : float)
{
var pitchFactor : float = Mathf.Lerp(0, 1, (pitch - startPitch) / (highPitchSecond - startPitch));
DAudio.volume = Mathf.Lerp(0, DVolume, pitchFactor);
var fVolume : float = Mathf.Lerp(FVolume * 0.80, FVolume, pitchFactor);
FAudio.volume = fVolume * 0.7 + fVolume * 0.3 * Mathf.Clamp01(car.throttle);
var eVolume : float = Mathf.Lerp(EVolume * 0.89, EVolume, pitchFactor);
EAudio.volume = eVolume * 0.8 + eVolume * 0.2 * Mathf.Clamp01(car.throttle);
}
function GearShift(oldPitchFactor : float, newPitchFactor : float, gear : int, shiftUp : boolean)
{
shiftingGear = true;
var timer : float = 0;
var pitchFactor : float = 0;
var newPitch : float = 0;
if(shiftUp)
{
while(timer < gearShiftTime)
{
pitchFactor = Mathf.Lerp(oldPitchFactor, 0, timer / gearShiftTime);
if(gear == 0)
newPitch = Mathf.Lerp(lowPitch, highPitchFirst, pitchFactor);
else
newPitch = Mathf.Lerp(lowPitch, highPitchSecond, pitchFactor);
SetPitch(newPitch);
SetVolume(newPitch);
timer += Time.deltaTime;
yield;
}
}
else
{
while(timer < gearShiftTime)
{
pitchFactor = Mathf.Lerp(0, 1, timer / gearShiftTime);
newPitch = Mathf.Lerp(lowPitch, shiftPitch, pitchFactor);
SetPitch(newPitch);
SetVolume(newPitch);
timer += Time.deltaTime;
yield;
}
}
shiftingGear = false;
}
function Skid(play : boolean, volumeFactor : float)
{
if(!skidAudio)
return;
if(play)
{
skidAudio.volume = Mathf.Clamp01(volumeFactor + 0.3);
}
else
skidAudio.volume = 0.0;
}
// Checks if the max amount of crash sounds has been started, and
// if the max amount of total one shot sounds has been started.
function Crash(volumeFactor : float)
{
if(crashesStarted > 3 || OneShotLimitReached())
return;
if(volumeFactor > 0.9)
carAudio.PlayOneShot(crashHighSpeedSound, Mathf.Clamp01((0.5 + volumeFactor * 0.5) * crashHighVolume));
carAudio.PlayOneShot(crashLowSpeedSound, Mathf.Clamp01(volumeFactor * crashLowVolume));
crashesStarted++;
yield new WaitForSeconds(crashTime);
crashesStarted--;
}
// A function for testing if the maximum amount of OneShot AudioClips
// has been started.
function OneShotLimitReached()
{
return (crashesStarted + gearShiftsStarted) > oneShotLimit;
}
function OnTriggerEnter(coll : Collider)
{
var st : SoundToggler = coll.transform.GetComponent(SoundToggler);
if(st)
ControlSound(true, st.fadeTime);
}
function OnTriggerExit(coll : Collider)
{
var st : SoundToggler = coll.transform.GetComponent(SoundToggler);
if(st)
ControlSound(false, st.fadeTime);
}
function ControlSound(play : boolean, fadeTime : float)
{
var timer : float = 0;
if(play && !tunnelAudio.isPlaying)
{
tunnelAudio.volume = 0;
tunnelAudio.Play();
while(timer < fadeTime)
{
tunnelAudio.volume = Mathf.Lerp(0, tunnelVolume, timer / fadeTime);
timer += Time.deltaTime;
yield;
}
}
else if(!play && tunnelAudio.isPlaying)
{
while(timer < fadeTime)
{
tunnelAudio.volume = Mathf.Lerp(0, tunnelVolume, timer / fadeTime);
timer += Time.deltaTime;
yield;
}
tunnelAudio.Stop();
}
}