324 lines
11 KiB
C#
324 lines
11 KiB
C#
using System.Collections.Generic;
|
|
using System.Threading.Tasks;
|
|
using UnityEngine;
|
|
using UnityEngine.Audio;
|
|
using UnityEngine.AddressableAssets;
|
|
using UnityEngine.Assertions;
|
|
using asap.core.common;
|
|
using UnityEngine.ResourceManagement.AsyncOperations;
|
|
using System.Threading;
|
|
using System;
|
|
using UniRx;
|
|
|
|
namespace asap.core
|
|
{
|
|
public interface ISoundService
|
|
{
|
|
[Inject]
|
|
public IObjectPoolService poolService { set; }
|
|
public int MasterVol { get; set; }
|
|
public int BGMVol { get; set; }
|
|
public int SFXVol { get; set; }
|
|
public int VoiceVol { get; set; }
|
|
|
|
public Task InitAsync(string mixerAddr = "AudioMixer", string soundPrefabAddr = "sound",
|
|
string bgmGroupId = "BGM", string fishingGroupId = "Fishing", string uiGroupId = "UI", string voiceGroupId = "Voice");
|
|
public void Release();
|
|
public Sound GetNewBgmSound(AudioClip clip, bool loop = true, int priority = 0, float time = 0);
|
|
public Sound GetNewFishingSound(AudioClip clip, bool loop = false, int priority = 128, float time = 0);
|
|
public Sound GetNewUISound(AudioClip clip, bool loop = false, int priority = 128, float time = 0);
|
|
public Sound GetNewVoiceSound(AudioClip clip);
|
|
public void ReturnSound(Sound sound);
|
|
public void FadeIn(Sound sound, float duration);
|
|
public void FadeOut(Sound sound, float duration);
|
|
}
|
|
|
|
public struct LowpassEffectEvt
|
|
{
|
|
public bool active;
|
|
public float transTime;
|
|
}
|
|
|
|
public class SoundService : ISoundService
|
|
{
|
|
[Inject]
|
|
public IObjectPoolService poolService { set; private get; }
|
|
|
|
private AudioMixer mixer;
|
|
private AudioMixerGroup bgmGroup;
|
|
private AudioMixerGroup fishingGroup;
|
|
private AudioMixerGroup uiGroup;
|
|
private AudioMixerGroup voiceGroup;
|
|
|
|
private AsyncOperationHandle<AudioMixer> mixerHandle;
|
|
private AsyncOperationHandle<GameObject> soundPrefabHandle;
|
|
|
|
private Dictionary<Sound, CancellationTokenSource> SoundFadeTaskDic;
|
|
private float bgmVol = 0;
|
|
private float fishingVol = 0;
|
|
private const float Min_Vol = -80.0f;
|
|
private const float Max_Vol = 20.0f;
|
|
private const string Master_Vol_Param_Name = "masterVol";
|
|
private const string Bgm_Vol_Param_Name = "bgmVol";
|
|
private const string Fishing_Vol_Param_Name = "fishingVol";
|
|
private const string UI_Vol_Param_Name = "uiVol";
|
|
private const string Voice_Vol_Param_Name = "voiceVol";
|
|
|
|
|
|
private const string Lowpass_Cutoff_Frq = "low_cut";
|
|
private AudioMixerSnapshot normal;
|
|
//private AudioMixerSnapshot lowpass;
|
|
private IDisposable lowpassEvtDisposable;
|
|
|
|
private int _masterVol;
|
|
public int MasterVol
|
|
{
|
|
get { return _masterVol; }
|
|
set
|
|
{
|
|
_masterVol = value;
|
|
mixer.SetFloat(Master_Vol_Param_Name, VolInt2Float(_masterVol));
|
|
}
|
|
}
|
|
|
|
private int _bgmVol;
|
|
public int BGMVol
|
|
{
|
|
get { return _bgmVol; }
|
|
set
|
|
{
|
|
_bgmVol = value;
|
|
mixer.SetFloat(Bgm_Vol_Param_Name, VolInt2Float(_bgmVol) + bgmVol);
|
|
}
|
|
}
|
|
|
|
private int _sfxVol;
|
|
public int SFXVol
|
|
{
|
|
get { return _sfxVol; }
|
|
set
|
|
{
|
|
_sfxVol = value;
|
|
mixer.SetFloat(Fishing_Vol_Param_Name, VolInt2Float(_sfxVol) + fishingVol);
|
|
mixer.SetFloat(UI_Vol_Param_Name, VolInt2Float(_sfxVol));
|
|
}
|
|
}
|
|
private int _voiceVol;
|
|
public int VoiceVol
|
|
{
|
|
get { return _voiceVol; }
|
|
set
|
|
{
|
|
_voiceVol = value;
|
|
mixer.SetFloat(Voice_Vol_Param_Name, VolInt2Float(_voiceVol));
|
|
}
|
|
}
|
|
private float VolInt2Float(int value)
|
|
{
|
|
var vol = Mathf.Clamp(value, 0f, 100f) / 100.0f;
|
|
vol = Min_Vol + (Max_Vol - Min_Vol) * vol;
|
|
return vol;
|
|
}
|
|
|
|
private AudioMixerGroup FindMixerGroup(string groupId)
|
|
{
|
|
var groups = mixer.FindMatchingGroups(groupId);
|
|
if (groups != null && groups.Length > 0)
|
|
return groups[0];
|
|
else
|
|
{
|
|
Debug.LogWarning("Audio mixer group {groupId} is not found");
|
|
return null;
|
|
}
|
|
}
|
|
|
|
public async Task InitAsync(string mixerAddr = "AudioMixer", string soundPrefabAddr = "sound",
|
|
string bgmGroupId = "BGM", string fishingGroupId = "Fishing", string uiGroupId = "UI", string voiceGroupId = "Voice")
|
|
{
|
|
SoundFadeTaskDic = new Dictionary<Sound, CancellationTokenSource>();
|
|
|
|
mixerHandle = Addressables.LoadAssetAsync<AudioMixer>(mixerAddr);
|
|
mixer = await mixerHandle.Task;
|
|
Assert.IsNotNull(mixer);
|
|
mixer.GetFloat(Bgm_Vol_Param_Name, out bgmVol);
|
|
mixer.GetFloat(Fishing_Vol_Param_Name, out fishingVol);
|
|
|
|
bgmGroup = FindMixerGroup(bgmGroupId);
|
|
fishingGroup = FindMixerGroup(fishingGroupId);
|
|
uiGroup = FindMixerGroup(uiGroupId);
|
|
voiceGroup = FindMixerGroup(voiceGroupId);
|
|
normal = mixer.FindSnapshot("Snapshot");// ("normal");
|
|
//lowpass = mixer.FindSnapshot("lowpass");
|
|
Assert.IsNotNull(bgmGroup);
|
|
Assert.IsNotNull(fishingGroup);
|
|
Assert.IsNotNull(uiGroup);
|
|
|
|
soundPrefabHandle = Addressables.LoadAssetAsync<GameObject>(soundPrefabAddr);
|
|
var soundPrefab = await soundPrefabHandle.Task;
|
|
Assert.IsNotNull(soundPrefab);
|
|
var sound = soundPrefab.GetComponent<Sound>();
|
|
Assert.IsNotNull(sound);
|
|
|
|
lowpassEvtDisposable = GContext.OnEvent<LowpassEffectEvt>().Subscribe(OnLowpassEffectEvt);
|
|
|
|
poolService.CreatePool<Sound>(sound, 10, 50);
|
|
}
|
|
|
|
private void OnLowpassEffectEvt(LowpassEffectEvt evt)
|
|
{
|
|
//if (evt.active)
|
|
//{
|
|
// lowpass.TransitionTo(evt.transTime);
|
|
// return;
|
|
//}
|
|
normal.TransitionTo(evt.transTime);
|
|
}
|
|
|
|
public void Release()
|
|
{
|
|
foreach (var source in SoundFadeTaskDic.Values)
|
|
{
|
|
source.Cancel();
|
|
}
|
|
SoundFadeTaskDic.Clear();
|
|
SoundFadeTaskDic = null;
|
|
|
|
poolService.DestroyPool<Sound>();
|
|
Addressables.Release(mixerHandle);
|
|
Addressables.Release(soundPrefabHandle);
|
|
|
|
lowpassEvtDisposable.Dispose();
|
|
lowpassEvtDisposable = null;
|
|
}
|
|
|
|
public void FadeIn(Sound sound, float duration)
|
|
{
|
|
if (SoundFadeTaskDic.TryGetValue(sound, out var s))
|
|
{
|
|
s.Cancel();
|
|
SoundFadeTaskDic[sound].Dispose();
|
|
SoundFadeTaskDic.Remove(sound);
|
|
}
|
|
var source = new CancellationTokenSource();
|
|
var token = source.Token;
|
|
SoundFadeTaskDic.Add(sound, source);
|
|
DoFade(0f, 1f, sound, duration, token);
|
|
}
|
|
|
|
public void FadeOut(Sound sound, float duration)
|
|
{
|
|
if (SoundFadeTaskDic.TryGetValue(sound, out var s))
|
|
{
|
|
s.Cancel();
|
|
SoundFadeTaskDic[sound].Dispose();
|
|
SoundFadeTaskDic.Remove(sound);
|
|
}
|
|
var source = new CancellationTokenSource();
|
|
var token = source.Token;
|
|
SoundFadeTaskDic.Add(sound, source);
|
|
DoFade(1f, 0f, sound, duration, token);
|
|
}
|
|
|
|
public Sound GetNewBgmSound(AudioClip clip, bool loop = true, int priority = 0, float time = 0)
|
|
{
|
|
var sound = poolService.SpawnObject<Sound>();
|
|
Assert.IsNotNull(sound, "Sound Pool reached max num");
|
|
var audioSource = sound.audioSource;
|
|
audioSource.clip = clip;
|
|
audioSource.loop = loop;
|
|
audioSource.priority = priority;
|
|
audioSource.time = time;
|
|
audioSource.outputAudioMixerGroup = bgmGroup;
|
|
audioSource.Pause();
|
|
return sound;
|
|
}
|
|
|
|
public Sound GetNewFishingSound(AudioClip clip, bool loop = false, int priority = 128, float time = 0)
|
|
{
|
|
var sound = poolService.SpawnObject<Sound>();
|
|
Assert.IsNotNull(sound, "Sound Pool reached max num");
|
|
var audioSource = sound.audioSource;
|
|
audioSource.clip = clip;
|
|
audioSource.loop = loop;
|
|
audioSource.priority = priority;
|
|
audioSource.time = time;
|
|
audioSource.outputAudioMixerGroup = fishingGroup;
|
|
return sound;
|
|
}
|
|
public Sound GetNewUISound(AudioClip clip, bool loop = false, int priority = 128, float time = 0)
|
|
{
|
|
var sound = poolService.SpawnObject<Sound>();
|
|
Assert.IsNotNull(sound, "Sound Pool reached max num");
|
|
var audioSource = sound.audioSource;
|
|
audioSource.clip = clip;
|
|
audioSource.loop = loop;
|
|
audioSource.priority = priority;
|
|
audioSource.time = time;
|
|
audioSource.outputAudioMixerGroup = uiGroup;
|
|
return sound;
|
|
}
|
|
public Sound GetNewVoiceSound(AudioClip clip)
|
|
{
|
|
var sound = poolService.SpawnObject<Sound>();
|
|
Assert.IsNotNull(sound, "Sound Pool reached max num");
|
|
var audioSource = sound.audioSource;
|
|
audioSource.clip = clip;
|
|
audioSource.loop = false;
|
|
audioSource.priority = 128;
|
|
audioSource.time = 0;
|
|
audioSource.outputAudioMixerGroup = voiceGroup;
|
|
return sound;
|
|
}
|
|
public void ReturnSound(Sound sound)
|
|
{
|
|
if (SoundFadeTaskDic == null || sound == null)
|
|
return;
|
|
if (SoundFadeTaskDic.TryGetValue(sound, out var s))
|
|
{
|
|
s.Cancel();
|
|
SoundFadeTaskDic[sound].Dispose();
|
|
SoundFadeTaskDic.Remove(sound);
|
|
}
|
|
if (sound.enabled)
|
|
{
|
|
poolService.DespawnObject(sound);
|
|
}
|
|
}
|
|
|
|
private async void DoFade(float startVol, float endVol, Sound sound, float duration, CancellationToken ct)
|
|
{
|
|
var elapsedTime = 0f;
|
|
sound.audioSource.volume = startVol;
|
|
|
|
try
|
|
{
|
|
while (elapsedTime < duration)
|
|
{
|
|
if (ct.IsCancellationRequested)
|
|
{
|
|
break;
|
|
}
|
|
else
|
|
{
|
|
sound.audioSource.volume = Mathf.Lerp(startVol, endVol, elapsedTime / duration);
|
|
elapsedTime += Time.deltaTime;
|
|
await Task.Yield();
|
|
}
|
|
}
|
|
Assert.IsNotNull(sound);
|
|
sound.audioSource.volume = endVol;
|
|
|
|
}
|
|
finally
|
|
{
|
|
if (!ct.IsCancellationRequested && SoundFadeTaskDic != null)
|
|
{
|
|
SoundFadeTaskDic[sound].Dispose();
|
|
SoundFadeTaskDic.Remove(sound);
|
|
}
|
|
}
|
|
|
|
}
|
|
}
|
|
}
|