audio-systems
Compare original and translation side by side
🇺🇸
Original
English🇨🇳
Translation
ChineseAudio & Sound Systems
音频与声音系统
Audio Architecture
音频架构
┌─────────────────────────────────────────────────────────────┐
│ GAME AUDIO PIPELINE │
├─────────────────────────────────────────────────────────────┤
│ SOURCES: SFX | Music | Voice | Ambient │
│ ↓ │
│ MIDDLEWARE: Wwise / FMOD / Engine Audio │
│ ↓ │
│ PROCESSING: 3D Spatial | Reverb | EQ | Compression │
│ ↓ │
│ MIXING: Master → Submixes → Individual Tracks │
│ ↓ │
│ OUTPUT: Speakers / Headphones (Stereo/Surround/Binaural) │
└─────────────────────────────────────────────────────────────┘┌─────────────────────────────────────────────────────────────┐
│ GAME AUDIO PIPELINE │
├─────────────────────────────────────────────────────────────┤
│ SOURCES: SFX | Music | Voice | Ambient │
│ ↓ │
│ MIDDLEWARE: Wwise / FMOD / Engine Audio │
│ ↓ │
│ PROCESSING: 3D Spatial | Reverb | EQ | Compression │
│ ↓ │
│ MIXING: Master → Submixes → Individual Tracks │
│ ↓ │
│ OUTPUT: Speakers / Headphones (Stereo/Surround/Binaural) │
└─────────────────────────────────────────────────────────────┘Audio Programming
音频编程
Unity Audio Manager
Unity 音频管理器
csharp
// ✅ Production-Ready: Audio Manager
public class AudioManager : MonoBehaviour
{
public static AudioManager Instance { get; private set; }
[System.Serializable]
public class SoundBank
{
public string id;
public AudioClip[] clips;
[Range(0f, 1f)] public float volume = 1f;
[Range(0.1f, 3f)] public float pitchVariation = 0.1f;
}
[SerializeField] private SoundBank[] _soundBanks;
[SerializeField] private int _poolSize = 20;
private Dictionary<string, SoundBank> _bankLookup;
private Queue<AudioSource> _sourcePool;
private void Awake()
{
if (Instance != null) { Destroy(gameObject); return; }
Instance = this;
DontDestroyOnLoad(gameObject);
InitializePool();
BuildLookup();
}
public void PlaySound(string id, Vector3 position)
{
if (!_bankLookup.TryGetValue(id, out var bank)) return;
if (bank.clips.Length == 0) return;
var source = GetPooledSource();
source.transform.position = position;
source.clip = bank.clips[Random.Range(0, bank.clips.Length)];
source.volume = bank.volume;
source.pitch = 1f + Random.Range(-bank.pitchVariation, bank.pitchVariation);
source.Play();
StartCoroutine(ReturnToPool(source, source.clip.length));
}
private AudioSource GetPooledSource()
{
if (_sourcePool.Count > 0) return _sourcePool.Dequeue();
return CreateNewSource();
}
private void InitializePool() { /* ... */ }
private void BuildLookup() { /* ... */ }
private AudioSource CreateNewSource() { /* ... */ }
private IEnumerator ReturnToPool(AudioSource s, float delay) { /* ... */ }
}csharp
// ✅ Production-Ready: Audio Manager
public class AudioManager : MonoBehaviour
{
public static AudioManager Instance { get; private set; }
[System.Serializable]
public class SoundBank
{
public string id;
public AudioClip[] clips;
[Range(0f, 1f)] public float volume = 1f;
[Range(0.1f, 3f)] public float pitchVariation = 0.1f;
}
[SerializeField] private SoundBank[] _soundBanks;
[SerializeField] private int _poolSize = 20;
private Dictionary<string, SoundBank> _bankLookup;
private Queue<AudioSource> _sourcePool;
private void Awake()
{
if (Instance != null) { Destroy(gameObject); return; }
Instance = this;
DontDestroyOnLoad(gameObject);
InitializePool();
BuildLookup();
}
public void PlaySound(string id, Vector3 position)
{
if (!_bankLookup.TryGetValue(id, out var bank)) return;
if (bank.clips.Length == 0) return;
var source = GetPooledSource();
source.transform.position = position;
source.clip = bank.clips[Random.Range(0, bank.clips.Length)];
source.volume = bank.volume;
source.pitch = 1f + Random.Range(-bank.pitchVariation, bank.pitchVariation);
source.Play();
StartCoroutine(ReturnToPool(source, source.clip.length));
}
private AudioSource GetPooledSource()
{
if (_sourcePool.Count > 0) return _sourcePool.Dequeue();
return CreateNewSource();
}
private void InitializePool() { /* ... */ }
private void BuildLookup() { /* ... */ }
private AudioSource CreateNewSource() { /* ... */ }
private IEnumerator ReturnToPool(AudioSource s, float delay) { /* ... */ }
}FMOD Integration
FMOD 集成
csharp
// ✅ Production-Ready: FMOD Event Player
public class FMODEventPlayer : MonoBehaviour
{
[SerializeField] private FMODUnity.EventReference _eventRef;
private FMOD.Studio.EventInstance _instance;
private bool _isPlaying;
public void Play()
{
if (_isPlaying) Stop();
_instance = FMODUnity.RuntimeManager.CreateInstance(_eventRef);
_instance.set3DAttributes(FMODUnity.RuntimeUtils.To3DAttributes(transform));
_instance.start();
_isPlaying = true;
}
public void SetParameter(string name, float value)
{
if (_isPlaying)
_instance.setParameterByName(name, value);
}
public void Stop(bool allowFadeout = true)
{
if (!_isPlaying) return;
_instance.stop(allowFadeout
? FMOD.Studio.STOP_MODE.ALLOWFADEOUT
: FMOD.Studio.STOP_MODE.IMMEDIATE);
_instance.release();
_isPlaying = false;
}
private void OnDestroy() => Stop(false);
}csharp
// ✅ Production-Ready: FMOD Event Player
public class FMODEventPlayer : MonoBehaviour
{
[SerializeField] private FMODUnity.EventReference _eventRef;
private FMOD.Studio.EventInstance _instance;
private bool _isPlaying;
public void Play()
{
if (_isPlaying) Stop();
_instance = FMODUnity.RuntimeManager.CreateInstance(_eventRef);
_instance.set3DAttributes(FMODUnity.RuntimeUtils.To3DAttributes(transform));
_instance.start();
_isPlaying = true;
}
public void SetParameter(string name, float value)
{
if (_isPlaying)
_instance.setParameterByName(name, value);
}
public void Stop(bool allowFadeout = true)
{
if (!_isPlaying) return;
_instance.stop(allowFadeout
? FMOD.Studio.STOP_MODE.ALLOWFADEOUT
: FMOD.Studio.STOP_MODE.IMMEDIATE);
_instance.release();
_isPlaying = false;
}
private void OnDestroy() => Stop(false);
}Spatial Audio
空间音频
3D AUDIO CONFIGURATION:
┌─────────────────────────────────────────────────────────────┐
│ ATTENUATION CURVES: │
│ │
│ Volume │████████████ │
│ │ ████ │
│ │ ████ │
│ │ ████ │
│ └──────────────────────────→ Distance │
│ 0m 10m 30m 50m │
│ │
│ Min Distance: 1m (full volume) │
│ Max Distance: 50m (inaudible) │
│ Rolloff: Logarithmic (realistic) │
└─────────────────────────────────────────────────────────────┘3D AUDIO CONFIGURATION:
┌─────────────────────────────────────────────────────────────┐
│ ATTENUATION CURVES: │
│ │
│ Volume │████████████ │
│ │ ████ │
│ │ ████ │
│ │ ████ │
│ └──────────────────────────→ Distance │
│ 0m 10m 30m 50m │
│ │
│ Min Distance: 1m (full volume) │
│ Max Distance: 50m (inaudible) │
│ Rolloff: Logarithmic (realistic) │
└─────────────────────────────────────────────────────────────┘最小距离:1米(全音量)
最大距离:50米(不可闻)
衰减模式:对数型(真实感)
Music Systems
音乐系统
Adaptive Music State Machine
自适应音乐状态机
MUSIC STATE TRANSITIONS:
┌─────────────────────────────────────────────────────────────┐
│ │
│ [EXPLORATION] ←──────────→ [TENSION] │
│ │ │ │
│ ↓ ↓ │
│ [DISCOVERY] [COMBAT] │
│ │ │
│ ↓ │
│ [VICTORY] / [DEFEAT] │
│ │
│ Transition Rules: │
│ • Crossfade on beat boundaries │
│ • 2-4 bar transition windows │
│ • Intensity parameter controls layers │
└─────────────────────────────────────────────────────────────┘MUSIC STATE TRANSITIONS:
┌─────────────────────────────────────────────────────────────┐
│ │
│ [EXPLORATION] ←──────────→ [TENSION] │
│ │ │ │
│ ↓ ↓ │
│ [DISCOVERY] [COMBAT] │
│ │ │
│ ↓ │
│ [VICTORY] / [DEFEAT] │
│ │
│ Transition Rules: │
│ • Crossfade on beat boundaries │
│ • 2-4 bar transition windows │
│ • Intensity parameter controls layers │
└─────────────────────────────────────────────────────────────┘过渡规则:
• 在节拍边界处进行交叉淡入淡出
• 2-4小节的过渡窗口
• 强度参数控制音轨层
Mixing Guidelines
混音指南
| Bus | Content | Target Level |
|---|---|---|
| Master | Final mix | -3dB peak |
| Music | BGM, Stingers | -12dB to -6dB |
| SFX | Gameplay sounds | -6dB to 0dB |
| Voice | Dialogue, VO | -6dB to -3dB |
| Ambient | Environment | -18dB to -12dB |
| 总线 | 内容 | 目标电平 |
|---|---|---|
| 主总线 | 最终混音 | -3dB peak |
| 音乐总线 | 背景音乐、过渡音效 | -12dB 至 -6dB |
| 音效总线 | 游戏玩法音效 | -6dB 至 0dB |
| 语音总线 | 对话、旁白 | -6dB 至 -3dB |
| 环境音总线 | 环境音效 | -18dB 至 -12dB |
🔧 Troubleshooting
🔧 故障排查
┌─────────────────────────────────────────────────────────────┐
│ PROBLEM: Audio popping/clicking │
├─────────────────────────────────────────────────────────────┤
│ SOLUTIONS: │
│ → Add fade in/out (5-10ms) │
│ → Check sample rate mismatches │
│ → Increase audio buffer size │
│ → Use audio source pooling │
└─────────────────────────────────────────────────────────────┘
┌─────────────────────────────────────────────────────────────┐
│ PROBLEM: Too many simultaneous sounds │
├─────────────────────────────────────────────────────────────┤
│ SOLUTIONS: │
│ → Implement voice limiting per category │
│ → Priority system (important sounds steal) │
│ → Distance-based culling │
│ → Virtual voices (middleware feature) │
└─────────────────────────────────────────────────────────────┘
┌─────────────────────────────────────────────────────────────┐
│ PROBLEM: Music transitions are jarring │
├─────────────────────────────────────────────────────────────┤
│ SOLUTIONS: │
│ → Align transitions to musical bars │
│ → Use crossfades (1-4 seconds) │
│ → Prepare transition stingers │
│ → Match keys between sections │
└─────────────────────────────────────────────────────────────┘┌─────────────────────────────────────────────────────────────┐
│ PROBLEM: Audio popping/clicking │
├─────────────────────────────────────────────────────────────┤
│ SOLUTIONS: │
│ → Add fade in/out (5-10ms) │
│ → Check sample rate mismatches │
│ → Increase audio buffer size │
│ → Use audio source pooling │
└─────────────────────────────────────────────────────────────┘问题:音频出现爆音/咔哒声
解决方案:
→ 添加淡入淡出效果(5-10毫秒)
→ 检查采样率不匹配问题
→ 增大音频缓冲区大小
→ 使用音频源对象池
┌─────────────────────────────────────────────────────────────┐
│ PROBLEM: Too many simultaneous sounds │
├─────────────────────────────────────────────────────────────┤
│ SOLUTIONS: │
│ → Implement voice limiting per category │
│ → Priority system (important sounds steal) │
│ → Distance-based culling │
│ → Virtual voices (middleware feature) │
└─────────────────────────────────────────────────────────────┘问题:同时播放的声音过多
解决方案:
→ 按类别实现发声数限制
→ 优先级系统(重要声音抢占资源)
→ 基于距离的声音剔除
→ 虚拟发声(中间件功能)
┌─────────────────────────────────────────────────────────────┐
│ PROBLEM: Music transitions are jarring │
├─────────────────────────────────────────────────────────────┤
│ SOLUTIONS: │
│ → Align transitions to musical bars │
│ → Use crossfades (1-4 seconds) │
│ → Prepare transition stingers │
│ → Match keys between sections │
└─────────────────────────────────────────────────────────────┘问题:音乐过渡生硬
解决方案:
→ 使过渡与音乐小节对齐
→ 使用交叉淡入淡出(1-4秒)
→ 准备过渡用的衔接音效
→ 匹配段落间的调式
Optimization
优化建议
| Platform | Max Voices | Compression | Streaming |
|---|---|---|---|
| Mobile | 16-32 | High (Vorbis) | Required |
| Console | 64-128 | Medium | Large files |
| PC | 128-256 | Low | Optional |
Use this skill: When implementing audio, designing sound, or composing music.
| 平台 | 最大发声数 | 压缩级别 | 流式处理 |
|---|---|---|---|
| 移动平台 | 16-32 | 高(Vorbis) | 必需 |
| 主机平台 | 64-128 | 中等 | 大文件启用 |
| PC平台 | 128-256 | 低 | 可选 |
使用场景:在实现音频、设计音效或创作音乐时。