GFramework/GFramework.Core.Godot/system/AbstractAudioManagerSystem.cs
GeWuYou 506c26f945 feat(audio): 实现音频管理系统基础功能
- 添加音频管理器抽象基类和接口定义
- 支持背景音乐、音效和3D音效播放
- 实现音量控制和音频淡入淡出效果
- 提供音频播放器池化管理机制
- 支持通过资源ID或路径播放音频
- 实现主音量、音乐音量和音效音量独立控制
- 添加音频播放状态检测功能
- 支持低通滤波器和混响效果设置
- 实现系统资源自动清理机制
2025-12-17 12:49:28 +08:00

447 lines
13 KiB
C#
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

using GFramework.Core.extensions;
using GFramework.Core.system;
using Godot;
namespace GFramework.Core.Godot.system;
/// <summary>
/// 音频管理器抽象基类,提供音频播放的基础实现
/// </summary>
public abstract class AbstractAudioManagerSystem : AbstractSystem, IAudioManagerSystem
{
/// <summary>
/// 音频资源加载系统依赖
/// </summary>
protected IResourceLoadSystem? ResourceLoadSystem;
/// <summary>
/// 资源目录系统依赖
/// </summary>
protected IAssetCatalogSystem? AssetCatalogSystem;
/// <summary>
/// 背景音乐播放器
/// </summary>
protected AudioStreamPlayer? MusicPlayer;
/// <summary>
/// 音效播放器列表
/// </summary>
protected readonly List<AudioStreamPlayer> SoundPlayers = [];
/// <summary>
/// 可用音效播放器队列
/// </summary>
protected readonly Queue<AudioStreamPlayer> AvailableSoundPlayers = new();
/// <summary>
/// 3D音效播放器列表
/// </summary>
protected readonly List<AudioStreamPlayer3D> Sound3DPlayers = [];
/// <summary>
/// 可用3D音效播放器队列
/// </summary>
protected readonly Queue<AudioStreamPlayer3D> AvailableSound3DPlayers = new();
/// <summary>
/// 资源工厂系统依赖
/// </summary>
protected IResourceFactorySystem? ResourceFactorySystem;
/// <summary>
/// 背景音乐音量
/// </summary>
protected float MusicVolume = 1.0f;
/// <summary>
/// 音效音量
/// </summary>
protected float SoundVolume = 1.0f;
/// <summary>
/// 主音量
/// </summary>
protected float MasterVolume = 1.0f;
/// <summary>
/// 特效音量
/// </summary>
protected float SfxVolume = 1.0f;
/// <summary>
/// 语音音量
/// </summary>
protected float VoiceVolume = 1.0f;
/// <summary>
/// 环境音量
/// </summary>
protected float AmbientVolume = 1.0f;
/// <summary>
/// 音乐淡入淡出动画
/// </summary>
protected Tween? MusicFadeTween;
/// <summary>
/// 最大同时播放的音效数量
/// </summary>
protected const int MaxSoundPlayers = 10;
/// <summary>
/// 最大同时播放的3D音效数量
/// </summary>
protected const int MaxSound3DPlayers = 5;
/// <summary>
/// 所有者节点的抽象属性
/// </summary>
protected abstract Node Owner { get; }
/// <summary>
/// 系统初始化方法
/// </summary>
protected override void OnInit()
{
// 获取依赖的系统
ResourceLoadSystem = this.GetSystem<IResourceLoadSystem>();
AssetCatalogSystem = this.GetSystem<IAssetCatalogSystem>();
ResourceFactorySystem = this.GetSystem<IResourceFactorySystem>();
// 初始化背景音乐播放器
MusicPlayer = new AudioStreamPlayer();
Owner.AddChild(MusicPlayer);
// 预创建音效播放器池
for (var i = 0; i < MaxSoundPlayers; i++)
{
var soundPlayer = new AudioStreamPlayer();
Owner.AddChild(soundPlayer);
soundPlayer.Finished += () => OnSoundFinished(soundPlayer);
SoundPlayers.Add(soundPlayer);
AvailableSoundPlayers.Enqueue(soundPlayer);
}
// 预创建3D音效播放器池
for (var i = 0; i < MaxSound3DPlayers; i++)
{
var sound3DPlayer = new AudioStreamPlayer3D();
Owner.AddChild(sound3DPlayer);
sound3DPlayer.Finished += () => OnSound3DFinished(sound3DPlayer);
Sound3DPlayers.Add(sound3DPlayer);
AvailableSound3DPlayers.Enqueue(sound3DPlayer);
}
}
/// <summary>
/// 当音效播放完成时的回调
/// </summary>
/// <param name="player">完成播放的音频播放器</param>
private void OnSoundFinished(AudioStreamPlayer player)
{
// 将播放器放回可用队列
AvailableSoundPlayers.Enqueue(player);
}
/// <summary>
/// 当3D音效播放完成时的回调
/// </summary>
/// <param name="player">完成播放的3D音频播放器</param>
private void OnSound3DFinished(AudioStreamPlayer3D player)
{
// 将播放器放回可用队列
AvailableSound3DPlayers.Enqueue(player);
}
/// <summary>
/// 播放背景音乐
/// </summary>
/// <param name="audioPath">音频文件路径</param>
/// <param name="volume">音量大小范围0-1</param>
/// <param name="loop">是否循环播放</param>
public virtual void PlayMusic(string audioPath, float volume = 1.0f, bool loop = true)
{
var audioStream = ResourceLoadSystem?.LoadResource<AudioStream>(audioPath);
if (audioStream == null || MusicPlayer == null) return;
// 停止当前正在进行的淡入淡出效果
MusicFadeTween?.Kill();
MusicPlayer.Stream = audioStream;
MusicPlayer.VolumeDb = LinearToDb(volume * MusicVolume * MasterVolume);
MusicPlayer.Play();
}
/// <summary>
/// 通过资源ID播放背景音乐
/// </summary>
/// <param name="musicId">音乐资源ID</param>
/// <param name="volume">音量大小范围0-1</param>
/// <param name="loop">是否循环播放</param>
public virtual void PlayMusic(AssetCatalog.ResourceId musicId, float volume = 1.0f, bool loop = true)
{
PlayMusic(musicId.Path, volume, loop);
}
/// <summary>
/// 播放音效
/// </summary>
/// <param name="audioPath">音频文件路径</param>
/// <param name="volume">音量大小范围0-1</param>
/// <param name="pitch">音调调整</param>
public virtual void PlaySound(string audioPath, float volume = 1.0f, float pitch = 1.0f)
{
if (AvailableSoundPlayers.Count == 0) return;
var audioStream = ResourceLoadSystem?.LoadResource<AudioStream>(audioPath);
if (audioStream == null) return;
var player = AvailableSoundPlayers.Dequeue();
player.Stream = audioStream;
player.VolumeDb = LinearToDb(volume * SoundVolume * MasterVolume);
player.Play();
}
/// <summary>
/// 通过资源ID播放音效
/// </summary>
/// <param name="soundId">音效资源ID</param>
/// <param name="volume">音量大小范围0-1</param>
/// <param name="pitch">音调调整</param>
public virtual void PlaySound(AssetCatalog.ResourceId soundId, float volume = 1.0f, float pitch = 1.0f)
{
PlaySound(soundId.Path, volume, pitch);
}
/// <summary>
/// 播放3D音效
/// </summary>
/// <param name="audioPath">音频文件路径</param>
/// <param name="position">3D空间中的位置</param>
/// <param name="volume">音量大小范围0-1</param>
public virtual void PlaySound3D(string audioPath, Vector3 position, float volume = 1.0f)
{
if (AvailableSound3DPlayers.Count == 0) return;
var audioStream = ResourceLoadSystem?.LoadResource<AudioStream>(audioPath);
if (audioStream == null) return;
var player = AvailableSound3DPlayers.Dequeue();
player.Stream = audioStream;
player.VolumeDb = LinearToDb(volume * SoundVolume * MasterVolume);
player.Position = position;
player.Play();
}
/// <summary>
/// 停止背景音乐
/// </summary>
public virtual void StopMusic()
{
MusicFadeTween?.Kill();
MusicPlayer?.Stop();
}
/// <summary>
/// 暂停背景音乐
/// </summary>
public virtual void PauseMusic()
{
MusicFadeTween?.Kill();
// todo 需要记录音乐播放位置,以便恢复播放时从正确位置开始
}
/// <summary>
/// 恢复背景音乐播放
/// </summary>
public virtual void ResumeMusic()
{
MusicPlayer?.Play();
}
/// <summary>
/// 设置背景音乐音量
/// </summary>
/// <param name="volume">音量大小范围0-1</param>
public virtual void SetMusicVolume(float volume)
{
MusicVolume = volume;
if (MusicPlayer != null)
{
MusicPlayer.VolumeDb = LinearToDb(MusicVolume * MasterVolume);
}
}
/// <summary>
/// 设置音效音量
/// </summary>
/// <param name="volume">音量大小范围0-1</param>
public virtual void SetSoundVolume(float volume)
{
SoundVolume = volume;
}
/// <summary>
/// 设置主音量
/// </summary>
/// <param name="volume">音量大小范围0-1</param>
public virtual void SetMasterVolume(float volume)
{
MasterVolume = volume;
// 更新音乐音量
if (MusicPlayer != null)
{
MusicPlayer.VolumeDb = LinearToDb(MusicVolume * MasterVolume);
}
}
/// <summary>
/// 设置SFX音量
/// </summary>
/// <param name="volume">音量大小范围0-1</param>
public virtual void SetSfxVolume(float volume)
{
SfxVolume = volume;
}
/// <summary>
/// 设置语音音量
/// </summary>
/// <param name="volume">音量大小范围0-1</param>
public virtual void SetVoiceVolume(float volume)
{
VoiceVolume = volume;
}
/// <summary>
/// 设置环境音量
/// </summary>
/// <param name="volume">音量大小范围0-1</param>
public virtual void SetAmbientVolume(float volume)
{
AmbientVolume = volume;
}
/// <summary>
/// 检查背景音乐是否正在播放
/// </summary>
/// <returns>正在播放返回true否则返回false</returns>
public virtual bool IsMusicPlaying()
{
return MusicPlayer?.Playing ?? false;
}
/// <summary>
/// 淡入背景音乐
/// </summary>
/// <param name="audioPath">音频文件路径</param>
/// <param name="duration">淡入持续时间(秒)</param>
/// <param name="volume">目标音量</param>
public virtual void FadeInMusic(string audioPath, float duration, float volume = 1.0f)
{
var audioStream = ResourceLoadSystem?.LoadResource<AudioStream>(audioPath);
if (audioStream == null || MusicPlayer == null) return;
// 停止当前正在进行的淡入淡出效果
MusicFadeTween?.Kill();
MusicPlayer.Stream = audioStream;
MusicPlayer.VolumeDb = LinearToDb(0.0f); // 初始音量为0
MusicPlayer.Play();
// 创建淡入动画
MusicFadeTween = Owner.CreateTween();
MusicFadeTween.TweenProperty(MusicPlayer, "volume_db", LinearToDb(volume * MusicVolume * MasterVolume),
duration);
}
/// <summary>
/// 淡出背景音乐
/// </summary>
/// <param name="duration">淡出持续时间(秒)</param>
public virtual void FadeOutMusic(float duration)
{
if (MusicPlayer == null) return;
// 停止当前正在进行的淡入淡出效果
MusicFadeTween?.Kill();
// 创建淡出动画
MusicFadeTween = Owner.CreateTween();
MusicFadeTween.TweenProperty(MusicPlayer, "volume_db", LinearToDb(0.0f), duration);
MusicFadeTween.TweenCallback(Callable.From(() => MusicPlayer.Stop()));
}
/// <summary>
/// 设置低通滤波器强度
/// </summary>
/// <param name="amount">滤波器强度范围0-1</param>
public virtual void SetLowPassFilter(float amount)
{
// TODO: 实现低通滤波器效果
// 可以通过AudioEffectLowPassFilter实现
}
/// <summary>
/// 设置音频混响效果
/// </summary>
/// <param name="roomSize">房间大小</param>
/// <param name="damping">阻尼</param>
/// <param name="wetLevel">湿声级别</param>
public virtual void SetReverb(float roomSize, float damping, float wetLevel)
{
// TODO: 实现音频混响效果
// 可以通过AudioEffectReverb实现
}
/// <summary>
/// 将线性音量值转换为分贝值
/// </summary>
/// <param name="linear">线性音量值0-1</param>
/// <returns>分贝值</returns>
protected static float LinearToDb(float linear)
{
return linear > 0 ? 20 * Mathf.Log(linear) : -100;
}
/// <summary>
/// 将分贝值转换为线性音量值
/// </summary>
/// <param name="db">分贝值</param>
/// <returns>线性音量值0-1</returns>
protected static float DbToLinear(float db)
{
return db > -100 ? Mathf.Exp(db / 20) : 0;
}
/// <summary>
/// 系统销毁时清理资源
/// </summary>
protected void OnDestroy()
{
// 停止并清理淡入淡出动画
MusicFadeTween?.Kill();
// 清理音乐播放器
MusicPlayer?.QueueFree();
// 清理音效播放器池
foreach (var player in SoundPlayers)
{
player.QueueFree();
}
// 清理3D音效播放器池
foreach (var player in Sound3DPlayers)
{
player.QueueFree();
}
SoundPlayers.Clear();
AvailableSoundPlayers.Clear();
Sound3DPlayers.Clear();
AvailableSound3DPlayers.Clear();
}
}