public virtual void Awake() { transform = new Components.Transform(); }
/// <summary> /// Updates the SoundInstance /// </summary> public void Update() { // Check existence of attachTo object if (this.attachedTo != null && this.attachedTo.Disposed) { this.attachedTo = null; } // Retrieve sound resource values Sound soundRes = this.sound.Res; AudioData audioDataRes = this.audioData.Res; if (soundRes == null || audioDataRes == null) { this.Dispose(); return; } // Set up local variables for state calculation Vector3 listenerPos = DualityApp.Sound.ListenerPos; bool attachedToListener = this.attachedTo != null && ((this.attachedTo == DualityApp.Sound.Listener) || this.attachedTo.IsChildOf(DualityApp.Sound.Listener)); float optVolFactor = this.GetTypeVolFactor(); float priorityTemp = 1000.0f; AudioSourceState nativeState = AudioSourceState.Default; nativeState.MinDistance = soundRes.MinDist; nativeState.MaxDistance = soundRes.MaxDist; nativeState.Volume = optVolFactor * soundRes.VolumeFactor * this.vol * this.curFade * this.pauseFade; nativeState.Pitch = soundRes.PitchFactor * this.pitch; nativeState.Lowpass = soundRes.LowpassFactor * this.lowpass; priorityTemp *= nativeState.Volume; // Calculate 3D source values, distance and priority nativeState.Position = this.pos; nativeState.Velocity = this.vel; if (this.is3D) { Components.Transform attachTransform = this.attachedTo != null ? this.attachedTo.Transform : null; // Attach to object if (this.attachedTo != null) { MathF.TransformCoord(ref nativeState.Position.X, ref nativeState.Position.Y, attachTransform.Angle); MathF.TransformCoord(ref nativeState.Velocity.X, ref nativeState.Velocity.Y, attachTransform.Angle); nativeState.Position += attachTransform.Pos; nativeState.Velocity += attachTransform.Vel; } // Distance check float dist = MathF.Sqrt( (nativeState.Position.X - listenerPos.X) * (nativeState.Position.X - listenerPos.X) + (nativeState.Position.Y - listenerPos.Y) * (nativeState.Position.Y - listenerPos.Y) + (nativeState.Position.Z - listenerPos.Z) * (nativeState.Position.Z - listenerPos.Z) * 0.25f); if (dist > nativeState.MaxDistance) { this.Dispose(); return; } else { priorityTemp *= Math.Max(0.0f, 1.0f - (dist - nativeState.MinDistance) / (nativeState.MaxDistance - nativeState.MinDistance)); } } if (this.notYetAssigned) { // Grab a native audio source if (this.GrabNativeSource()) { this.RegisterPlaying(); } // If there is none available, just stop right there. else { this.Dispose(); return; } } // If the source is stopped / finished, dispose and return if (this.native == null || this.native.IsFinished) { this.Dispose(); return; } // Fading in and out bool fadeOut = this.fadeTarget <= 0.0f; if (!this.paused) { if (this.fadeTarget != this.curFade) { float fadeTemp = Time.TimeMult * Time.SPFMult / Math.Max(0.05f, this.fadeTimeSec); if (this.fadeTarget > this.curFade) { this.curFade += fadeTemp; } else { this.curFade -= fadeTemp; } if (Math.Abs(this.curFade - this.fadeTarget) < fadeTemp * 2.0f) { this.curFade = this.fadeTarget; } } } // Special paused-fading if (this.paused && this.pauseFade > 0.0f) { this.pauseFade = MathF.Max(0.0f, this.pauseFade - Time.TimeMult * Time.SPFMult * 5.0f); } else if (!this.paused && this.pauseFade < 1.0f) { this.pauseFade = MathF.Min(1.0f, this.pauseFade + Time.TimeMult * Time.SPFMult * 5.0f); } // Apply the sounds state to its internal native audio source if (this.native != null) { if (this.is3D) { nativeState.RelativeToListener = attachedToListener; if (attachedToListener) { nativeState.Position -= listenerPos; } // Convert from Duality units to (physical) audio backend units. nativeState.Position *= AudioUnit.LengthToPhysical; nativeState.Velocity *= AudioUnit.VelocityToPhysical; nativeState.MinDistance *= AudioUnit.LengthToPhysical; nativeState.MaxDistance *= AudioUnit.LengthToPhysical; // Post-process sound instance data in listener space float listenerAngle = DualityApp.Sound.ListenerAngle; Vector3 adjustedPos = nativeState.RelativeToListener ? nativeState.Position : nativeState.Position - listenerPos * AudioUnit.LengthToPhysical; MathF.TransformCoord(ref adjustedPos.X, ref adjustedPos.Z, -listenerAngle); // Flatten depth position a little, so far away sounds that can still be seen appear louder adjustedPos.Z *= 0.5f; // Normalize audio position for smooth panning when near. Do it in physical // units, so this remains constant regardless of unit changes. float smoothPanRadius = 5.0f; float listenerSpaceDist = adjustedPos.Length; if (listenerSpaceDist < smoothPanRadius) { float panningActive = listenerSpaceDist / smoothPanRadius; adjustedPos = Vector3.Lerp( new Vector3(0.0f, 0.0f, 1.0f + (smoothPanRadius - 1.0f) * panningActive), adjustedPos, panningActive); } MathF.TransformCoord(ref adjustedPos.X, ref adjustedPos.Z, listenerAngle); nativeState.Position = nativeState.RelativeToListener ? adjustedPos : adjustedPos + listenerPos * AudioUnit.LengthToPhysical; } else { // We'll do a +/- 30° panning for 2D audio Vector2 localPos = Vector2.FromAngleLength( MathF.DegToRad(30.0f * this.panning), 1.0f); nativeState.RelativeToListener = true; nativeState.Position = new Vector3(localPos.X, 0.0f, -localPos.Y); nativeState.Velocity = Vector3.Zero; } nativeState.Looped = this.looped; nativeState.Paused = this.paused && this.pauseFade == 0.0f; this.native.ApplyState(ref nativeState); } // Update play time if (!this.paused) { this.playTime += MathF.Max(0.5f, nativeState.Pitch) * Time.TimeMult * Time.SPFMult; if (this.sound.Res.FadeOutAt > 0.0f && this.playTime >= this.sound.Res.FadeOutAt) { this.FadeOut(this.sound.Res.FadeOutTime); } } // Finish priority calculation this.curPriority = (int)Math.Round(priorityTemp / Math.Sqrt(DualityApp.Sound.GetNumPlaying(this.sound))); // Initially play the source if (this.native.IsInitial && !this.paused) { if (audioDataRes.IsStreamed) { this.native.Play(this); } else if (audioDataRes.Native != null) { this.native.Play(audioDataRes.Native); } } // Remove faded out sources if (fadeOut && nativeState.Volume <= 0.0f) { this.fadeWaitEnd += Time.TimeMult * Time.MsPFMult; // After fading out entirely, wait 50 ms before actually stopping the source to prevent unpleasant audio tick / glitch noises if (this.fadeWaitEnd > 50.0f) { this.Dispose(); return; } } else { this.fadeWaitEnd = 0.0f; } }
/// <summary> /// Updates the SoundInstance /// </summary> public void Update() { // Check existence of attachTo object if (this.attachedTo != null && this.attachedTo.Disposed) { this.attachedTo = null; } // Retrieve sound resource values Sound soundRes = this.sound.Res; AudioData audioDataRes = this.audioData.Res; if (soundRes == null || audioDataRes == null) { this.Dispose(); return; } // Set up local variables for state calculation Vector3 listenerPos = DualityApp.Sound.ListenerPos; bool attachedToListener = this.attachedTo != null && ((this.attachedTo == DualityApp.Sound.Listener) || this.attachedTo.IsChildOf(DualityApp.Sound.Listener)); float optVolFactor = this.GetTypeVolFactor(); float priorityTemp = 1000.0f; AudioSourceState nativeState = AudioSourceState.Default; nativeState.MinDistance = soundRes.MinDist; nativeState.MaxDistance = soundRes.MaxDist; nativeState.Volume = optVolFactor * soundRes.VolumeFactor * this.vol * this.curFade * this.pauseFade; nativeState.Pitch = soundRes.PitchFactor * this.pitch; nativeState.Lowpass = soundRes.LowpassFactor * this.lowpass; priorityTemp *= nativeState.Volume; // Calculate 3D source values, distance and priority nativeState.Position = this.pos; nativeState.Velocity = this.vel; if (this.is3D) { Components.Transform attachTransform = this.attachedTo != null ? this.attachedTo.Transform : null; // Attach to object if (this.attachedTo != null) { MathF.TransformCoord(ref nativeState.Position.X, ref nativeState.Position.Y, attachTransform.Angle); MathF.TransformCoord(ref nativeState.Velocity.X, ref nativeState.Velocity.Y, attachTransform.Angle); nativeState.Position += attachTransform.Pos; nativeState.Velocity += attachTransform.Vel; } // Distance check float dist = MathF.Sqrt( (nativeState.Position.X - listenerPos.X) * (nativeState.Position.X - listenerPos.X) + (nativeState.Position.Y - listenerPos.Y) * (nativeState.Position.Y - listenerPos.Y) + (nativeState.Position.Z - listenerPos.Z) * (nativeState.Position.Z - listenerPos.Z) * 0.25f); if (dist > nativeState.MaxDistance) { this.Dispose(); return; } else { priorityTemp *= Math.Max(0.0f, 1.0f - (dist - nativeState.MinDistance) / (nativeState.MaxDistance - nativeState.MinDistance)); } } if (this.notYetAssigned) { // Grab a native audio source if (this.GrabNativeSource()) { this.RegisterPlaying(); } // If there is none available, just stop right there. else { this.Dispose(); return; } } // If the source is stopped / finished, dispose and return if (this.native == null || this.native.IsFinished) { this.Dispose(); return; } // Fading in and out bool fadeOut = this.fadeTarget <= 0.0f; if (!this.paused) { if (this.fadeTarget != this.curFade) { float fadeTemp = Time.TimeMult * Time.SPFMult / Math.Max(0.05f, this.fadeTimeSec); if (this.fadeTarget > this.curFade) { this.curFade += fadeTemp; } else { this.curFade -= fadeTemp; } if (Math.Abs(this.curFade - this.fadeTarget) < fadeTemp * 2.0f) { this.curFade = this.fadeTarget; } } } // Special paused-fading if (this.paused && this.pauseFade > 0.0f) { this.pauseFade = MathF.Max(0.0f, this.pauseFade - Time.TimeMult * Time.SPFMult * 5.0f); } else if (!this.paused && this.pauseFade < 1.0f) { this.pauseFade = MathF.Min(1.0f, this.pauseFade + Time.TimeMult * Time.SPFMult * 5.0f); } // Apply the sounds state to its internal native audio source if (this.native != null) { if (this.is3D) { nativeState.RelativeToListener = attachedToListener; if (attachedToListener) { nativeState.Position -= listenerPos; } } else { nativeState.RelativeToListener = true; nativeState.Position = new Vector3(this.panning, 0.0f, 0.0f); nativeState.Velocity = Vector3.Zero; } nativeState.Looped = this.looped; nativeState.Paused = this.paused && this.pauseFade == 0.0f; this.native.ApplyState(ref nativeState); } // Update play time if (!this.paused) { this.playTime += MathF.Max(0.5f, nativeState.Pitch) * Time.TimeMult * Time.SPFMult; if (this.sound.Res.FadeOutAt > 0.0f && this.playTime >= this.sound.Res.FadeOutAt) { this.FadeOut(this.sound.Res.FadeOutTime); } } // Finish priority calculation this.curPriority = (int)Math.Round(priorityTemp / Math.Sqrt(DualityApp.Sound.GetNumPlaying(this.sound))); // Initially play the source if (this.native.IsInitial && !this.paused) { if (audioDataRes.IsStreamed) { this.native.Play(this); } else if (audioDataRes.Native != null) { this.native.Play(audioDataRes.Native); } } // Remove faded out sources if (fadeOut && nativeState.Volume <= 0.0f) { this.fadeWaitEnd += Time.TimeMult * Time.MsPFMult; // After fading out entirely, wait 50 ms before actually stopping the source to prevent unpleasant audio tick / glitch noises if (this.fadeWaitEnd > 50.0f) { this.Dispose(); return; } } else { this.fadeWaitEnd = 0.0f; } }