1019 lines
37 KiB
C#
1019 lines
37 KiB
C#
|
|
/*! \cond PRIVATE */
|
||
|
|
|
||
|
|
using UnityEngine;
|
||
|
|
using Random = UnityEngine.Random;
|
||
|
|
|
||
|
|
// ReSharper disable once CheckNamespace
|
||
|
|
namespace DarkTonic.MasterAudio {
|
||
|
|
/// <summary>
|
||
|
|
/// This class is only activated when you need code to execute in an Update method, such as "follow" code.
|
||
|
|
/// </summary>
|
||
|
|
// ReSharper disable once CheckNamespace
|
||
|
|
[AudioScriptOrder(-15)]
|
||
|
|
public class SoundGroupVariationUpdater : MonoBehaviour {
|
||
|
|
private const float TimeEarlyToScheduleNextClip = .1f;
|
||
|
|
private const float FakeNegativeFloatValue = -10f;
|
||
|
|
|
||
|
|
private Transform _objectToFollow;
|
||
|
|
private GameObject _objectToFollowGo;
|
||
|
|
private bool _isFollowing;
|
||
|
|
private SoundGroupVariation _variation;
|
||
|
|
private float _priorityLastUpdated = FakeNegativeFloatValue;
|
||
|
|
private bool _useClipAgePriority;
|
||
|
|
private WaitForSoundFinishMode _waitMode = WaitForSoundFinishMode.None;
|
||
|
|
private AudioSource _varAudio;
|
||
|
|
private MasterAudioGroup _parentGrp;
|
||
|
|
private Transform _trans;
|
||
|
|
private int _frameNum = -1;
|
||
|
|
private bool _inited = false;
|
||
|
|
|
||
|
|
// fade in out vars
|
||
|
|
private float _fadeOutStartTime = -5;
|
||
|
|
private bool _fadeInOutWillFadeOut;
|
||
|
|
private bool _hasFadeInOutSetMaxVolume;
|
||
|
|
private float _fadeInOutInFactor;
|
||
|
|
private float _fadeInOutOutFactor;
|
||
|
|
|
||
|
|
// fade out early vars
|
||
|
|
private System.Action _fadeOutEarlyCompletionCallback;
|
||
|
|
private int _fadeOutEarlyTotalFrames;
|
||
|
|
private float _fadeOutEarlyFrameVolChange;
|
||
|
|
private int _fadeOutEarlyFrameNumber;
|
||
|
|
private float _fadeOutEarlyOrigVol;
|
||
|
|
|
||
|
|
// gradual fade vars
|
||
|
|
private float _fadeToTargetFrameVolChange;
|
||
|
|
private int _fadeToTargetFrameNumber;
|
||
|
|
private float _fadeToTargetOrigVol;
|
||
|
|
private System.Action _fadeToTargetCompletionCallback;
|
||
|
|
private int _fadeToTargetTotalFrames;
|
||
|
|
private float _fadeToTargetVolume;
|
||
|
|
private bool _fadeOutStarted;
|
||
|
|
private float _lastFrameClipTime = -1f;
|
||
|
|
private bool _isPlayingBackward;
|
||
|
|
|
||
|
|
private int _pitchGlideToTargetTotalFrames;
|
||
|
|
private float _pitchGlideToTargetFramePitchChange;
|
||
|
|
private int _pitchGlideToTargetFrameNumber;
|
||
|
|
private float _glideToTargetPitch;
|
||
|
|
private float _glideToTargetOrigPitch;
|
||
|
|
private System.Action _glideToPitchCompletionCallback;
|
||
|
|
|
||
|
|
private bool _hasStartedNextInChain;
|
||
|
|
|
||
|
|
private bool _isWaitingForQueuedOcclusionRay;
|
||
|
|
private int _framesPlayed = 0;
|
||
|
|
private float? _clipStartPosition;
|
||
|
|
private float? _clipEndPosition;
|
||
|
|
private double? _clipSchedEndTime;
|
||
|
|
private bool _hasScheduledNextClip;
|
||
|
|
private bool _hasScheduledEndLinkedGroups;
|
||
|
|
private int _lastFrameClipPosition = -1;
|
||
|
|
private int _timesLooped = 0;
|
||
|
|
private bool _isPaused;
|
||
|
|
private double _pauseTime;
|
||
|
|
|
||
|
|
private static int _maCachedFromFrame = -1;
|
||
|
|
private static MasterAudio _maThisFrame;
|
||
|
|
private static Transform _listenerThisFrame;
|
||
|
|
|
||
|
|
private enum WaitForSoundFinishMode {
|
||
|
|
None,
|
||
|
|
Play,
|
||
|
|
WaitForEnd,
|
||
|
|
StopOrRepeat
|
||
|
|
}
|
||
|
|
|
||
|
|
#region Public methods
|
||
|
|
|
||
|
|
public void GlidePitch(float targetPitch, float glideTime, System.Action completionCallback = null) {
|
||
|
|
GrpVariation.curPitchMode = SoundGroupVariation.PitchMode.Gliding;
|
||
|
|
|
||
|
|
var pitchDiff = targetPitch - VarAudio.pitch;
|
||
|
|
|
||
|
|
_pitchGlideToTargetTotalFrames = (int)(glideTime / AudioUtil.FrameTime);
|
||
|
|
_pitchGlideToTargetFramePitchChange = pitchDiff / _pitchGlideToTargetTotalFrames;
|
||
|
|
_pitchGlideToTargetFrameNumber = 0;
|
||
|
|
_glideToTargetPitch = targetPitch;
|
||
|
|
_glideToTargetOrigPitch = VarAudio.pitch;
|
||
|
|
_glideToPitchCompletionCallback = completionCallback;
|
||
|
|
}
|
||
|
|
|
||
|
|
public void FadeOverTimeToVolume(float targetVolume, float fadeTime, System.Action completionCallback = null) {
|
||
|
|
GrpVariation.curFadeMode = SoundGroupVariation.FadeMode.GradualFade;
|
||
|
|
|
||
|
|
var volDiff = targetVolume - VarAudio.volume;
|
||
|
|
|
||
|
|
var currentClipTime = VarAudio.time;
|
||
|
|
var currentClipLength = ClipEndPosition;
|
||
|
|
|
||
|
|
if (!VarAudio.loop && VarAudio.clip != null && fadeTime + currentClipTime > currentClipLength) {
|
||
|
|
// if too long, fade out faster
|
||
|
|
fadeTime = currentClipLength - currentClipTime;
|
||
|
|
}
|
||
|
|
|
||
|
|
_fadeToTargetTotalFrames = (int)(fadeTime / AudioUtil.FrameTime);
|
||
|
|
_fadeToTargetFrameVolChange = volDiff / _fadeToTargetTotalFrames;
|
||
|
|
_fadeToTargetFrameNumber = 0;
|
||
|
|
_fadeToTargetOrigVol = VarAudio.volume;
|
||
|
|
_fadeToTargetVolume = targetVolume;
|
||
|
|
_fadeToTargetCompletionCallback = completionCallback;
|
||
|
|
}
|
||
|
|
|
||
|
|
public void FadeOutEarly(float fadeTime, System.Action completionCallback = null) {
|
||
|
|
GrpVariation.curFadeMode = SoundGroupVariation.FadeMode.FadeOutEarly;
|
||
|
|
// cancel the FadeInOut loop, if it's going.
|
||
|
|
|
||
|
|
if (!VarAudio.loop && VarAudio.clip != null && VarAudio.time + fadeTime > ClipEndPosition) {
|
||
|
|
// if too long, fade out faster
|
||
|
|
fadeTime = ClipEndPosition - VarAudio.time;
|
||
|
|
}
|
||
|
|
|
||
|
|
var frameTime = AudioUtil.FrameTime;
|
||
|
|
if (frameTime == 0) {
|
||
|
|
frameTime = AudioUtil.FixedDeltaTime;
|
||
|
|
}
|
||
|
|
|
||
|
|
_fadeOutEarlyCompletionCallback = completionCallback;
|
||
|
|
_fadeOutEarlyTotalFrames = (int)(fadeTime / frameTime);
|
||
|
|
_fadeOutEarlyFrameVolChange = -VarAudio.volume / _fadeOutEarlyTotalFrames;
|
||
|
|
_fadeOutEarlyFrameNumber = 0;
|
||
|
|
_fadeOutEarlyOrigVol = VarAudio.volume;
|
||
|
|
}
|
||
|
|
|
||
|
|
// Called by Master Audio, do not call.
|
||
|
|
public void Initialize() {
|
||
|
|
if (_inited) {
|
||
|
|
return;
|
||
|
|
}
|
||
|
|
|
||
|
|
_lastFrameClipPosition = -1;
|
||
|
|
_timesLooped = 0;
|
||
|
|
_isPaused = false;
|
||
|
|
_pauseTime = -1;
|
||
|
|
_clipStartPosition = null;
|
||
|
|
_clipEndPosition = null;
|
||
|
|
_clipSchedEndTime = null;
|
||
|
|
_hasScheduledNextClip = false;
|
||
|
|
_hasScheduledEndLinkedGroups = false;
|
||
|
|
_inited = true;
|
||
|
|
}
|
||
|
|
|
||
|
|
public void FadeInOut() {
|
||
|
|
GrpVariation.curFadeMode = SoundGroupVariation.FadeMode.FadeInOut;
|
||
|
|
// wait to set this so it stops the previous one if it's still going.
|
||
|
|
_fadeOutStartTime = ClipEndPosition - GrpVariation.fadeOutTime;
|
||
|
|
|
||
|
|
if (GrpVariation.fadeInTime > 0f) {
|
||
|
|
VarAudio.volume = 0f; // start at zero volume
|
||
|
|
_fadeInOutInFactor = GrpVariation.fadeMaxVolume / GrpVariation.fadeInTime;
|
||
|
|
} else {
|
||
|
|
_fadeInOutInFactor = 0f;
|
||
|
|
}
|
||
|
|
|
||
|
|
_fadeInOutWillFadeOut = GrpVariation.fadeOutTime > 0f && !VarAudio.loop;
|
||
|
|
|
||
|
|
if (_fadeInOutWillFadeOut) {
|
||
|
|
_fadeInOutOutFactor = GrpVariation.fadeMaxVolume / (ClipEndPosition - _fadeOutStartTime);
|
||
|
|
} else {
|
||
|
|
_fadeInOutOutFactor = 0f;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
public void FollowObject(bool follow, Transform objToFollow, bool clipAgePriority) {
|
||
|
|
_isFollowing = follow;
|
||
|
|
|
||
|
|
if (objToFollow != null) {
|
||
|
|
_objectToFollow = objToFollow;
|
||
|
|
_objectToFollowGo = objToFollow.gameObject;
|
||
|
|
}
|
||
|
|
_useClipAgePriority = clipAgePriority;
|
||
|
|
|
||
|
|
UpdateCachedObjects();
|
||
|
|
UpdateAudioLocationAndPriority(false); // in case we're not following, it should get one update.
|
||
|
|
}
|
||
|
|
|
||
|
|
public void WaitForSoundFinish() {
|
||
|
|
if (MasterAudio.IsWarming) {
|
||
|
|
PlaySoundAndWait();
|
||
|
|
return;
|
||
|
|
}
|
||
|
|
|
||
|
|
_waitMode = WaitForSoundFinishMode.Play;
|
||
|
|
}
|
||
|
|
|
||
|
|
public void StopPitchGliding() {
|
||
|
|
GrpVariation.curPitchMode = SoundGroupVariation.PitchMode.None;
|
||
|
|
|
||
|
|
if (_glideToPitchCompletionCallback != null) {
|
||
|
|
_glideToPitchCompletionCallback();
|
||
|
|
_glideToPitchCompletionCallback = null;
|
||
|
|
}
|
||
|
|
|
||
|
|
DisableIfFinished();
|
||
|
|
}
|
||
|
|
|
||
|
|
public void StopFading() {
|
||
|
|
GrpVariation.curFadeMode = SoundGroupVariation.FadeMode.None;
|
||
|
|
|
||
|
|
DisableIfFinished();
|
||
|
|
}
|
||
|
|
|
||
|
|
public void StopWaitingForFinish() {
|
||
|
|
_waitMode = WaitForSoundFinishMode.None;
|
||
|
|
GrpVariation.curDetectEndMode = SoundGroupVariation.DetectEndMode.None;
|
||
|
|
|
||
|
|
DisableIfFinished();
|
||
|
|
}
|
||
|
|
|
||
|
|
public void StopFollowing() {
|
||
|
|
_isFollowing = false;
|
||
|
|
_useClipAgePriority = false;
|
||
|
|
_objectToFollow = null;
|
||
|
|
_objectToFollowGo = null;
|
||
|
|
|
||
|
|
DisableIfFinished();
|
||
|
|
}
|
||
|
|
|
||
|
|
#endregion
|
||
|
|
|
||
|
|
#region Helper methods
|
||
|
|
|
||
|
|
private void DisableIfFinished() {
|
||
|
|
if (_isFollowing
|
||
|
|
|| GrpVariation.curDetectEndMode == SoundGroupVariation.DetectEndMode.DetectEnd
|
||
|
|
|| GrpVariation.curFadeMode != SoundGroupVariation.FadeMode.None) {
|
||
|
|
|
||
|
|
return;
|
||
|
|
}
|
||
|
|
|
||
|
|
if (GrpVariation.curPitchMode != SoundGroupVariation.PitchMode.None) {
|
||
|
|
return;
|
||
|
|
}
|
||
|
|
|
||
|
|
enabled = false;
|
||
|
|
}
|
||
|
|
|
||
|
|
private void UpdateAudioLocationAndPriority(bool rePrioritize) {
|
||
|
|
// update location, only if following.
|
||
|
|
if (_isFollowing && _objectToFollow != null) {
|
||
|
|
Trans.position = _objectToFollow.position;
|
||
|
|
}
|
||
|
|
|
||
|
|
// re-set priority, still used by non-following (audio clip age priority)
|
||
|
|
if (!_maThisFrame.prioritizeOnDistance || !rePrioritize || ParentGroup.alwaysHighestPriority) {
|
||
|
|
return;
|
||
|
|
}
|
||
|
|
|
||
|
|
if (Time.realtimeSinceStartup - _priorityLastUpdated <= MasterAudio.ReprioritizeTime) {
|
||
|
|
return;
|
||
|
|
}
|
||
|
|
|
||
|
|
AudioPrioritizer.Set3DPriority(GrpVariation, _useClipAgePriority);
|
||
|
|
_priorityLastUpdated = AudioUtil.Time;
|
||
|
|
}
|
||
|
|
|
||
|
|
private void ResetToNonOcclusionSetting() {
|
||
|
|
var lp = GrpVariation.LowPassFilter;
|
||
|
|
if (lp != null) {
|
||
|
|
lp.cutoffFrequency = AudioUtil.DefaultMinOcclusionCutoffFrequency;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
private void UpdateOcclusion() {
|
||
|
|
var hasOcclusionOn = GrpVariation.UsesOcclusion;
|
||
|
|
if (!hasOcclusionOn) {
|
||
|
|
MasterAudio.StopTrackingOcclusionForSource(GrpVariation.GameObj);
|
||
|
|
ResetToNonOcclusionSetting();
|
||
|
|
|
||
|
|
return;
|
||
|
|
}
|
||
|
|
|
||
|
|
if (_listenerThisFrame == null) {
|
||
|
|
// cannot occlude without something to raycast at.
|
||
|
|
return;
|
||
|
|
}
|
||
|
|
|
||
|
|
if (IsOcclusionMeasuringPaused) {
|
||
|
|
return; // wait until processed
|
||
|
|
}
|
||
|
|
|
||
|
|
MasterAudio.AddToQueuedOcclusionRays(this);
|
||
|
|
_isWaitingForQueuedOcclusionRay = true;
|
||
|
|
}
|
||
|
|
|
||
|
|
private void DoneWithOcclusion() {
|
||
|
|
_isWaitingForQueuedOcclusionRay = false;
|
||
|
|
MasterAudio.RemoveFromOcclusionFrequencyTransitioning(GrpVariation);
|
||
|
|
}
|
||
|
|
|
||
|
|
/// <summary>
|
||
|
|
/// This method is called in a batch from ListenerFollower
|
||
|
|
/// </summary>
|
||
|
|
/// <returns></returns>
|
||
|
|
public bool RayCastForOcclusion() {
|
||
|
|
DoneWithOcclusion();
|
||
|
|
|
||
|
|
var raycastOrigin = Trans.position;
|
||
|
|
|
||
|
|
var offset = RayCastOriginOffset;
|
||
|
|
if (offset > 0) {
|
||
|
|
raycastOrigin = Vector3.MoveTowards(raycastOrigin, _listenerThisFrame.position, offset);
|
||
|
|
}
|
||
|
|
|
||
|
|
var direction = _listenerThisFrame.position - raycastOrigin;
|
||
|
|
var distanceToListener = direction.magnitude;
|
||
|
|
|
||
|
|
if (distanceToListener > VarAudio.maxDistance) {
|
||
|
|
// out of hearing range, no reason to calculate occlusion.
|
||
|
|
MasterAudio.AddToOcclusionOutOfRangeSources(GrpVariation.GameObj);
|
||
|
|
ResetToNonOcclusionSetting();
|
||
|
|
return false;
|
||
|
|
}
|
||
|
|
|
||
|
|
MasterAudio.AddToOcclusionInRangeSources(GrpVariation.GameObj);
|
||
|
|
var is2DRaycast = _maThisFrame.occlusionRaycastMode == MasterAudio.RaycastMode.Physics2D;
|
||
|
|
|
||
|
|
if (GrpVariation.LowPassFilter == null) {
|
||
|
|
// in case Occlusion got turned on during runtime.
|
||
|
|
var newFilter = GrpVariation.gameObject.AddComponent<AudioLowPassFilter>();
|
||
|
|
GrpVariation.LowPassFilter = newFilter;
|
||
|
|
}
|
||
|
|
|
||
|
|
#if PHY2D_ENABLED
|
||
|
|
var oldQueriesStart = Physics2D.queriesStartInColliders;
|
||
|
|
if (is2DRaycast) {
|
||
|
|
Physics2D.queriesStartInColliders = _maThisFrame.occlusionIncludeStartRaycast2DCollider;
|
||
|
|
}
|
||
|
|
#endif
|
||
|
|
|
||
|
|
#if PHY2D_ENABLED || PHY3D_ENABLED
|
||
|
|
var oldRaycastsHitTriggers = true;
|
||
|
|
#endif
|
||
|
|
|
||
|
|
// ReSharper disable once ConvertIfStatementToConditionalTernaryExpression
|
||
|
|
if (is2DRaycast) {
|
||
|
|
#if PHY2D_ENABLED
|
||
|
|
oldRaycastsHitTriggers = Physics2D.queriesHitTriggers;
|
||
|
|
Physics2D.queriesHitTriggers = _maThisFrame.occlusionRaycastsHitTriggers;
|
||
|
|
#endif
|
||
|
|
} else {
|
||
|
|
#if PHY3D_ENABLED
|
||
|
|
oldRaycastsHitTriggers = Physics.queriesHitTriggers;
|
||
|
|
Physics.queriesHitTriggers = _maThisFrame.occlusionRaycastsHitTriggers;
|
||
|
|
#endif
|
||
|
|
}
|
||
|
|
|
||
|
|
var hitPoint = Vector3.zero;
|
||
|
|
float? hitDistance = null;
|
||
|
|
var isHit = false;
|
||
|
|
|
||
|
|
if (_maThisFrame.occlusionUseLayerMask) {
|
||
|
|
switch (_maThisFrame.occlusionRaycastMode) {
|
||
|
|
case MasterAudio.RaycastMode.Physics3D:
|
||
|
|
#if PHY3D_ENABLED
|
||
|
|
RaycastHit hitObject;
|
||
|
|
if (Physics.Raycast(raycastOrigin, direction, out hitObject, distanceToListener, _maThisFrame.occlusionLayerMask.value)) {
|
||
|
|
isHit = true;
|
||
|
|
hitPoint = hitObject.point;
|
||
|
|
hitDistance = hitObject.distance;
|
||
|
|
}
|
||
|
|
#endif
|
||
|
|
break;
|
||
|
|
case MasterAudio.RaycastMode.Physics2D:
|
||
|
|
#if PHY2D_ENABLED
|
||
|
|
var castHit2D = Physics2D.Raycast(raycastOrigin, direction, distanceToListener, _maThisFrame.occlusionLayerMask.value);
|
||
|
|
if (castHit2D.transform != null) {
|
||
|
|
isHit = true;
|
||
|
|
hitPoint = castHit2D.point;
|
||
|
|
hitDistance = castHit2D.distance;
|
||
|
|
}
|
||
|
|
#endif
|
||
|
|
break;
|
||
|
|
}
|
||
|
|
} else {
|
||
|
|
switch (_maThisFrame.occlusionRaycastMode) {
|
||
|
|
case MasterAudio.RaycastMode.Physics3D:
|
||
|
|
#if PHY3D_ENABLED
|
||
|
|
RaycastHit hitObject;
|
||
|
|
if (Physics.Raycast(raycastOrigin, direction, out hitObject, distanceToListener)) {
|
||
|
|
isHit = true;
|
||
|
|
hitPoint = hitObject.point;
|
||
|
|
hitDistance = hitObject.distance;
|
||
|
|
}
|
||
|
|
#endif
|
||
|
|
break;
|
||
|
|
case MasterAudio.RaycastMode.Physics2D:
|
||
|
|
#if PHY2D_ENABLED
|
||
|
|
var castHit2D = Physics2D.Raycast(raycastOrigin, direction, distanceToListener);
|
||
|
|
if (castHit2D.transform != null) {
|
||
|
|
isHit = true;
|
||
|
|
hitPoint = castHit2D.point;
|
||
|
|
hitDistance = castHit2D.distance;
|
||
|
|
}
|
||
|
|
#endif
|
||
|
|
break;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
if (is2DRaycast) {
|
||
|
|
#if PHY2D_ENABLED
|
||
|
|
Physics2D.queriesStartInColliders = oldQueriesStart;
|
||
|
|
Physics2D.queriesHitTriggers = oldRaycastsHitTriggers;
|
||
|
|
#endif
|
||
|
|
} else {
|
||
|
|
#if PHY3D_ENABLED
|
||
|
|
Physics.queriesHitTriggers = oldRaycastsHitTriggers;
|
||
|
|
#endif
|
||
|
|
}
|
||
|
|
|
||
|
|
if (_maThisFrame.occlusionShowRaycasts) {
|
||
|
|
var endPoint = isHit ? hitPoint : _listenerThisFrame.position;
|
||
|
|
var lineColor = isHit ? Color.red : Color.green;
|
||
|
|
Debug.DrawLine(raycastOrigin, endPoint, lineColor, .1f);
|
||
|
|
}
|
||
|
|
|
||
|
|
if (!isHit) {
|
||
|
|
// ReSharper disable once PossibleNullReferenceException
|
||
|
|
MasterAudio.RemoveFromBlockedOcclusionSources(GrpVariation.GameObj);
|
||
|
|
ResetToNonOcclusionSetting();
|
||
|
|
return true;
|
||
|
|
}
|
||
|
|
|
||
|
|
MasterAudio.AddToBlockedOcclusionSources(GrpVariation.GameObj);
|
||
|
|
|
||
|
|
var ratioToEdgeOfSound = hitDistance.Value / VarAudio.maxDistance;
|
||
|
|
var filterFrequency = AudioUtil.GetOcclusionCutoffFrequencyByDistanceRatio(ratioToEdgeOfSound, this);
|
||
|
|
|
||
|
|
var fadeTime = _maThisFrame.occlusionFreqChangeSeconds;
|
||
|
|
if (fadeTime <= MasterAudio.InnerLoopCheckInterval) { // fast, just do it instantly.
|
||
|
|
// ReSharper disable once PossibleNullReferenceException
|
||
|
|
GrpVariation.LowPassFilter.cutoffFrequency = filterFrequency;
|
||
|
|
return true;
|
||
|
|
}
|
||
|
|
|
||
|
|
MasterAudio.GradualOcclusionFreqChange(GrpVariation, fadeTime, filterFrequency);
|
||
|
|
|
||
|
|
return true;
|
||
|
|
}
|
||
|
|
|
||
|
|
private void PlaySoundAndWait() {
|
||
|
|
if (VarAudio.clip == null) { // in case the warming sound is an "internet file"
|
||
|
|
return;
|
||
|
|
}
|
||
|
|
|
||
|
|
double startTime = AudioSettings.dspTime;
|
||
|
|
|
||
|
|
if (GrpVariation.PlaySoundParm.TimeToSchedulePlay.HasValue) {
|
||
|
|
startTime = GrpVariation.PlaySoundParm.TimeToSchedulePlay.Value;
|
||
|
|
}
|
||
|
|
|
||
|
|
var delayTime = 0f;
|
||
|
|
|
||
|
|
if (GrpVariation.useIntroSilence && GrpVariation.introSilenceMax > 0f) {
|
||
|
|
var rndSilence = Random.Range(GrpVariation.introSilenceMin, GrpVariation.introSilenceMax);
|
||
|
|
delayTime += rndSilence;
|
||
|
|
}
|
||
|
|
|
||
|
|
delayTime += GrpVariation.PlaySoundParm.DelaySoundTime;
|
||
|
|
|
||
|
|
if (delayTime > 0f) {
|
||
|
|
startTime += delayTime;
|
||
|
|
}
|
||
|
|
|
||
|
|
VarAudio.PlayScheduled(startTime);
|
||
|
|
|
||
|
|
switch (GrpVariation.audLocation) {
|
||
|
|
#if ADDRESSABLES_ENABLED
|
||
|
|
case MasterAudio.AudioLocation.Addressable:
|
||
|
|
AudioAddressableOptimizer.AddAddressablePlayingClip(GrpVariation.audioClipAddressable, VarAudio);
|
||
|
|
break;
|
||
|
|
#endif
|
||
|
|
default:
|
||
|
|
AudioUtil.ClipPlayed(VarAudio.clip, GrpVariation.GameObj);
|
||
|
|
break;
|
||
|
|
}
|
||
|
|
|
||
|
|
if (GrpVariation.useRandomStartTime) {
|
||
|
|
VarAudio.time = ClipStartPosition;
|
||
|
|
|
||
|
|
if (!VarAudio.loop) { // don't stop it if it's going to loop.
|
||
|
|
var playableLength = AudioUtil.AdjustAudioClipDurationForPitch(ClipEndPosition - ClipStartPosition, VarAudio);
|
||
|
|
_clipSchedEndTime = startTime + playableLength;
|
||
|
|
VarAudio.SetScheduledEndTime(_clipSchedEndTime.Value);
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
GrpVariation.LastTimePlayed = AudioUtil.Time;
|
||
|
|
|
||
|
|
DuckIfNotSilent();
|
||
|
|
|
||
|
|
_isPlayingBackward = GrpVariation.OriginalPitch < 0;
|
||
|
|
_lastFrameClipTime = _isPlayingBackward ? ClipEndPosition + 1 : -1f;
|
||
|
|
|
||
|
|
_waitMode = WaitForSoundFinishMode.WaitForEnd;
|
||
|
|
}
|
||
|
|
|
||
|
|
private void DuckIfNotSilent() {
|
||
|
|
bool isSilent = false;
|
||
|
|
|
||
|
|
if (GrpVariation.PlaySoundParm.VolumePercentage <= 0) {
|
||
|
|
isSilent = true;
|
||
|
|
} else if (GrpVariation.ParentGroup.groupMasterVolume <= 0) {
|
||
|
|
isSilent = true;
|
||
|
|
} else if (GrpVariation.VarAudio.mute) { // other group soloed
|
||
|
|
isSilent = true;
|
||
|
|
} else if (MasterAudio.MixerMuted) {
|
||
|
|
isSilent = true;
|
||
|
|
} else if (GrpVariation.ParentGroup.isMuted) {
|
||
|
|
isSilent = true;
|
||
|
|
} else {
|
||
|
|
var bus = GrpVariation.ParentGroup.BusForGroup;
|
||
|
|
if (bus != null && bus.isMuted) {
|
||
|
|
isSilent = true;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
// sound play worked! Duck music if a ducking sound and sound is not silent.
|
||
|
|
if (!isSilent) {
|
||
|
|
MasterAudio.DuckSoundGroup(ParentGroup.GameObjectName, VarAudio, this);
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
private void StopOrChain() {
|
||
|
|
var playSnd = GrpVariation.PlaySoundParm;
|
||
|
|
|
||
|
|
var wasPlaying = playSnd.IsPlaying;
|
||
|
|
var usingChainLoop = wasPlaying && playSnd.IsChainLoop;
|
||
|
|
|
||
|
|
if (!VarAudio.loop || usingChainLoop) {
|
||
|
|
GrpVariation.Stop();
|
||
|
|
}
|
||
|
|
|
||
|
|
if (!usingChainLoop) {
|
||
|
|
return;
|
||
|
|
}
|
||
|
|
StopWaitingForFinish();
|
||
|
|
|
||
|
|
MaybeChain();
|
||
|
|
}
|
||
|
|
|
||
|
|
public void Pause() {
|
||
|
|
_isPaused = true;
|
||
|
|
_pauseTime = AudioSettings.dspTime;
|
||
|
|
MasterAudio.EndDucking(this);
|
||
|
|
}
|
||
|
|
|
||
|
|
public void Unpause() {
|
||
|
|
_isPaused = false;
|
||
|
|
|
||
|
|
if (_clipSchedEndTime.HasValue) {
|
||
|
|
var timePaused = AudioSettings.dspTime - _pauseTime;
|
||
|
|
_clipSchedEndTime += timePaused;
|
||
|
|
VarAudio.SetScheduledEndTime(_clipSchedEndTime.Value);
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
public void MaybeChain() {
|
||
|
|
if (_hasStartedNextInChain) {
|
||
|
|
return;
|
||
|
|
}
|
||
|
|
|
||
|
|
_hasStartedNextInChain = true;
|
||
|
|
|
||
|
|
var playSnd = GrpVariation.PlaySoundParm;
|
||
|
|
|
||
|
|
var clipsRemaining = MasterAudio.RemainingClipsInGroup(ParentGroup.GameObjectName);
|
||
|
|
var totalClips = MasterAudio.VoicesForGroup(ParentGroup.GameObjectName);
|
||
|
|
|
||
|
|
if (clipsRemaining == totalClips) {
|
||
|
|
ParentGroup.FireLastVariationFinishedPlay();
|
||
|
|
}
|
||
|
|
|
||
|
|
// check if loop count is over.
|
||
|
|
if (ParentGroup.chainLoopMode == MasterAudioGroup.ChainedLoopLoopMode.NumberOfLoops && ParentGroup.ChainLoopCount >= ParentGroup.chainLoopNumLoops) {
|
||
|
|
// done looping
|
||
|
|
return;
|
||
|
|
}
|
||
|
|
|
||
|
|
var rndDelay = playSnd.DelaySoundTime;
|
||
|
|
if (ParentGroup.chainLoopDelayMin > 0f || ParentGroup.chainLoopDelayMax > 0f) {
|
||
|
|
rndDelay = Random.Range(ParentGroup.chainLoopDelayMin, ParentGroup.chainLoopDelayMax);
|
||
|
|
}
|
||
|
|
|
||
|
|
// cannot use "AndForget" methods! Chain loop needs to check the status.
|
||
|
|
if (playSnd.AttachToSource || playSnd.SourceTrans != null) {
|
||
|
|
PlaySoundResult chainedVariation = null;
|
||
|
|
|
||
|
|
if (playSnd.AttachToSource) {
|
||
|
|
chainedVariation = MasterAudio.PlaySound3DFollowTransform(playSnd.SoundType, playSnd.SourceTrans,
|
||
|
|
playSnd.VolumePercentage, playSnd.Pitch, rndDelay, null, _clipSchedEndTime, true);
|
||
|
|
} else {
|
||
|
|
chainedVariation = MasterAudio.PlaySound3DAtTransform(playSnd.SoundType, playSnd.SourceTrans, playSnd.VolumePercentage,
|
||
|
|
playSnd.Pitch, rndDelay, null, _clipSchedEndTime, true);
|
||
|
|
}
|
||
|
|
|
||
|
|
if (chainedVariation.ActingVariation != null) {
|
||
|
|
// must set and inform TransformTracker of the new Variation so it doesn't continue to follow the old.
|
||
|
|
chainedVariation.ActingVariation.UpdateAudioVariation(GrpVariation.AmbientFollower);
|
||
|
|
}
|
||
|
|
} else {
|
||
|
|
MasterAudio.PlaySoundAndForget(playSnd.SoundType, playSnd.VolumePercentage, playSnd.Pitch, rndDelay, null, _clipSchedEndTime, true);
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
private void UpdatePitch() {
|
||
|
|
switch (GrpVariation.curPitchMode) {
|
||
|
|
case SoundGroupVariation.PitchMode.None:
|
||
|
|
return;
|
||
|
|
case SoundGroupVariation.PitchMode.Gliding:
|
||
|
|
if (!VarAudio.isPlaying) {
|
||
|
|
break;
|
||
|
|
}
|
||
|
|
|
||
|
|
_pitchGlideToTargetFrameNumber++;
|
||
|
|
if (_pitchGlideToTargetFrameNumber >= _pitchGlideToTargetTotalFrames) {
|
||
|
|
VarAudio.pitch = _glideToTargetPitch;
|
||
|
|
StopPitchGliding();
|
||
|
|
} else {
|
||
|
|
VarAudio.pitch = (_pitchGlideToTargetFrameNumber * _pitchGlideToTargetFramePitchChange) + _glideToTargetOrigPitch;
|
||
|
|
}
|
||
|
|
|
||
|
|
break;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
private void PerformFading() {
|
||
|
|
switch (GrpVariation.curFadeMode) {
|
||
|
|
case SoundGroupVariation.FadeMode.None:
|
||
|
|
break;
|
||
|
|
case SoundGroupVariation.FadeMode.FadeInOut:
|
||
|
|
if (!VarAudio.isPlaying) {
|
||
|
|
break;
|
||
|
|
}
|
||
|
|
|
||
|
|
var clipTime = VarAudio.time;
|
||
|
|
if (GrpVariation.fadeInTime > 0f && clipTime < GrpVariation.fadeInTime) {
|
||
|
|
// fade in!
|
||
|
|
VarAudio.volume = clipTime * _fadeInOutInFactor;
|
||
|
|
} else if (clipTime >= GrpVariation.fadeInTime && !_hasFadeInOutSetMaxVolume) {
|
||
|
|
VarAudio.volume = GrpVariation.fadeMaxVolume;
|
||
|
|
_hasFadeInOutSetMaxVolume = true;
|
||
|
|
if (!_fadeInOutWillFadeOut) {
|
||
|
|
StopFading();
|
||
|
|
}
|
||
|
|
} else if (_fadeInOutWillFadeOut && clipTime >= _fadeOutStartTime) {
|
||
|
|
// fade out!
|
||
|
|
if (GrpVariation.PlaySoundParm.IsChainLoop && !_fadeOutStarted) {
|
||
|
|
MaybeChain();
|
||
|
|
_fadeOutStarted = true;
|
||
|
|
}
|
||
|
|
VarAudio.volume = (ClipEndPosition - clipTime) * _fadeInOutOutFactor;
|
||
|
|
}
|
||
|
|
break;
|
||
|
|
case SoundGroupVariation.FadeMode.FadeOutEarly:
|
||
|
|
if (!VarAudio.isPlaying) {
|
||
|
|
break;
|
||
|
|
}
|
||
|
|
|
||
|
|
_fadeOutEarlyFrameNumber++;
|
||
|
|
|
||
|
|
VarAudio.volume = (_fadeOutEarlyFrameNumber * _fadeOutEarlyFrameVolChange) + _fadeOutEarlyOrigVol;
|
||
|
|
|
||
|
|
if (_fadeOutEarlyFrameNumber >= _fadeOutEarlyTotalFrames) {
|
||
|
|
GrpVariation.curFadeMode = SoundGroupVariation.FadeMode.None;
|
||
|
|
GrpVariation.Stop();
|
||
|
|
if (_fadeOutEarlyCompletionCallback != null)
|
||
|
|
{
|
||
|
|
_fadeOutEarlyCompletionCallback();
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
break;
|
||
|
|
case SoundGroupVariation.FadeMode.GradualFade:
|
||
|
|
if (!VarAudio.isPlaying) {
|
||
|
|
break;
|
||
|
|
}
|
||
|
|
|
||
|
|
_fadeToTargetFrameNumber++;
|
||
|
|
if (_fadeToTargetFrameNumber >= _fadeToTargetTotalFrames) {
|
||
|
|
var grpInfo = MasterAudio.GetAllVariationsOfGroup(ParentGroup.GameObjectName);
|
||
|
|
for (var i = 0; i < grpInfo.Count; i++) {
|
||
|
|
var aVar = grpInfo[i];
|
||
|
|
if (aVar.Variation != this.GrpVariation)
|
||
|
|
{
|
||
|
|
continue;
|
||
|
|
}
|
||
|
|
|
||
|
|
aVar.LastPercentageVolume = _fadeToTargetVolume;
|
||
|
|
break;
|
||
|
|
}
|
||
|
|
|
||
|
|
|
||
|
|
VarAudio.volume = _fadeToTargetVolume;
|
||
|
|
StopFading();
|
||
|
|
if (_fadeToTargetCompletionCallback != null)
|
||
|
|
{
|
||
|
|
_fadeToTargetCompletionCallback();
|
||
|
|
}
|
||
|
|
} else {
|
||
|
|
VarAudio.volume = (_fadeToTargetFrameNumber * _fadeToTargetFrameVolChange) + _fadeToTargetOrigVol;
|
||
|
|
}
|
||
|
|
break;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
#endregion
|
||
|
|
|
||
|
|
#region MonoBehavior events
|
||
|
|
|
||
|
|
// ReSharper disable once UnusedMember.Local
|
||
|
|
private void OnEnable() {
|
||
|
|
_inited = false;
|
||
|
|
|
||
|
|
// values to be reset every time a sound plays.
|
||
|
|
_fadeInOutWillFadeOut = false;
|
||
|
|
_hasFadeInOutSetMaxVolume = false;
|
||
|
|
_fadeOutStarted = false;
|
||
|
|
_hasStartedNextInChain = false;
|
||
|
|
_framesPlayed = 0;
|
||
|
|
|
||
|
|
_clipStartPosition = null;
|
||
|
|
_clipEndPosition = null;
|
||
|
|
|
||
|
|
DoneWithOcclusion();
|
||
|
|
MasterAudio.RegisterUpdaterForUpdates(this);
|
||
|
|
}
|
||
|
|
|
||
|
|
// ReSharper disable once UnusedMember.Local
|
||
|
|
private void OnDisable() {
|
||
|
|
if (MasterAudio.AppIsShuttingDown) {
|
||
|
|
return; // do nothing
|
||
|
|
}
|
||
|
|
|
||
|
|
_framesPlayed = 0;
|
||
|
|
|
||
|
|
DoneWithOcclusion();
|
||
|
|
MasterAudio.UnregisterUpdaterForUpdates(this);
|
||
|
|
}
|
||
|
|
|
||
|
|
public void UpdateCachedObjects() {
|
||
|
|
_frameNum = AudioUtil.FrameCount;
|
||
|
|
|
||
|
|
// ReSharper disable once InvertIf
|
||
|
|
if (_maCachedFromFrame >= _frameNum) {
|
||
|
|
return; // same frame. Use cached objects
|
||
|
|
}
|
||
|
|
|
||
|
|
// new frame. Update cached objects and frame counters;
|
||
|
|
_maCachedFromFrame = _frameNum;
|
||
|
|
_maThisFrame = MasterAudio.Instance;
|
||
|
|
_listenerThisFrame = MasterAudio.ListenerTrans;
|
||
|
|
}
|
||
|
|
|
||
|
|
/// <summary>
|
||
|
|
/// This method will be called by MasterAudio.cs either during LateUpdate (default) or FixedUpdate, however you've configured it in Advanced Settings.
|
||
|
|
/// </summary>
|
||
|
|
public void ManualUpdate() {
|
||
|
|
UpdateCachedObjects();
|
||
|
|
|
||
|
|
_framesPlayed++;
|
||
|
|
|
||
|
|
if (VarAudio.loop) {
|
||
|
|
if (VarAudio.timeSamples < _lastFrameClipPosition) {
|
||
|
|
_timesLooped++;
|
||
|
|
if (VarAudio.loop && GrpVariation.useCustomLooping && _timesLooped >= GrpVariation.MaxLoops) {
|
||
|
|
GrpVariation.Stop();
|
||
|
|
} else {
|
||
|
|
GrpVariation.SoundLoopStarted(_timesLooped);
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
_lastFrameClipPosition = VarAudio.timeSamples;
|
||
|
|
}
|
||
|
|
|
||
|
|
if (_isFollowing) { // check for despawned caller and act if so.
|
||
|
|
if (ParentGroup.targetDespawnedBehavior != MasterAudioGroup.TargetDespawnedBehavior.None) {
|
||
|
|
if (_objectToFollowGo == null || !DTMonoHelper.IsActive(_objectToFollowGo)) {
|
||
|
|
switch (ParentGroup.targetDespawnedBehavior) {
|
||
|
|
case MasterAudioGroup.TargetDespawnedBehavior.Stop:
|
||
|
|
GrpVariation.Stop();
|
||
|
|
break;
|
||
|
|
case MasterAudioGroup.TargetDespawnedBehavior.FadeOut:
|
||
|
|
GrpVariation.FadeOutNowAndStop(ParentGroup.despawnFadeTime);
|
||
|
|
break;
|
||
|
|
}
|
||
|
|
|
||
|
|
StopFollowing();
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
// fade in out / out early etc.
|
||
|
|
PerformFading();
|
||
|
|
|
||
|
|
// priority
|
||
|
|
UpdateAudioLocationAndPriority(true);
|
||
|
|
|
||
|
|
// occlusion
|
||
|
|
UpdateOcclusion();
|
||
|
|
|
||
|
|
// pitch
|
||
|
|
UpdatePitch();
|
||
|
|
|
||
|
|
|
||
|
|
switch (_waitMode) {
|
||
|
|
case WaitForSoundFinishMode.None:
|
||
|
|
break;
|
||
|
|
case WaitForSoundFinishMode.Play:
|
||
|
|
PlaySoundAndWait();
|
||
|
|
break;
|
||
|
|
case WaitForSoundFinishMode.WaitForEnd:
|
||
|
|
if (_isPaused) {
|
||
|
|
break;
|
||
|
|
}
|
||
|
|
|
||
|
|
if (_clipSchedEndTime.HasValue) {
|
||
|
|
if (AudioSettings.dspTime + TimeEarlyToScheduleNextClip >= _clipSchedEndTime.Value) {
|
||
|
|
if (GrpVariation.PlaySoundParm.IsChainLoop && !_hasScheduledNextClip) {
|
||
|
|
MaybeChain();
|
||
|
|
_hasScheduledNextClip = true;
|
||
|
|
}
|
||
|
|
if (HasEndLinkedGroups && !_hasScheduledEndLinkedGroups) {
|
||
|
|
GrpVariation.PlayEndLinkedGroups(_clipSchedEndTime.Value);
|
||
|
|
_hasScheduledEndLinkedGroups = true;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
var willChangeModes = false;
|
||
|
|
|
||
|
|
if (_isPlayingBackward) {
|
||
|
|
if (VarAudio.time > _lastFrameClipTime) {
|
||
|
|
willChangeModes = true;
|
||
|
|
}
|
||
|
|
} else {
|
||
|
|
if (VarAudio.time < _lastFrameClipTime) {
|
||
|
|
willChangeModes = true;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
_lastFrameClipTime = VarAudio.time;
|
||
|
|
|
||
|
|
if (willChangeModes) {
|
||
|
|
_waitMode = WaitForSoundFinishMode.StopOrRepeat;
|
||
|
|
}
|
||
|
|
break;
|
||
|
|
case WaitForSoundFinishMode.StopOrRepeat:
|
||
|
|
StopOrChain();
|
||
|
|
break;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
#endregion
|
||
|
|
|
||
|
|
#region Properties
|
||
|
|
|
||
|
|
public float ClipStartPosition {
|
||
|
|
get {
|
||
|
|
if (_clipStartPosition.HasValue) {
|
||
|
|
return _clipStartPosition.Value;
|
||
|
|
}
|
||
|
|
|
||
|
|
if (GrpVariation.useRandomStartTime) {
|
||
|
|
_clipStartPosition = Random.Range(GrpVariation.randomStartMinPercent, GrpVariation.randomStartMaxPercent) * 0.01f * VarAudio.clip.length;
|
||
|
|
} else {
|
||
|
|
_clipStartPosition = 0f;
|
||
|
|
}
|
||
|
|
|
||
|
|
return _clipStartPosition.Value;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
public float ClipEndPosition {
|
||
|
|
get {
|
||
|
|
if (_clipEndPosition.HasValue) {
|
||
|
|
return _clipEndPosition.Value;
|
||
|
|
}
|
||
|
|
|
||
|
|
if (GrpVariation.useRandomStartTime) {
|
||
|
|
_clipEndPosition = GrpVariation.randomEndPercent * 0.01f * VarAudio.clip.length;
|
||
|
|
} else {
|
||
|
|
_clipEndPosition = VarAudio.clip.length;
|
||
|
|
}
|
||
|
|
|
||
|
|
return _clipEndPosition.Value;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
public int FramesPlayed {
|
||
|
|
get {
|
||
|
|
return _framesPlayed;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
public MasterAudio MAThisFrame {
|
||
|
|
get {
|
||
|
|
return _maThisFrame;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
public float MaxOcclusionFreq {
|
||
|
|
get {
|
||
|
|
// ReSharper disable once InvertIf
|
||
|
|
if (GrpVariation.UsesOcclusion && ParentGroup.willOcclusionOverrideFrequencies) {
|
||
|
|
return ParentGroup.occlusionMaxCutoffFreq;
|
||
|
|
}
|
||
|
|
|
||
|
|
return _maThisFrame.occlusionMaxCutoffFreq;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
public float MinOcclusionFreq {
|
||
|
|
get {
|
||
|
|
// ReSharper disable once InvertIf
|
||
|
|
if (GrpVariation.UsesOcclusion && ParentGroup.willOcclusionOverrideFrequencies) {
|
||
|
|
return ParentGroup.occlusionMinCutoffFreq;
|
||
|
|
}
|
||
|
|
|
||
|
|
return _maThisFrame.occlusionMinCutoffFreq;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
private Transform Trans {
|
||
|
|
get {
|
||
|
|
if (_trans != null) {
|
||
|
|
return _trans;
|
||
|
|
}
|
||
|
|
|
||
|
|
_trans = GrpVariation.Trans;
|
||
|
|
|
||
|
|
return _trans;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
private AudioSource VarAudio {
|
||
|
|
get {
|
||
|
|
if (_varAudio != null) {
|
||
|
|
return _varAudio;
|
||
|
|
}
|
||
|
|
|
||
|
|
_varAudio = GrpVariation.VarAudio;
|
||
|
|
|
||
|
|
return _varAudio;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
private MasterAudioGroup ParentGroup {
|
||
|
|
get {
|
||
|
|
if (_parentGrp != null) {
|
||
|
|
return _parentGrp;
|
||
|
|
}
|
||
|
|
|
||
|
|
_parentGrp = GrpVariation.ParentGroup;
|
||
|
|
|
||
|
|
return _parentGrp;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
private SoundGroupVariation GrpVariation {
|
||
|
|
get {
|
||
|
|
if (_variation != null) {
|
||
|
|
return _variation;
|
||
|
|
}
|
||
|
|
|
||
|
|
_variation = GetComponent<SoundGroupVariation>();
|
||
|
|
|
||
|
|
return _variation;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
private float RayCastOriginOffset {
|
||
|
|
get {
|
||
|
|
// ReSharper disable once InvertIf
|
||
|
|
if (GrpVariation.UsesOcclusion && ParentGroup.willOcclusionOverrideRaycastOffset) {
|
||
|
|
return ParentGroup.occlusionRayCastOffset;
|
||
|
|
}
|
||
|
|
|
||
|
|
return _maThisFrame.occlusionRayCastOffset;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
private bool IsOcclusionMeasuringPaused {
|
||
|
|
get { return _isWaitingForQueuedOcclusionRay || MasterAudio.IsOcclusionFrequencyTransitioning(GrpVariation); }
|
||
|
|
}
|
||
|
|
|
||
|
|
private bool HasEndLinkedGroups {
|
||
|
|
get {
|
||
|
|
if (GrpVariation.ParentGroup.endLinkedGroups.Count > 0) {
|
||
|
|
return true;
|
||
|
|
}
|
||
|
|
|
||
|
|
return false;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
#endregion
|
||
|
|
}
|
||
|
|
}
|
||
|
|
/*! \endcond */
|