using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.Audio;
using QFSW.MOP2;
using UnityEngine.SceneManagement;
using Sirenix.OdinInspector;
namespace KairoEngine.SFX
{
// Todo: Remove playing SFX on scene change
public class SoundEmitter : MonoBehaviour
{
public SphereCollider trigger;
public AudioSource audioSource;
[ReadOnly]
public AudioClip audioClip;
public SFXClip sfx;
public string soundEmitterPrefabPool = "";
private float fadeInTime;
private float fadeOutTime;
private Coroutine fadeOutCoroutine;
private bool done = false;
///
/// play a sound at a location in the world using an Audio Clip.
///
/// The audio clip to be played
/// The Vector3 position to play the sound in the world
/// Audio clip volume
/// Radius for SoundSensors
/// Audio Mixer Channel
/// Trigger SoundSensors in world?
public void Initialize(AudioClip audioClip, Vector3 location, float volume, float radius, AudioMixerGroup audioMixerGroup, bool world = true)
{
this.audioClip = audioClip;
this.trigger.radius = radius;
transform.position = location;
this.audioSource.volume = volume;
this.audioSource.outputAudioMixerGroup = audioMixerGroup;
this.audioSource.clip = this.audioClip;
this.done = false;
if(world == false)
{
trigger.enabled = false;
}
this.audioSource.Play();
}
///
/// Play a sound at a location in the world using a SFX Clip.
///
/// SFX Clip with audio clip and parameters.
/// Vector3 representing the location to play the sound.
public void Initialize(SFXClip sfx, Vector3 location)
{
this.sfx = sfx;
this.done = false;
// Audio Clip
if(sfx.sfxType == SFXClipType.Single)
{
// Single
this.audioClip = sfx.clip;
}
else if(sfx.sfxType == SFXClipType.RandomList)
{
// Random from list
this.audioClip = sfx.clips[Random.Range(0, sfx.clips.Count)];
}
this.audioSource.clip = this.audioClip;
// Sound Location
transform.position = location;
// Audio Mixer Channel
this.audioSource.outputAudioMixerGroup = sfx.audioMixerChannel;
// Loop
if(sfx.sfxType == SFXClipType.Single) this.audioSource.loop = sfx.loop;
// Volume
this.audioSource.volume = sfx.volume + Random.Range(-sfx.volumeVariation, sfx.volumeVariation);
// Pitch
this.audioSource.pitch = sfx.pitch + Random.Range(-sfx.pitchVariation, sfx.pitchVariation);
// Spatial or stereo audio
if(sfx.soundSpace != SFXSpace.Stereo)
{
this.audioSource.spatialize = true;
}
else
{
this.audioSource.spatialize = false;
this.audioSource.spatialBlend = 0;
}
// Pan
if(sfx.soundSpace != SFXSpace.GameWorld)
{
// Stereo audio Pan
this.audioSource.panStereo = sfx.pan + Random.Range(-sfx.panVariation, sfx.panVariation);
}
else
{
// 3D audio has no Pan
this.audioSource.panStereo = 0;
}
// Spatial Blend
if(sfx.soundSpace == SFXSpace.Mix)
{
this.audioSource.spatialBlend = sfx.spatialBlend + Random.Range(-sfx.spatialBlendVariation, sfx.spatialBlendVariation);
}
// Set Distance
if(sfx.soundSpace == SFXSpace.GameWorld || sfx.soundSpace == SFXSpace.Mix)
{
this.audioSource.minDistance = sfx.minDistance;
this.audioSource.maxDistance = sfx.maxDistance;
}
// Use world sensor
if(sfx.sensorDetection == true)
{
trigger.enabled = true;
this.trigger.radius = sfx.soundRadius;
}
else trigger.enabled = true;
// Set Fade In
if(sfx.fadeIn)
{
this.audioSource.volume = 0f;
this.fadeInTime = 0f;
StartCoroutine(FadeIn());
}
// Set Fade out
if(sfx.fadeOut)
{
fadeOutTime = 0f;
fadeOutCoroutine = StartCoroutine(FadeOut());
}
// Set Remove on scene change
// ! Turn this on when dependencies are solved
//if(sfx.removeOnSceneChange) TransitionEvents.OnChangeScene += OnSceneChanged;
// Trim and Play the audio clip
if(sfx.trim) this.audioSource.time = sfx.trimStartDuration;
this.audioSource.Play();
if(sfx.trim) this.audioSource.SetScheduledEndTime(AudioSettings.dspTime +(sfx.trimEndDuration - sfx.trimStartDuration));
}
void Update()
{
if(done == true) return;
// Destroy this Gameobject when the sound is done playing
if(audioSource.isPlaying == false)
{
if(sfx == null) return;
if(sfx.loop && sfx.sfxType == SFXClipType.RandomList)
{
Initialize(sfx, transform.position);
}
else
{
Remove();
}
}
}
private void Remove()
{
SoundController.soundEmitters.Remove(this);
// ! Enable when dependencies are resolved
//if(sfx.removeOnSceneChange) TransitionEvents.OnChangeScene -= OnSceneChanged;
sfx = null;
if(MasterObjectPooler.Instance != null && soundEmitterPrefabPool != "") MasterObjectPooler.Instance.GetPool(soundEmitterPrefabPool).Release(this.gameObject);
else Destroy(this.gameObject);
}
IEnumerator FadeIn()
{
float start = Time.realtimeSinceStartup;
while(Time.realtimeSinceStartup <= (start + (sfx.fadeInDuration)))
{
fadeInTime = (Time.realtimeSinceStartup - start);
this.audioSource.volume = Mathf.Lerp(0, 1, fadeInTime/sfx.fadeInDuration);
yield return null;
}
this.audioSource.volume = 1;
}
IEnumerator FadeOut(bool wait = true, bool remove = false, float time = 0)
{
fadeOutTime = 0f;
if(time == 0) time = sfx.fadeOutDuration;
if(wait) yield return new WaitForSecondsRealtime((this.audioSource.clip.length - this.audioSource.time) - time);
if(sfx == null) yield return 0;
float start = Time.realtimeSinceStartup;
while(Time.realtimeSinceStartup < (start + (time)))
{
fadeOutTime = (Time.realtimeSinceStartup - start);
this.audioSource.volume = Mathf.Lerp(1, 0, fadeOutTime/time);
yield return null;
}
this.audioSource.volume = 0;
if(remove) Remove();
}
// ! Enable when dependencies are solved
/*
private void OnSceneChanged(SceneChangeData sceneData, float time)
{
StopCoroutine(fadeOutCoroutine);
done = true;
if(sfx == null) return;
if(sfx.fadeOut) StartCoroutine(FadeOut(false, true, time));
else Remove();
}
*/
}
}