public static AudioClip PopulateResourceSongToPlaylistController(string controllerName, string songResourceName, string playlistName) { var resAudioClip = Resources.Load(songResourceName) as AudioClip; if (resAudioClip == null) { MasterAudio.LogWarning("Resource file '" + songResourceName + "' could not be located from Playlist '" + playlistName + "'."); return(null); } if (!AudioUtil.AudioClipWillPreload(resAudioClip)) { MasterAudio.LogWarning("Audio Clip for Resource file '" + songResourceName + "' from Playlist '" + playlistName + "' has 'Preload Audio Data' turned off, which can cause audio glitches. Resource files should always Preload Audio Data. Please turn it on."); } FinishRecordingPlaylistClip(controllerName, resAudioClip); return(resAudioClip); }
/// <summary> /// Populates the sources with resource clip. /// </summary> /// <returns><c>true</c>, if sources with resource clip was populated, <c>false</c> otherwise.</returns> /// <param name="clipName">Clip name.</param> /// <param name="variation">Variation.</param> public static bool PopulateSourcesWithResourceClip(string clipName, SoundGroupVariation variation) { if (AudioClipsByName.ContainsKey(clipName)) { //MasterAudio.Log("clip already exists: " + clipName); return(true); // work is done already! } var resAudioClip = Resources.Load(clipName) as AudioClip; if (resAudioClip == null) { MasterAudio.LogError("Resource file '" + clipName + "' could not be located."); return(false); } if (!AudioResourceTargetsByName.ContainsKey(clipName)) { MasterAudio.LogError("No Audio Sources found to add Resource file '" + clipName + "'."); return(false); } var sources = AudioResourceTargetsByName[clipName]; // ReSharper disable once ForCanBeConvertedToForeach for (var i = 0; i < sources.Count; i++) { sources[i].clip = resAudioClip; } if (!AudioUtil.AudioClipWillPreload(resAudioClip)) { MasterAudio.LogWarning("Audio Clip for Resource file '" + clipName + "' of Sound Group '" + variation.ParentGroup.name + "' has 'Preload Audio Data' turned off, which can cause audio glitches. Resource files should always Preload Audio Data. Please turn it on."); } AudioClipsByName.Add(clipName, resAudioClip); return(true); }
/// <summary> /// Populates the sources with resource clip, non-thread blocking. /// </summary> /// <param name="clipName">Clip name.</param> /// <param name="variation">Variation.</param> /// <param name="successAction">Method to execute if successful.</param> /// <param name="failureAction">Method to execute if not successful.</param> public static IEnumerator PopulateSourcesWithResourceClipAsync(string clipName, SoundGroupVariation variation, // ReSharper disable RedundantNameQualifier System.Action successAction, System.Action failureAction) { // ReSharper restore RedundantNameQualifier if (AudioClipsByName.ContainsKey(clipName)) { if (successAction != null) { successAction(); } yield break; } var asyncRes = Resources.LoadAsync(clipName, typeof(AudioClip)); while (!asyncRes.isDone) { yield return(MasterAudio.EndOfFrameDelay); } var resAudioClip = asyncRes.asset as AudioClip; if (resAudioClip == null) { MasterAudio.LogError("Resource file '" + clipName + "' could not be located."); if (failureAction != null) { failureAction(); } yield break; } if (!AudioResourceTargetsByName.ContainsKey(clipName)) { MasterAudio.LogError("No Audio Sources found to add Resource file '" + clipName + "'."); if (failureAction != null) { failureAction(); } yield break; } if (!AudioUtil.AudioClipWillPreload(resAudioClip)) { MasterAudio.LogWarning("Audio Clip for Resource file '" + clipName + "' of Sound Group '" + variation.ParentGroup.name + "' has 'Preload Audio Data' turned off, which can cause audio glitches. Resource files should always Preload Audio Data. Please turn it on."); } var sources = AudioResourceTargetsByName[clipName]; // ReSharper disable once ForCanBeConvertedToForeach for (var i = 0; i < sources.Count; i++) { sources[i].clip = resAudioClip; } if (!AudioClipsByName.ContainsKey(clipName)) { AudioClipsByName.Add(clipName, resAudioClip); } if (successAction != null) { successAction(); } }
private static readonly object _syncRoot = new object(); // to lock below /// <summary> /// Start Coroutine when calling this, passing in success and failure action delegates. /// </summary> /// <param name="addressable"></param> /// <param name="variation"></param> /// <param name="successAction"></param> /// <param name="failureAction"></param> /// <returns></returns> public static IEnumerator PopulateSourceWithAddressableClipAsync(AssetReference addressable, SoundGroupVariation variation, int unusedSecondsLifespan, System.Action successAction, System.Action failureAction) { var isWarmingCall = MasterAudio.IsWarming; // since this may change by the time we load the asset, we store it so we can know. if (!IsAddressableValid(addressable)) { if (failureAction != null) { failureAction(); } if (isWarmingCall) { DTMonoHelper.SetActive(variation.GameObj, false); // should disable itself } yield break; } var addressableId = GetAddressableId(addressable); AsyncOperationHandle <AudioClip> loadHandle; AudioClip addressableClip; var shouldReleaseLoadedAssetNow = false; if (AddressableTasksByAddressibleId.ContainsKey(addressableId)) { loadHandle = AddressableTasksByAddressibleId[addressableId].AssetHandle; addressableClip = loadHandle.Result; } else { loadHandle = addressable.LoadAssetAsync <AudioClip>(); while (!loadHandle.IsDone) { yield return(MasterAudio.EndOfFrameDelay); } addressableClip = loadHandle.Result; if (addressableClip == null || loadHandle.Status != AsyncOperationStatus.Succeeded) { var errorText = ""; if (loadHandle.OperationException != null) { errorText = " Exception: " + loadHandle.OperationException.Message; } MasterAudio.LogError("Addressable file for '" + variation.name + "' could not be located." + errorText); if (failureAction != null) { failureAction(); } if (isWarmingCall) { DTMonoHelper.SetActive(variation.GameObj, false); // should disable itself } yield break; } lock (_syncRoot) { if (!AddressableTasksByAddressibleId.ContainsKey(addressableId)) { AddressableTasksByAddressibleId.Add(addressableId, new AddressableTracker <AudioClip>(loadHandle, unusedSecondsLifespan)); } else { // race condition reached. Another load finished before this one. Throw this away and use the other, to release memory. shouldReleaseLoadedAssetNow = true; addressableClip = AddressableTasksByAddressibleId[addressableId].AssetHandle.Result; } } } if (shouldReleaseLoadedAssetNow) { Addressables.Release(loadHandle); } if (!AudioUtil.AudioClipWillPreload(addressableClip)) { MasterAudio.LogWarning("Audio Clip for Addressable file '" + addressableClip.name + "' of Sound Group '" + variation.ParentGroup.name + "' has 'Preload Audio Data' turned off, which can cause audio glitches. Addressables should always Preload Audio Data. Please turn it on."); } variation.LoadStatus = MasterAudio.VariationLoadStatus.Loaded; var stoppedBeforePlay = variation.IsStopRequested; if (stoppedBeforePlay) { // do nothing, but don't call the delegate or set audio clip for sure! } else { variation.VarAudio.clip = addressableClip; if (successAction != null) { successAction(); } } }
public static IEnumerator PopulateAddressableSongToPlaylistControllerAsync(MusicSetting setting, AssetReference addressable, PlaylistController playlistController, PlaylistController.AudioPlayType playType) { if (!IsAddressableValid(addressable)) { yield break; } var addressableId = GetAddressableId(addressable); AsyncOperationHandle <AudioClip> loadHandle; AudioClip addressableClip; var shouldReleaseLoadedAssetNow = false; if (AddressableTasksByAddressibleId.ContainsKey(addressableId)) { loadHandle = AddressableTasksByAddressibleId[addressableId].AssetHandle; addressableClip = loadHandle.Result; } else { loadHandle = addressable.LoadAssetAsync <AudioClip>(); while (!loadHandle.IsDone) { yield return(MasterAudio.EndOfFrameDelay); } addressableClip = loadHandle.Result; if (addressableClip == null || loadHandle.Status != AsyncOperationStatus.Succeeded) { var errorText = ""; if (loadHandle.OperationException != null) { errorText = " Exception: " + loadHandle.OperationException.Message; } MasterAudio.LogError("Addressable file for PlaylistController '" + playlistController.name + "' could not be located." + errorText); yield break; } lock (_syncRoot) { if (!AddressableTasksByAddressibleId.ContainsKey(addressableId)) { AddressableTasksByAddressibleId.Add(addressableId, new AddressableTracker <AudioClip>(loadHandle, 0)); } else { // race condition reached. Another load finished before this one. Throw this away and use the other, to release memory. shouldReleaseLoadedAssetNow = true; addressableClip = AddressableTasksByAddressibleId[addressableId].AssetHandle.Result; } } } if (shouldReleaseLoadedAssetNow) { Addressables.Release(loadHandle); } if (!AudioUtil.AudioClipWillPreload(addressableClip)) { MasterAudio.LogWarning("Audio Clip for Addressable file '" + addressableClip.name + "' of Playlist Controller '" + playlistController.name + "' has 'Preload Audio Data' turned off, which can cause audio glitches. Addressables should always Preload Audio Data. Please turn it on."); } // Figure out how to detect stop before loaded, if needed var stoppedBeforePlay = false; if (stoppedBeforePlay) { // do nothing, but don't call the delegate or set audio clip for sure! } else { playlistController.FinishLoadingNewSong(setting, addressableClip, playType); } }
private void UpdateOcclusion() { var hasOcclusionOn = GrpVariation.UsesOcclusion; if (!hasOcclusionOn) { if (!_occlusionOnLastFrame) { return; } _occlusionOnLastFrame = false; MasterAudio.StopTrackingOcclusionForSource(GrpVariation.GameObj); ResetToNonOcclusionSetting(); return; } _occlusionOnLastFrame = true; if (_listenerThisFrame == null) { // cannot occlude without something to raycast at. return; } if (Time.realtimeSinceStartup - _occlusionLastCalculated <= MasterAudio.ReOccludeCheckTime) { // too early, abort and try next frame return; } var lastCalcTime = Time.realtimeSinceStartup; if (_occlusionLastCalculated == FakeNegativeFloatValue) { // spread out the line casts so they're not all on the same frame (for ambient sounds that all start in the Scene). lastCalcTime += MasterAudio.ReOccludeCheckTime * Random.Range(0f, 0.9f); } _occlusionLastCalculated = lastCalcTime; var direction = _listenerThisFrame.position - Trans.position; var distanceToListener = direction.magnitude; if (distanceToListener > VarAudio.maxDistance) { // out of hearing range, no reason to calculate occlusion. MasterAudio.AddToOcclusionOutOfRangeSources(GrpVariation.GameObj); ResetToNonOcclusionSetting(); return; } MasterAudio.AddToOcclusionInRangeSources(GrpVariation.GameObj); if (GrpVariation.LowPassFilter == null) { // in case Occlusion got turned on during runtime. GrpVariation.gameObject.AddComponent <AudioLowPassFilter>(); } #if UNITY_4_5 || UNITY_4_6 || UNITY_4_7 || UNITY_5_0 || UNITY_5_1 #else var is2DRaycast = _maThisFrame.occlusionRaycastMode == MasterAudio.RaycastMode.Physics2D; var oldQueriesStart = Physics2D.queriesStartInColliders; if (is2DRaycast) { Physics2D.queriesStartInColliders = _maThisFrame.occlusionIncludeStartRaycast2DCollider; } #endif var hitPoint = Vector3.zero; float?hitDistance = null; var isHit = false; if (_maThisFrame.occlusionUseLayerMask) { switch (_maThisFrame.occlusionRaycastMode) { case MasterAudio.RaycastMode.Physics3D: RaycastHit hitObject; if (Physics.Raycast(Trans.position, direction, out hitObject, distanceToListener, _maThisFrame.occlusionLayerMask.value)) { isHit = true; hitPoint = hitObject.point; hitDistance = hitObject.distance; } break; case MasterAudio.RaycastMode.Physics2D: var castHit2D = Physics2D.Raycast(Trans.position, direction, distanceToListener, _maThisFrame.occlusionLayerMask.value); if (castHit2D.transform != null) { isHit = true; hitPoint = castHit2D.point; hitDistance = castHit2D.distance; } break; } } else { switch (_maThisFrame.occlusionRaycastMode) { case MasterAudio.RaycastMode.Physics3D: RaycastHit hitObject; if (Physics.Raycast(Trans.position, direction, out hitObject, distanceToListener)) { isHit = true; hitPoint = hitObject.point; hitDistance = hitObject.distance; } break; case MasterAudio.RaycastMode.Physics2D: var castHit2D = Physics2D.Raycast(Trans.position, direction, distanceToListener); if (castHit2D.transform != null) { isHit = true; hitPoint = castHit2D.point; hitDistance = castHit2D.distance; } break; } } #if UNITY_4_5 || UNITY_4_6 || UNITY_4_7 || UNITY_5_0 || UNITY_5_1 #else if (is2DRaycast) { Physics2D.queriesStartInColliders = oldQueriesStart; } #endif var endPoint = isHit ? hitPoint : _listenerThisFrame.position; var lineColor = isHit ? Color.red : Color.green; if (_maThisFrame.occlusionShowRaycasts) { Debug.DrawLine(Trans.position, endPoint, lineColor, .1f); } if (!isHit) { // ReSharper disable once PossibleNullReferenceException MasterAudio.RemoveFromBlockedOcclusionSources(GrpVariation.GameObj); ResetToNonOcclusionSetting(); return; } MasterAudio.AddToBlockedOcclusionSources(GrpVariation.GameObj); var ratioToEdgeOfSound = hitDistance.Value / VarAudio.maxDistance; var filterFrequency = AudioUtil.GetOcclusionCutoffFrequencyByDistanceRatio(ratioToEdgeOfSound); // ReSharper disable once PossibleNullReferenceException GrpVariation.LowPassFilter.cutoffFrequency = filterFrequency; }
/// <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; } var oldQueriesStart = Physics2D.queriesStartInColliders; if (is2DRaycast) { Physics2D.queriesStartInColliders = _maThisFrame.occlusionIncludeStartRaycast2DCollider; } var oldRaycastsHitTriggers = true; // ReSharper disable once ConvertIfStatementToConditionalTernaryExpression if (is2DRaycast) { oldRaycastsHitTriggers = Physics2D.queriesHitTriggers; Physics2D.queriesHitTriggers = _maThisFrame.occlusionRaycastsHitTriggers; } else { oldRaycastsHitTriggers = Physics.queriesHitTriggers; Physics.queriesHitTriggers = _maThisFrame.occlusionRaycastsHitTriggers; } var hitPoint = Vector3.zero; float?hitDistance = null; var isHit = false; if (_maThisFrame.occlusionUseLayerMask) { switch (_maThisFrame.occlusionRaycastMode) { case MasterAudio.RaycastMode.Physics3D: RaycastHit hitObject; if (Physics.Raycast(raycastOrigin, direction, out hitObject, distanceToListener, _maThisFrame.occlusionLayerMask.value)) { isHit = true; hitPoint = hitObject.point; hitDistance = hitObject.distance; } break; case MasterAudio.RaycastMode.Physics2D: var castHit2D = Physics2D.Raycast(raycastOrigin, direction, distanceToListener, _maThisFrame.occlusionLayerMask.value); if (castHit2D.transform != null) { isHit = true; hitPoint = castHit2D.point; hitDistance = castHit2D.distance; } break; } } else { switch (_maThisFrame.occlusionRaycastMode) { case MasterAudio.RaycastMode.Physics3D: RaycastHit hitObject; if (Physics.Raycast(raycastOrigin, direction, out hitObject, distanceToListener)) { isHit = true; hitPoint = hitObject.point; hitDistance = hitObject.distance; } break; case MasterAudio.RaycastMode.Physics2D: var castHit2D = Physics2D.Raycast(raycastOrigin, direction, distanceToListener); if (castHit2D.transform != null) { isHit = true; hitPoint = castHit2D.point; hitDistance = castHit2D.distance; } break; } } if (is2DRaycast) { Physics2D.queriesStartInColliders = oldQueriesStart; Physics2D.queriesHitTriggers = oldRaycastsHitTriggers; } else { Physics.queriesHitTriggers = oldRaycastsHitTriggers; } 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; }