Audio fixes
This commit is contained in:
@@ -10,12 +10,14 @@ namespace Darkmatter.Services.Audio
|
||||
public class AudioServiceModule : MonoBehaviour, IModule
|
||||
{
|
||||
[SerializeField] private SfxCatalogSO sfxCatalog;
|
||||
[SerializeField] private AudioService audioService;
|
||||
|
||||
public void Register(IContainerBuilder builder)
|
||||
{
|
||||
if (sfxCatalog != null)
|
||||
builder.RegisterComponent(sfxCatalog);
|
||||
builder.Register<IAudioService, AudioService>(Lifetime.Singleton);
|
||||
if (audioService != null)
|
||||
builder.RegisterComponent<IAudioService>(audioService);
|
||||
builder.Register<ISfxPlayer, SfxPlayer>(Lifetime.Singleton);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,6 +2,7 @@ using Darkmatter.Core.Contracts.Services.Music;
|
||||
using Darkmatter.Libs.Installers;
|
||||
using Darkmatter.Services.Music.Systems;
|
||||
using UnityEngine;
|
||||
using UnityEngine.Audio;
|
||||
using VContainer;
|
||||
using VContainer.Unity;
|
||||
|
||||
@@ -12,10 +13,11 @@ namespace Darkmatter.Services.Music.Installers
|
||||
[SerializeField] private AudioClip defaultTrack;
|
||||
[SerializeField, Range(0f, 1f)] private float defaultVolume = 0.7f;
|
||||
[SerializeField, Min(0f)] private float crossFadeSeconds = 0.4f;
|
||||
[SerializeField] private AudioMixerGroup mixerGroup;
|
||||
|
||||
public void Register(IContainerBuilder builder)
|
||||
{
|
||||
builder.RegisterInstance(new MusicConfig(defaultTrack, defaultVolume, crossFadeSeconds));
|
||||
builder.RegisterInstance(new MusicConfig(defaultTrack, defaultVolume, crossFadeSeconds, mixerGroup));
|
||||
builder.RegisterEntryPoint<MusicService>(Lifetime.Singleton).As<IMusicService>();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
using System;
|
||||
using UnityEngine;
|
||||
using UnityEngine.Audio;
|
||||
|
||||
namespace Darkmatter.Services.Music.Systems
|
||||
{
|
||||
@@ -9,12 +10,14 @@ namespace Darkmatter.Services.Music.Systems
|
||||
public AudioClip DefaultTrack { get; }
|
||||
public float DefaultVolume { get; }
|
||||
public float CrossFadeSeconds { get; }
|
||||
public AudioMixerGroup MixerGroup { get; }
|
||||
|
||||
public MusicConfig(AudioClip defaultTrack, float defaultVolume, float crossFadeSeconds)
|
||||
public MusicConfig(AudioClip defaultTrack, float defaultVolume, float crossFadeSeconds, AudioMixerGroup mixerGroup)
|
||||
{
|
||||
DefaultTrack = defaultTrack;
|
||||
DefaultVolume = defaultVolume;
|
||||
CrossFadeSeconds = crossFadeSeconds;
|
||||
MixerGroup = mixerGroup;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,9 +1,8 @@
|
||||
using System;
|
||||
using Darkmatter.Core.Contracts.Services.Audio;
|
||||
using System.Threading;
|
||||
using Cysharp.Threading.Tasks;
|
||||
using Darkmatter.Core.Contracts.Services.Music;
|
||||
using Darkmatter.Core.Data.Dynamic.Services.Audio;
|
||||
using Darkmatter.Core.Data.Signals.Features.AppBoot;
|
||||
using Darkmatter.Core.Enums.Services.Audio;
|
||||
using Darkmatter.Libs.Observer;
|
||||
using UnityEngine;
|
||||
using VContainer.Unity;
|
||||
@@ -12,59 +11,136 @@ namespace Darkmatter.Services.Music.Systems
|
||||
{
|
||||
public class MusicService : IMusicService, IStartable, IDisposable
|
||||
{
|
||||
private readonly IAudioService _audio;
|
||||
private readonly IEventBus _bus;
|
||||
private readonly MusicConfig _config;
|
||||
|
||||
private AudioHandle _current;
|
||||
private GameObject _host;
|
||||
private AudioSource _source;
|
||||
private IDisposable _introSub;
|
||||
private CancellationTokenSource _fadeCts;
|
||||
|
||||
public MusicService(IAudioService audio, IEventBus bus, MusicConfig config)
|
||||
public MusicService(IEventBus bus, MusicConfig config)
|
||||
{
|
||||
_audio = audio;
|
||||
_bus = bus;
|
||||
_config = config;
|
||||
}
|
||||
|
||||
public void Start()
|
||||
{
|
||||
_host = new GameObject("[MusicService]");
|
||||
UnityEngine.Object.DontDestroyOnLoad(_host);
|
||||
_source = _host.AddComponent<AudioSource>();
|
||||
_source.playOnAwake = false;
|
||||
_source.loop = true;
|
||||
_source.spatialBlend = 0f;
|
||||
_source.volume = _config.DefaultVolume;
|
||||
if (_config.MixerGroup != null) _source.outputAudioMixerGroup = _config.MixerGroup;
|
||||
|
||||
_introSub = _bus.Subscribe<IntroCompletedSignal>(OnIntroCompleted);
|
||||
}
|
||||
|
||||
private void OnIntroCompleted(IntroCompletedSignal _)
|
||||
{
|
||||
if (_config.DefaultTrack != null && !_current.IsValid)
|
||||
if (_config.DefaultTrack != null && (_source == null || !_source.isPlaying))
|
||||
Play(_config.DefaultTrack, _config.DefaultVolume, loop: true);
|
||||
}
|
||||
|
||||
public void Play(AudioClip clip, float volume01 = 1f, bool loop = true)
|
||||
{
|
||||
if (clip == null) return;
|
||||
if (_current.IsValid) _audio.Stop(_current, _config.CrossFadeSeconds);
|
||||
if (clip == null || _source == null) return;
|
||||
CancelFade();
|
||||
|
||||
var req = new AudioRequest(
|
||||
clip: clip,
|
||||
channel: AudioChannel.Music,
|
||||
mode: loop ? AudioPlayMode.Loop : AudioPlayMode.OneShot,
|
||||
stopChannelBeforePlay: true,
|
||||
volume01: Mathf.Clamp01(volume01));
|
||||
_current = _audio.Play(req);
|
||||
if (_source.isPlaying && _config.CrossFadeSeconds > 0f)
|
||||
{
|
||||
_fadeCts = new CancellationTokenSource();
|
||||
CrossFadeAsync(clip, Mathf.Clamp01(volume01), loop, _fadeCts.Token).Forget();
|
||||
return;
|
||||
}
|
||||
|
||||
_source.clip = clip;
|
||||
_source.loop = loop;
|
||||
_source.volume = Mathf.Clamp01(volume01);
|
||||
_source.Play();
|
||||
}
|
||||
|
||||
public void Stop(float fadeOutSeconds = 0f)
|
||||
{
|
||||
if (_current.IsValid) _audio.Stop(_current, fadeOutSeconds);
|
||||
_current = AudioHandle.Invalid;
|
||||
if (_source == null) return;
|
||||
CancelFade();
|
||||
if (fadeOutSeconds <= 0f) { _source.Stop(); return; }
|
||||
_fadeCts = new CancellationTokenSource();
|
||||
FadeOutAsync(fadeOutSeconds, _fadeCts.Token).Forget();
|
||||
}
|
||||
|
||||
public void SetVolume(float volume01)
|
||||
{
|
||||
if (_current.IsValid) _audio.SetVolume(_current, Mathf.Clamp01(volume01));
|
||||
if (_source == null) return;
|
||||
_source.volume = Mathf.Clamp01(volume01);
|
||||
}
|
||||
|
||||
private async UniTaskVoid CrossFadeAsync(AudioClip nextClip, float targetVolume, bool loop, CancellationToken ct)
|
||||
{
|
||||
try
|
||||
{
|
||||
float start = _source.volume;
|
||||
float t = 0f;
|
||||
float dur = _config.CrossFadeSeconds;
|
||||
while (t < dur)
|
||||
{
|
||||
ct.ThrowIfCancellationRequested();
|
||||
t += Time.unscaledDeltaTime;
|
||||
_source.volume = Mathf.Lerp(start, 0f, t / dur);
|
||||
await UniTask.Yield(PlayerLoopTiming.Update, ct);
|
||||
}
|
||||
_source.Stop();
|
||||
_source.clip = nextClip;
|
||||
_source.loop = loop;
|
||||
_source.volume = 0f;
|
||||
_source.Play();
|
||||
t = 0f;
|
||||
while (t < dur)
|
||||
{
|
||||
ct.ThrowIfCancellationRequested();
|
||||
t += Time.unscaledDeltaTime;
|
||||
_source.volume = Mathf.Lerp(0f, targetVolume, t / dur);
|
||||
await UniTask.Yield(PlayerLoopTiming.Update, ct);
|
||||
}
|
||||
_source.volume = targetVolume;
|
||||
}
|
||||
catch (OperationCanceledException) { }
|
||||
}
|
||||
|
||||
private async UniTaskVoid FadeOutAsync(float seconds, CancellationToken ct)
|
||||
{
|
||||
try
|
||||
{
|
||||
float start = _source.volume;
|
||||
float t = 0f;
|
||||
while (t < seconds)
|
||||
{
|
||||
ct.ThrowIfCancellationRequested();
|
||||
t += Time.unscaledDeltaTime;
|
||||
_source.volume = Mathf.Lerp(start, 0f, t / seconds);
|
||||
await UniTask.Yield(PlayerLoopTiming.Update, ct);
|
||||
}
|
||||
_source.Stop();
|
||||
_source.volume = start;
|
||||
}
|
||||
catch (OperationCanceledException) { }
|
||||
}
|
||||
|
||||
private void CancelFade()
|
||||
{
|
||||
_fadeCts?.Cancel();
|
||||
_fadeCts?.Dispose();
|
||||
_fadeCts = null;
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
CancelFade();
|
||||
_introSub?.Dispose();
|
||||
if (_host != null) UnityEngine.Object.Destroy(_host);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user