using UnityEngine; using UnityEngine.Audio; using System; using System.Collections; using System.Collections.Generic; public enum SoundType{ BGM, SE, Voice, } public class SoundManager : SingletonMonoBehaviour { private string bgmFilePath = ""; private AudioSource bgmSource = null; private float uniqueBGMVolume; public float UniqueBGMVolume { get{ return uniqueBGMVolume; } } private List seSourceList = new List(); private Dictionary seLoopSourceDic = new Dictionary(); private List voiceSourceList = new List(); public AudioMixerGroup defaultBGMAudioMixer; public AudioMixerGroup defaultSEAudioMixer; public AudioMixerGroup defaultVoiceAudioMixer; public float bgmVolume = 1.0f; public float seVolume = 1.0f; public float voiceVolume = 1.0f; public float pauseTime = 0.0f; public float GetVolume(SoundType soundType){ switch(soundType){ case SoundType.BGM: return bgmVolume; case SoundType.Voice: return voiceVolume; default: return seVolume; } } [SerializeField] private bool enabledBGM = true; [SerializeField] private bool enabledSE = true; [SerializeField] private bool enabledVoice = true; public void EnabledSound(SoundType soundType, bool enabled){ switch(soundType){ case SoundType.BGM: enabledBGM = enabled; break; case SoundType.Voice: enabledVoice = enabled; break; default: enabledSE = enabled; break; } } public bool IsEnabled(SoundType soundType){ switch(soundType){ case SoundType.BGM: return enabledBGM; case SoundType.Voice: return enabledVoice; default: return enabledSE; } } void Awake(){ if(CheckInstance()){ return; } #if !OLD_STORAGE enabledBGM = UsayaStorageManager.LoadOrDefault(UsayaStorageFilename.Settings_Data, "EnabledBGM", true); enabledSE = UsayaStorageManager.LoadOrDefault(UsayaStorageFilename.Settings_Data, "EnabledSE", true); enabledVoice = UsayaStorageManager.LoadOrDefault(UsayaStorageFilename.Settings_Data, "EnabledVoice", true); bgmVolume = UsayaStorageManager.LoadOrDefault(UsayaStorageFilename.Settings_Data, "VolumeBGM", bgmVolume); seVolume = UsayaStorageManager.LoadOrDefault(UsayaStorageFilename.Settings_Data, "VolumeSE", seVolume); voiceVolume = UsayaStorageManager.LoadOrDefault(UsayaStorageFilename.Settings_Data, "VolumeVoice", voiceVolume); #else if(UsayaStorageManager.Exists(UsayaStorageFilename.Settings_Data, "EnabledBGM")){ enabledBGM = UsayaStorageManager.Load(UsayaStorageFilename.Settings_Data, "EnabledBGM"); }else{ try{ if(StorageManager.Exists(StorageFilename.SettingsData, "EnabledBGM")){ enabledBGM = StorageManager.Load(StorageFilename.SettingsData, "EnabledBGM"); }else{ enabledBGM = DataManager.LoadOrDefault("EnabledBGM", true); } }catch{ enabledBGM = DataManager.LoadOrDefault("EnabledBGM", true); } } if(UsayaStorageManager.Exists(UsayaStorageFilename.Settings_Data, "EnabledSE")){ enabledSE = UsayaStorageManager.Load(UsayaStorageFilename.Settings_Data, "EnabledSE"); }else{ try{ if(StorageManager.Exists(StorageFilename.SettingsData, "EnabledSE")){ enabledSE = StorageManager.Load(StorageFilename.SettingsData, "EnabledSE"); }else{ enabledSE = DataManager.LoadOrDefault("EnabledSE", true); } }catch{ enabledSE = DataManager.LoadOrDefault("EnabledSE", true); } } if(UsayaStorageManager.Exists(UsayaStorageFilename.Settings_Data, "EnabledVoice")){ enabledVoice = UsayaStorageManager.Load(UsayaStorageFilename.Settings_Data, "EnabledVoice"); }else{ try{ if(StorageManager.Exists(StorageFilename.SettingsData, "EnabledVoice")){ enabledVoice = StorageManager.Load(StorageFilename.SettingsData, "EnabledVoice"); }else{ enabledVoice = DataManager.LoadOrDefault("EnabledVoice", true); } }catch{ enabledVoice = DataManager.LoadOrDefault("EnabledVoice", true); } } if(UsayaStorageManager.Exists(UsayaStorageFilename.Settings_Data, "VolumeBGM")){ bgmVolume = UsayaStorageManager.Load(UsayaStorageFilename.Settings_Data, "VolumeBGM"); }else{ try{ if(StorageManager.Exists(StorageFilename.SettingsData, "VolumeBGM")){ bgmVolume = StorageManager.Load(StorageFilename.SettingsData, "VolumeBGM"); }else{ bgmVolume = DataManager.LoadOrDefault("VolumeBGM", bgmVolume); } }catch{ bgmVolume = DataManager.LoadOrDefault("VolumeBGM", bgmVolume); } } if(UsayaStorageManager.Exists(UsayaStorageFilename.Settings_Data, "VolumeSE")){ seVolume = UsayaStorageManager.Load(UsayaStorageFilename.Settings_Data, "VolumeSE"); }else{ try{ if(StorageManager.Exists(StorageFilename.SettingsData, "VolumeSE")){ seVolume = StorageManager.Load(StorageFilename.SettingsData, "VolumeSE"); }else{ seVolume = DataManager.LoadOrDefault("VolumeSE", seVolume); } }catch{ seVolume = DataManager.LoadOrDefault("VolumeSE", seVolume); } } if(UsayaStorageManager.Exists(UsayaStorageFilename.Settings_Data, "VolumeVoice")){ voiceVolume = UsayaStorageManager.Load(UsayaStorageFilename.Settings_Data, "VolumeVoice"); }else{ try{ if(StorageManager.Exists(StorageFilename.SettingsData, "VolumeVoice")){ voiceVolume = StorageManager.Load(StorageFilename.SettingsData, "VolumeVoice"); }else{ voiceVolume = DataManager.LoadOrDefault("VolumeVoice", voiceVolume); } }catch{ voiceVolume = DataManager.LoadOrDefault("VolumeVoice", voiceVolume); } } #endif } public void SaveEnabledBGM(bool enabled){ UsayaStorageManager.Save(UsayaStorageFilename.Settings_Data, "EnabledBGM", enabled); enabledBGM = enabled; if(bgmSource != null){ bgmSource.mute = !enabledBGM; } } public void SaveEnabledSE(bool enabled){ UsayaStorageManager.Save(UsayaStorageFilename.Settings_Data, "EnabledSE", enabled); enabledSE = enabled; seSourceList.ForEach(se => se.ChangeMute(!enabledSE)); } public void SaveVolumeBGM(){ SaveVolumeBGM(bgmVolume); } public void SaveVolumeBGM(float volume){ UsayaStorageManager.Save(UsayaStorageFilename.Settings_Data, "VolumeBGM", volume); ChangeVolumeBGM(volume); } public void ChangeVolumeBGM(float volume){ bgmVolume = volume; if(bgmSource != null){ bgmSource.volume = uniqueBGMVolume * volume; bgmSource.mute = bgmSource.volume <= 0.0f; } } public void ChangeVolumeUniqueBGM(float volume){ uniqueBGMVolume = volume; if(bgmSource != null){ bgmSource.volume = uniqueBGMVolume * bgmVolume; } } public void SaveVolumeSE(){ SaveVolumeSE(seVolume); } public void SaveVolumeSE(float volume){ UsayaStorageManager.Save(UsayaStorageFilename.Settings_Data, "VolumeSE", volume); ChangeVolumeSE(volume); } public void ChangeVolumeSE(float volume){ seVolume = volume; seSourceList.ForEach(se => se.ChangeVolume(volume)); foreach(KeyValuePair pair in seLoopSourceDic){ pair.Value.ChangeVolume(volume); } } public void SaveVolumeVoice(){ SaveVolumeVoice(voiceVolume); } public void SaveVolumeVoice(float volume){ UsayaStorageManager.Save(UsayaStorageFilename.Settings_Data, "VolumeVoice", volume); ChangeVolumeVoice(volume); } public void ChangeVolumeVoice(float volume){ voiceVolume = volume; voiceSourceList.ForEach(voice => voice.ChangeVolume(volume)); } public void ChangeVolume(SoundType soundType, float volume){ switch(soundType){ case SoundType.BGM: ChangeVolumeBGM(volume); break; case SoundType.Voice: ChangeVolumeVoice(volume); break; default: ChangeVolumeSE(volume); break; } } void LateUpdate(){ for(int i = seSourceList.Count - 1; i >= 0; --i){ if(!seSourceList[i].IsPlaying()){ seSourceList[i].PlayCallBack(); seSourceList.RemoveAt(i); } } for(int i = voiceSourceList.Count - 1; i >= 0; --i){ if(!voiceSourceList[i].IsPlaying()){ voiceSourceList[i].PlayCallBack(); voiceSourceList.RemoveAt(i); } } } public void PauseBGM() { if(bgmSource) bgmSource.Pause(); } public void UnPauseBGM() { if(bgmSource) bgmSource.UnPause(); } public void PauseTimeBGM() { if(bgmSource){ pauseTime = bgmSource.time; bgmSource.Pause(); } } public void UnPauseTimeBGM() { if(bgmSource){ bgmSource.UnPause(); bgmSource.time = pauseTime; } } public void ReplayBGM(){ if(!bgmSource) return ; bgmSource.Stop(); bgmSource.Play(); } public void StopBGM(){ if(!bgmSource) return ; bgmFilePath = ""; bgmSource.Stop(); bgmSource.clip = null; } public void StopSE(){ foreach(PlayingAudio playing in seSourceList){ playing.Stop(); } seSourceList.Clear(); } public void StopSELoop(){ foreach(KeyValuePair pair in seLoopSourceDic){ pair.Value.StopDestroy(); } seLoopSourceDic.Clear(); } public void StopSELoop(string filePath){ if(!seLoopSourceDic.ContainsKey(filePath)) return ; PlayingAudio audioSource = seLoopSourceDic[filePath]; audioSource.StopDestroy(); seLoopSourceDic.Remove(filePath); } public void StopVoice(){ foreach(PlayingAudio playing in voiceSourceList){ playing.Stop(); } voiceSourceList.Clear(); } public void StopAll(){ StopBGM(); StopSE(); StopSELoop(); StopVoice(); } public void StopAllFade(float interval){ FadeOut(interval, StopAll); } public void ChangeFadeBGM(string filePath, float interval, float volume = 1.0f, bool loop = true){ if(bgmFilePath.Contains(filePath)) return ; if(bgmFilePath.Length > 0){ FadeOut(interval * 0.5f, () => { PlayBGM(filePath, volume); FadeIn(interval * 0.5f, ActionExtensions.EmptyAction); }); }else{ PlayBGM(filePath, volume, loop); } } public void PlayBGM(string filePath, float volume = 1.0f, bool loop = true){ if(bgmFilePath.Contains(filePath)) return ; bgmFilePath = filePath; PlayBGM(LoadAudioClip(filePath, SoundType.BGM), volume, loop); } public void PlayBGM(AudioClip clip, float volume = 1.0f, bool loop = true){ if(bgmSource == null){ bgmSource = gameObject.AddComponent(); } if(bgmSource.clip == clip) return ; uniqueBGMVolume = volume; pauseTime = 0.0f; bgmSource.time = 0.0f; bgmSource.Stop(); bgmSource.clip = clip; bgmSource.loop = loop; bgmSource.volume = uniqueBGMVolume * bgmVolume; bgmSource.mute = !enabledBGM; bgmSource.Play(); bgmSource.outputAudioMixerGroup = defaultBGMAudioMixer; } public void PlaySE(string filePath, int maxCount = 0, float volume = 1.0f, float pitch = 1.0f){ PlaySE(LoadAudioClip(filePath, SoundType.SE), maxCount, volume, pitch); } public void PlaySE(AudioClip clip, int maxCount = 0, float volume = 1.0f, float pitch = 1.0f){ if(clip == null) return ; PlaySE(clip, ActionExtensions.EmptyAction, maxCount, volume, pitch); } public void PlaySE(string filePath, Action callBack, int maxCount = 0, float volume = 1.0f){ PlaySE(LoadAudioClip(filePath, SoundType.SE), callBack, maxCount, volume); } public void PlaySE(AudioClip clip, Action callBack, int maxCount = 0, float volume = 1.0f, float pitch = 1.0f){ if(clip == null || isPausing) return ; PlaySE(clip, maxCount, volume, pitch, callBack, seSourceList); } private void PlaySE(AudioClip clip, int maxCount, float volume, float pitch, Action callBack, List list){ string clipName = clip.name; var result = FindCountOverPlayingAudio(clipName, maxCount, list); if(result != null){ result.audioSource.Stop(); result.audioSource.Play(); }else{ AudioSource source = CreateAudioSource(clip, volume * seVolume, pitch, !enabledSE, defaultSEAudioMixer); list.Add(new PlayingAudio(clipName, source, volume, callBack)); } } public AudioSource PlaySELoop(string filePath, float volume = 1.0f, float pitch = 1.0f){ if(seLoopSourceDic.ContainsKey(filePath)) return seLoopSourceDic[filePath].audioSource; AudioClip clip = LoadAudioClip(filePath, SoundType.SE); AudioSource source = CreateAudioSource(clip, volume * seVolume, pitch, !enabledSE, defaultSEAudioMixer); source.loop = true; seLoopSourceDic.Add(filePath, new PlayingAudio(clip.name, source, volume, ActionExtensions.EmptyAction)); return source; } public void PlayVoice(string filePath, int maxCount = 0, float volume = 1.0f, float pitch = 1.0f){ PlayVoice(LoadAudioClip(filePath, SoundType.Voice), maxCount, volume, pitch); } public void PlayVoice(AudioClip clip, int maxCount = 0, float volume = 1.0f, float pitch = 1.0f){ if(clip == null) return ; PlayVoice(clip, ActionExtensions.EmptyAction, maxCount, volume, pitch); } public void PlayVoice(string filePath, Action callBack, int maxCount = 0, float volume = 1.0f){ PlayVoice(LoadAudioClip(filePath, SoundType.Voice), callBack, maxCount, volume); } public void PlayVoice(AudioClip clip, Action callBack, int maxCount = 0, float volume = 1.0f, float pitch = 1.0f){ if(clip == null || isPausing){ callBack(); }else{ PlayVoice(clip, maxCount, volume, pitch, callBack, voiceSourceList); } } private void PlayVoice(AudioClip clip, int maxCount, float volume, float pitch, Action callBack, List list){ string clipName = clip.name; var result = FindCountOverPlayingAudio(clipName, maxCount, list); if(result != null){ result.audioSource.Stop(); result.audioSource.Play(); }else{ AudioSource source = CreateAudioSource(clip, volume * voiceVolume, pitch, !enabledVoice, defaultVoiceAudioMixer); list.Add(new PlayingAudio(clipName, source, volume, callBack)); } } private PlayingAudio FindCountOverPlayingAudio(string clipName, int maxCount, List list){ if(maxCount > 0){ int counter = 0; foreach(var pa in list){ if(pa.Name == clipName && ++counter >= maxCount){ foreach(var p in list){ if(p.Name == clipName){ return p; } } } } } return null; } private AudioSource CreateAudioSource(AudioClip clip, float volume, float pitch, bool mute, AudioMixerGroup audioMixerGroup){ AudioSource source = gameObject.AddComponent(); source.Stop(); source.clip = clip; source.volume = volume; source.pitch = pitch; source.mute = mute; source.Play(); source.outputAudioMixerGroup = defaultVoiceAudioMixer; return source; } public class PlayingAudio { private string name; public string Name { get{ return name; } } public AudioSource audioSource = null; private Action callBack = null; private float uniqueVolume; public PlayingAudio(string name, AudioSource audioSource, float uniqueVolume, Action callBack){ this.name = name; this.audioSource = audioSource; this.uniqueVolume = uniqueVolume; this.callBack = callBack; } public bool IsPlaying(){ return audioSource.isPlaying; } public void PlayCallBack(){ callBack(); Destroy(audioSource); } public void Stop(){ audioSource.Stop(); } public void StopDestroy(){ audioSource.Stop(); Destroy(audioSource); } public void ChangeVolume(float volume){ audioSource.volume = volume * uniqueVolume; } public void ChangeMute(bool mute){ audioSource.mute = mute; } } private Dictionary audioClipDict = new Dictionary(); private AudioClip LoadAudioClip(string filePath, SoundType soundType){ if(!filePath.Contains("/")){ switch(soundType){ case SoundType.BGM: filePath = "Sounds/BGM/" + filePath; break; case SoundType.SE: filePath = "Sounds/SE/" + filePath; break; case SoundType.Voice: filePath = "Sounds/Voice/" + filePath; break; } } AudioClip result = null; if(!audioClipDict.TryGetValue(filePath, out result)){ result = Resources.Load(filePath, typeof(AudioClip)) as AudioClip; #if UNITY_EDITOR if(result == null){ Debug.LogError("鳴らそうとしているファイル(" + filePath + ")が存在しません。"); UnityEditor.EditorApplication.isPlaying = false; } #endif audioClipDict.Add(filePath, result); } return result; } private void UpdateMute(){ if(bgmSource != null){ bgmSource.mute = !enabledBGM; } seSourceList.ForEach(se => se.ChangeMute(!enabledSE)); voiceSourceList.ForEach(voice => voice.ChangeMute(!enabledVoice)); } public void ChangeBGMAudioMixerGroup(AudioMixerGroup amg){ bgmSource.outputAudioMixerGroup = amg; } public void ResetBGMAudioMixerGroup(){ bgmSource.outputAudioMixerGroup = defaultBGMAudioMixer; } private bool isPause = false; void OnApplicationPause(bool pauseStatus){ if(!bgmSource) return ; if(pauseStatus){ isPause = true; bgmSource.volume = 0.0f; PauseBGM(); isPausing = true; }else if(isPause){ isPause = false; StartCoroutine(ReturnPause()); } } private bool isPausing = false; private IEnumerator ReturnPause(){ int i = 0; // 素通りだと起動時にFadeIn後のVolumeから開始される int waitFrameCounter = 20; while(i++ < waitFrameCounter){ yield return null; } isPausing = false; UnPauseBGM(); FadeIn(1.0f, ActionExtensions.EmptyAction); } private void FadeIn(float duration, Action callback){ Fade(duration, lerp => Mathf.Lerp(0.0f, 1.0f, lerp * lerp), callback); } private void FadeOut(float duration, Action callback){ Fade(duration, lerp => 1.0f - Mathf.Lerp(0.0f, 1.0f, lerp * lerp), callback); } private void Fade(float duration, Func lerpToVolume, Action callback){ this.CallLerpSmooth(duration, lerp => { float v = lerpToVolume(lerp); bgmSource.volume = v * uniqueBGMVolume * bgmVolume; float se = v * seVolume; foreach(PlayingAudio playing in seSourceList){ playing.ChangeVolume(se); } foreach(KeyValuePair pair in seLoopSourceDic){ pair.Value.ChangeVolume(se); } float voice = v * voiceVolume; foreach(PlayingAudio playing in voiceSourceList){ playing.ChangeVolume(voice); } }, callback); } }