@zigrivers/scaffold 3.4.1 → 3.5.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +91 -0
- package/content/knowledge/game/game-accessibility.md +328 -0
- package/content/knowledge/game/game-ai-patterns.md +567 -0
- package/content/knowledge/game/game-asset-pipeline.md +363 -0
- package/content/knowledge/game/game-audio-design.md +344 -0
- package/content/knowledge/game/game-binary-vcs-strategy.md +396 -0
- package/content/knowledge/game/game-design-document.md +269 -0
- package/content/knowledge/game/game-domain-patterns.md +299 -0
- package/content/knowledge/game/game-economy-design.md +355 -0
- package/content/knowledge/game/game-engine-selection.md +242 -0
- package/content/knowledge/game/game-input-systems.md +379 -0
- package/content/knowledge/game/game-level-content-design.md +483 -0
- package/content/knowledge/game/game-liveops-analytics.md +280 -0
- package/content/knowledge/game/game-localization.md +323 -0
- package/content/knowledge/game/game-milestone-definitions.md +337 -0
- package/content/knowledge/game/game-modding-ugc.md +390 -0
- package/content/knowledge/game/game-narrative-design.md +404 -0
- package/content/knowledge/game/game-networking.md +393 -0
- package/content/knowledge/game/game-performance-budgeting.md +389 -0
- package/content/knowledge/game/game-platform-certification.md +417 -0
- package/content/knowledge/game/game-project-structure.md +360 -0
- package/content/knowledge/game/game-save-systems.md +452 -0
- package/content/knowledge/game/game-testing-strategy.md +470 -0
- package/content/knowledge/game/game-ui-patterns.md +477 -0
- package/content/knowledge/game/game-vr-ar-design.md +313 -0
- package/content/knowledge/review/review-art-bible.md +305 -0
- package/content/knowledge/review/review-game-design.md +303 -0
- package/content/knowledge/review/review-game-economy.md +272 -0
- package/content/knowledge/review/review-game-ui.md +293 -0
- package/content/knowledge/review/review-netcode.md +280 -0
- package/content/knowledge/review/review-platform-cert.md +341 -0
- package/content/methodology/custom-defaults.yml +25 -0
- package/content/methodology/deep.yml +25 -0
- package/content/methodology/game-overlay.yml +145 -0
- package/content/methodology/mvp.yml +25 -0
- package/content/pipeline/architecture/ai-behavior-design.md +87 -0
- package/content/pipeline/architecture/netcode-spec.md +86 -0
- package/content/pipeline/architecture/review-netcode.md +78 -0
- package/content/pipeline/foundation/performance-budgets.md +91 -0
- package/content/pipeline/modeling/narrative-bible.md +84 -0
- package/content/pipeline/pre/game-design-document.md +90 -0
- package/content/pipeline/pre/review-gdd.md +74 -0
- package/content/pipeline/quality/analytics-telemetry.md +98 -0
- package/content/pipeline/quality/live-ops-plan.md +99 -0
- package/content/pipeline/quality/platform-cert-prep.md +129 -0
- package/content/pipeline/quality/playtest-plan.md +84 -0
- package/content/pipeline/specification/art-bible.md +87 -0
- package/content/pipeline/specification/audio-design.md +97 -0
- package/content/pipeline/specification/content-structure-design.md +142 -0
- package/content/pipeline/specification/economy-design.md +105 -0
- package/content/pipeline/specification/game-accessibility.md +82 -0
- package/content/pipeline/specification/game-ui-spec.md +97 -0
- package/content/pipeline/specification/input-controls-spec.md +81 -0
- package/content/pipeline/specification/localization-plan.md +113 -0
- package/content/pipeline/specification/modding-ugc-spec.md +116 -0
- package/content/pipeline/specification/online-services-spec.md +104 -0
- package/content/pipeline/specification/review-economy.md +87 -0
- package/content/pipeline/specification/review-game-ui.md +73 -0
- package/content/pipeline/specification/save-system-spec.md +116 -0
- package/dist/cli/commands/adopt.d.ts.map +1 -1
- package/dist/cli/commands/adopt.js +25 -0
- package/dist/cli/commands/adopt.js.map +1 -1
- package/dist/cli/commands/adopt.test.js +28 -1
- package/dist/cli/commands/adopt.test.js.map +1 -1
- package/dist/cli/commands/build.test.js +3 -0
- package/dist/cli/commands/build.test.js.map +1 -1
- package/dist/cli/commands/init.d.ts +1 -0
- package/dist/cli/commands/init.d.ts.map +1 -1
- package/dist/cli/commands/init.js +6 -0
- package/dist/cli/commands/init.js.map +1 -1
- package/dist/cli/commands/init.test.js +12 -1
- package/dist/cli/commands/init.test.js.map +1 -1
- package/dist/cli/commands/knowledge.test.js +8 -0
- package/dist/cli/commands/knowledge.test.js.map +1 -1
- package/dist/cli/commands/next.d.ts.map +1 -1
- package/dist/cli/commands/next.js +19 -5
- package/dist/cli/commands/next.js.map +1 -1
- package/dist/cli/commands/next.test.js +56 -0
- package/dist/cli/commands/next.test.js.map +1 -1
- package/dist/cli/commands/rework.d.ts.map +1 -1
- package/dist/cli/commands/rework.js +11 -2
- package/dist/cli/commands/rework.js.map +1 -1
- package/dist/cli/commands/rework.test.js +5 -0
- package/dist/cli/commands/rework.test.js.map +1 -1
- package/dist/cli/commands/run.d.ts.map +1 -1
- package/dist/cli/commands/run.js +54 -4
- package/dist/cli/commands/run.js.map +1 -1
- package/dist/cli/commands/run.test.js +384 -0
- package/dist/cli/commands/run.test.js.map +1 -1
- package/dist/cli/commands/skip.test.js +3 -0
- package/dist/cli/commands/skip.test.js.map +1 -1
- package/dist/cli/commands/status.d.ts.map +1 -1
- package/dist/cli/commands/status.js +16 -3
- package/dist/cli/commands/status.js.map +1 -1
- package/dist/cli/commands/status.test.js +55 -0
- package/dist/cli/commands/status.test.js.map +1 -1
- package/dist/cli/output/auto.d.ts +3 -0
- package/dist/cli/output/auto.d.ts.map +1 -1
- package/dist/cli/output/auto.js +9 -0
- package/dist/cli/output/auto.js.map +1 -1
- package/dist/cli/output/context.d.ts +6 -0
- package/dist/cli/output/context.d.ts.map +1 -1
- package/dist/cli/output/context.js.map +1 -1
- package/dist/cli/output/context.test.js +87 -0
- package/dist/cli/output/context.test.js.map +1 -1
- package/dist/cli/output/error-display.test.js +3 -0
- package/dist/cli/output/error-display.test.js.map +1 -1
- package/dist/cli/output/interactive.d.ts +3 -0
- package/dist/cli/output/interactive.d.ts.map +1 -1
- package/dist/cli/output/interactive.js +76 -0
- package/dist/cli/output/interactive.js.map +1 -1
- package/dist/cli/output/json.d.ts +3 -0
- package/dist/cli/output/json.d.ts.map +1 -1
- package/dist/cli/output/json.js +9 -0
- package/dist/cli/output/json.js.map +1 -1
- package/dist/config/loader.d.ts.map +1 -1
- package/dist/config/loader.js +3 -2
- package/dist/config/loader.js.map +1 -1
- package/dist/config/schema.d.ts +641 -15
- package/dist/config/schema.d.ts.map +1 -1
- package/dist/config/schema.js +26 -1
- package/dist/config/schema.js.map +1 -1
- package/dist/config/schema.test.js +192 -1
- package/dist/config/schema.test.js.map +1 -1
- package/dist/core/assembly/overlay-loader.d.ts +24 -0
- package/dist/core/assembly/overlay-loader.d.ts.map +1 -0
- package/dist/core/assembly/overlay-loader.js +190 -0
- package/dist/core/assembly/overlay-loader.js.map +1 -0
- package/dist/core/assembly/overlay-loader.test.d.ts +2 -0
- package/dist/core/assembly/overlay-loader.test.d.ts.map +1 -0
- package/dist/core/assembly/overlay-loader.test.js +106 -0
- package/dist/core/assembly/overlay-loader.test.js.map +1 -0
- package/dist/core/assembly/overlay-resolver.d.ts +15 -0
- package/dist/core/assembly/overlay-resolver.d.ts.map +1 -0
- package/dist/core/assembly/overlay-resolver.js +58 -0
- package/dist/core/assembly/overlay-resolver.js.map +1 -0
- package/dist/core/assembly/overlay-resolver.test.d.ts +2 -0
- package/dist/core/assembly/overlay-resolver.test.d.ts.map +1 -0
- package/dist/core/assembly/overlay-resolver.test.js +246 -0
- package/dist/core/assembly/overlay-resolver.test.js.map +1 -0
- package/dist/core/assembly/overlay-state-resolver.d.ts +26 -0
- package/dist/core/assembly/overlay-state-resolver.d.ts.map +1 -0
- package/dist/core/assembly/overlay-state-resolver.js +63 -0
- package/dist/core/assembly/overlay-state-resolver.js.map +1 -0
- package/dist/core/assembly/overlay-state-resolver.test.d.ts +2 -0
- package/dist/core/assembly/overlay-state-resolver.test.d.ts.map +1 -0
- package/dist/core/assembly/overlay-state-resolver.test.js +256 -0
- package/dist/core/assembly/overlay-state-resolver.test.js.map +1 -0
- package/dist/core/assembly/preset-loader.d.ts +1 -0
- package/dist/core/assembly/preset-loader.d.ts.map +1 -1
- package/dist/core/assembly/preset-loader.js +2 -0
- package/dist/core/assembly/preset-loader.js.map +1 -1
- package/dist/core/dependency/eligibility.test.js +3 -0
- package/dist/core/dependency/eligibility.test.js.map +1 -1
- package/dist/e2e/game-pipeline.test.d.ts +10 -0
- package/dist/e2e/game-pipeline.test.d.ts.map +1 -0
- package/dist/e2e/game-pipeline.test.js +298 -0
- package/dist/e2e/game-pipeline.test.js.map +1 -0
- package/dist/e2e/init.test.js +3 -0
- package/dist/e2e/init.test.js.map +1 -1
- package/dist/project/adopt.d.ts +3 -1
- package/dist/project/adopt.d.ts.map +1 -1
- package/dist/project/adopt.js +29 -1
- package/dist/project/adopt.js.map +1 -1
- package/dist/project/adopt.test.js +51 -1
- package/dist/project/adopt.test.js.map +1 -1
- package/dist/types/config.d.ts +50 -4
- package/dist/types/config.d.ts.map +1 -1
- package/dist/types/config.test.d.ts +2 -0
- package/dist/types/config.test.d.ts.map +1 -0
- package/dist/types/config.test.js +97 -0
- package/dist/types/config.test.js.map +1 -0
- package/dist/utils/eligible.d.ts +3 -2
- package/dist/utils/eligible.d.ts.map +1 -1
- package/dist/utils/eligible.js +18 -4
- package/dist/utils/eligible.js.map +1 -1
- package/dist/utils/errors.d.ts +4 -0
- package/dist/utils/errors.d.ts.map +1 -1
- package/dist/utils/errors.js +31 -0
- package/dist/utils/errors.js.map +1 -1
- package/dist/utils/errors.test.js +4 -1
- package/dist/utils/errors.test.js.map +1 -1
- package/dist/wizard/questions.d.ts +4 -0
- package/dist/wizard/questions.d.ts.map +1 -1
- package/dist/wizard/questions.js +59 -1
- package/dist/wizard/questions.js.map +1 -1
- package/dist/wizard/questions.test.js +178 -4
- package/dist/wizard/questions.test.js.map +1 -1
- package/dist/wizard/wizard.d.ts +1 -0
- package/dist/wizard/wizard.d.ts.map +1 -1
- package/dist/wizard/wizard.js +4 -1
- package/dist/wizard/wizard.js.map +1 -1
- package/dist/wizard/wizard.test.js +102 -4
- package/dist/wizard/wizard.test.js.map +1 -1
- package/package.json +1 -1
|
@@ -0,0 +1,344 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: game-audio-design
|
|
3
|
+
description: Wwise vs FMOD selection, bus hierarchy, spatial audio, adaptive music systems, VO pipeline, and platform loudness targets
|
|
4
|
+
topics: [game-dev, audio, fmod, wwise, spatial-audio, adaptive-music]
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
Game audio is not background decoration — it is a primary feedback channel that communicates game state, spatial awareness, emotional tone, and mechanical timing to the player. A gunshot tells the player where the enemy is, how far away they are, and what weapon they are using. Adaptive music builds tension before the player consciously recognizes danger. Missing or poorly mixed audio creates a hollow, unfinished experience that players feel even if they cannot articulate why. Audio architecture decisions (middleware, bus hierarchy, adaptive systems) must be made early because they affect content pipelines, memory budgets, and CPU budgets throughout production.
|
|
8
|
+
|
|
9
|
+
## Summary
|
|
10
|
+
|
|
11
|
+
### Middleware Decision: Wwise vs FMOD
|
|
12
|
+
|
|
13
|
+
Both Wwise and FMOD are professional audio middleware that replace the engine's built-in audio system with far more capable tools. Choosing between them affects the audio team's workflow, licensing costs, and available features.
|
|
14
|
+
|
|
15
|
+
**FMOD Studio:**
|
|
16
|
+
- Lower learning curve; audio designers can be productive within days
|
|
17
|
+
- Generous indie licensing (free under $200K revenue)
|
|
18
|
+
- Clean C API with strong Unity and Unreal integration
|
|
19
|
+
- Event-based authoring with timeline and parameter-driven transitions
|
|
20
|
+
- Adequate spatial audio with listener-based panning and occlusion
|
|
21
|
+
- Good for indie through AA productions
|
|
22
|
+
|
|
23
|
+
**Wwise:**
|
|
24
|
+
- Steeper learning curve; full productivity takes weeks of training
|
|
25
|
+
- More complex licensing (free for non-commercial use and projects under revenue thresholds set by Audiokinetic; commercial pricing based on project budget tier — verify current thresholds at audiokinetic.com as these shift periodically)
|
|
26
|
+
- Industry standard for AAA — most senior audio programmers have Wwise experience
|
|
27
|
+
- Superior spatial audio with Wwise Spatial Audio including room/portal modeling
|
|
28
|
+
- More powerful interactive music system (Music Segments, Stingers, Transitions)
|
|
29
|
+
- Advanced profiling tools (Wwise Profiler) for runtime debugging
|
|
30
|
+
- SoundSeed plugins for procedural audio (wind, impact, grain)
|
|
31
|
+
|
|
32
|
+
**Decision framework:**
|
|
33
|
+
- Team size 1–5 audio designers, budget under $500K: **FMOD**
|
|
34
|
+
- Team has AAA audio designers with Wwise experience: **Wwise**
|
|
35
|
+
- Game relies heavily on adaptive music and spatial audio as core mechanics: **Wwise**
|
|
36
|
+
- Rapid prototyping or game jam: **FMOD** (faster setup)
|
|
37
|
+
- Both are correct choices — the wrong choice is using the engine's built-in audio for a production game
|
|
38
|
+
|
|
39
|
+
### Bus / Mixer Hierarchy
|
|
40
|
+
|
|
41
|
+
Audio buses (mixer groups) organize sounds into categories for independent volume control, effects processing, and ducking. A well-designed bus hierarchy is the foundation of a clean mix.
|
|
42
|
+
|
|
43
|
+
Standard hierarchy:
|
|
44
|
+
- **Master** (output)
|
|
45
|
+
- **Music** — adaptive score, menu music, stingers
|
|
46
|
+
- **SFX** — gameplay sound effects
|
|
47
|
+
- **Weapons** — gunshots, impacts, reload
|
|
48
|
+
- **Footsteps** — per-surface, per-character
|
|
49
|
+
- **Environment** — ambient beds, wind, rain, machinery
|
|
50
|
+
- **UI** — button clicks, notifications, menu transitions
|
|
51
|
+
- **Abilities** — spell effects, power-ups, special moves
|
|
52
|
+
- **Voice** — dialogue, barks, VO
|
|
53
|
+
- **Dialogue** — scripted narrative VO
|
|
54
|
+
- **Barks** — contextual combat/exploration callouts
|
|
55
|
+
- **Announcer** — game state announcements
|
|
56
|
+
- **Cinematics** — pre-rendered or in-engine cutscene audio (overrides normal mix)
|
|
57
|
+
|
|
58
|
+
Each bus should have: volume fader, mute/solo, low-pass/high-pass filter, compressor, and ducking sidechain inputs.
|
|
59
|
+
|
|
60
|
+
### Loudness Standards
|
|
61
|
+
|
|
62
|
+
Platform holders and distribution channels enforce loudness standards. Non-compliant audio may cause certification failures.
|
|
63
|
+
|
|
64
|
+
- **Console (PlayStation, Xbox, Switch)**: -24 LUFS integrated, +/- 2 LU tolerance
|
|
65
|
+
- **PC (Steam, Epic)**: No enforcement, but -23 LUFS is the professional standard
|
|
66
|
+
- **Mobile (iOS, Android)**: Target -18 LUFS integrated (compensates for noisy environments and small speakers)
|
|
67
|
+
- **Streaming/Trailer**: -14 LUFS for YouTube/Twitch (louder to compete for attention)
|
|
68
|
+
- **VR**: -24 LUFS with very tight dynamic range (loud sounds in headphones cause discomfort)
|
|
69
|
+
|
|
70
|
+
Measure loudness with integrated LUFS metering over a representative gameplay session, not just peak levels. A game that averages -24 LUFS but has gunshots hitting -6 LUFS true peak will clip and distort.
|
|
71
|
+
|
|
72
|
+
### Spatial Audio Fundamentals
|
|
73
|
+
|
|
74
|
+
Spatial audio places sounds in 3D space relative to the listener (camera or player character). It enables the player to locate threats, allies, and objectives by ear.
|
|
75
|
+
|
|
76
|
+
Key concepts:
|
|
77
|
+
- **Attenuation**: Sound volume decreases with distance. Linear, logarithmic, or custom curves.
|
|
78
|
+
- **Panning**: Stereo or surround placement based on angle to listener.
|
|
79
|
+
- **Occlusion**: Sounds behind walls are muffled (low-pass filtered and attenuated).
|
|
80
|
+
- **Obstruction**: A partial barrier between source and listener (e.g., crate) partially filters the sound.
|
|
81
|
+
- **Reverb zones**: Different environments (cave, hallway, outdoor) apply different reverb characteristics.
|
|
82
|
+
- **HRTF (Head-Related Transfer Function)**: Simulates how human ears perceive directionality. Essential for headphone playback and VR.
|
|
83
|
+
|
|
84
|
+
## Deep Guidance
|
|
85
|
+
|
|
86
|
+
### Adaptive Music Systems
|
|
87
|
+
|
|
88
|
+
Adaptive music responds to gameplay state in real-time, creating a dynamic soundtrack that matches the player's experience rather than looping a fixed track.
|
|
89
|
+
|
|
90
|
+
**Horizontal re-sequencing:**
|
|
91
|
+
- Music is composed in segments (intro, low tension, high tension, victory, defeat)
|
|
92
|
+
- The music system selects and sequences segments based on game state
|
|
93
|
+
- Transitions between segments use crossfades, transition segments, or beat-synced cuts
|
|
94
|
+
- Example: exploration segment loops until combat starts, then transitions to combat segment on the next bar line
|
|
95
|
+
|
|
96
|
+
**Vertical layering (additive mixing):**
|
|
97
|
+
- A single musical passage has multiple layers recorded simultaneously (drums, bass, melody, strings, percussion)
|
|
98
|
+
- Layers are added or removed based on game intensity
|
|
99
|
+
- Exploration: drums + bass only. Approaching danger: add melody. Full combat: all layers
|
|
100
|
+
- Advantages: seamless transitions (no segment switch), consistent harmonic content
|
|
101
|
+
- Disadvantages: all layers must work in every combination, limiting compositional freedom
|
|
102
|
+
|
|
103
|
+
**Stingers:**
|
|
104
|
+
- Short musical phrases triggered by specific game events (boss appearance, treasure found, death)
|
|
105
|
+
- Play over the current music, typically ducking the score briefly
|
|
106
|
+
- Must be composed in a compatible key/tempo or be atonal enough to work over anything
|
|
107
|
+
- Budget 10–30 stingers per game; overuse makes them less impactful
|
|
108
|
+
|
|
109
|
+
**Implementation pattern:**
|
|
110
|
+
|
|
111
|
+
The following example uses Unity + FMOD, but the pattern is engine-agnostic: create a persistent music event, drive parameters (intensity, danger) from gameplay state, and smooth parameter transitions. In Unreal, use FMOD or Wwise UE plugin with Blueprint-exposed parameters. In Godot, use AudioStreamPlayer with custom properties driven by game state, or integrate FMOD via GDNative. The core pattern — a persistent music controller receiving gameplay state updates — is identical across engines.
|
|
112
|
+
|
|
113
|
+
```csharp
|
|
114
|
+
// Adaptive music controller — vertical layering with FMOD parameters
|
|
115
|
+
// Attach to a persistent game object that survives scene loads
|
|
116
|
+
|
|
117
|
+
using UnityEngine;
|
|
118
|
+
using FMODUnity;
|
|
119
|
+
using FMOD.Studio;
|
|
120
|
+
|
|
121
|
+
public class AdaptiveMusicController : MonoBehaviour
|
|
122
|
+
{
|
|
123
|
+
[SerializeField] private EventReference musicEvent;
|
|
124
|
+
|
|
125
|
+
private EventInstance _musicInstance;
|
|
126
|
+
private PARAMETER_ID _intensityParamId;
|
|
127
|
+
private PARAMETER_ID _dangerParamId;
|
|
128
|
+
|
|
129
|
+
// Intensity: 0.0 = calm exploration, 1.0 = full combat
|
|
130
|
+
// Danger: 0.0 = safe, 1.0 = boss fight
|
|
131
|
+
// These drive vertical layer activation in the FMOD event
|
|
132
|
+
|
|
133
|
+
private float _currentIntensity;
|
|
134
|
+
private float _targetIntensity;
|
|
135
|
+
private const float IntensityLerpSpeed = 0.5f; // Smooth transitions
|
|
136
|
+
|
|
137
|
+
private void Start()
|
|
138
|
+
{
|
|
139
|
+
_musicInstance = RuntimeManager.CreateInstance(musicEvent);
|
|
140
|
+
|
|
141
|
+
// Cache parameter IDs for efficient per-frame updates
|
|
142
|
+
EventDescription desc;
|
|
143
|
+
_musicInstance.getDescription(out desc);
|
|
144
|
+
|
|
145
|
+
PARAMETER_DESCRIPTION paramDesc;
|
|
146
|
+
desc.getParameterDescriptionByName("Intensity", out paramDesc);
|
|
147
|
+
_intensityParamId = paramDesc.id;
|
|
148
|
+
desc.getParameterDescriptionByName("Danger", out paramDesc);
|
|
149
|
+
_dangerParamId = paramDesc.id;
|
|
150
|
+
|
|
151
|
+
_musicInstance.start();
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
private void Update()
|
|
155
|
+
{
|
|
156
|
+
// Smooth intensity transitions — avoid jarring mix changes
|
|
157
|
+
_currentIntensity = Mathf.Lerp(
|
|
158
|
+
_currentIntensity,
|
|
159
|
+
_targetIntensity,
|
|
160
|
+
IntensityLerpSpeed * Time.deltaTime
|
|
161
|
+
);
|
|
162
|
+
_musicInstance.setParameterByID(_intensityParamId, _currentIntensity);
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
// Called by combat system when threat level changes
|
|
166
|
+
public void SetCombatIntensity(float intensity)
|
|
167
|
+
{
|
|
168
|
+
_targetIntensity = Mathf.Clamp01(intensity);
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
// Called when entering/exiting boss encounters
|
|
172
|
+
public void SetDangerLevel(float danger)
|
|
173
|
+
{
|
|
174
|
+
_musicInstance.setParameterByID(_dangerParamId, danger);
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
// Trigger a stinger (one-shot musical phrase over the current score)
|
|
178
|
+
public void PlayStinger(EventReference stingerEvent)
|
|
179
|
+
{
|
|
180
|
+
// FMOD handles ducking the score via sidechain in the mixer
|
|
181
|
+
RuntimeManager.PlayOneShot(stingerEvent);
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
private void OnDestroy()
|
|
185
|
+
{
|
|
186
|
+
_musicInstance.stop(FMOD.Studio.STOP_MODE.ALLOWFADEOUT);
|
|
187
|
+
_musicInstance.release();
|
|
188
|
+
}
|
|
189
|
+
}
|
|
190
|
+
```
|
|
191
|
+
|
|
192
|
+
### Voice-Over Pipeline
|
|
193
|
+
|
|
194
|
+
Voice-over (VO) production is one of the most expensive and logistically complex aspects of game audio. A well-structured pipeline prevents re-records, miscast lines, and late-stage localization disasters.
|
|
195
|
+
|
|
196
|
+
**Pipeline stages:**
|
|
197
|
+
1. **Script finalization**: Lock dialogue text before casting. Every change after recording costs studio time.
|
|
198
|
+
2. **Casting**: Audition voice actors for each character. Record sample lines in the target emotional range.
|
|
199
|
+
3. **Recording sessions**: Professional studio with consistent microphone and room treatment. Record at 48 kHz / 24-bit WAV minimum.
|
|
200
|
+
4. **Editing**: Remove breaths (or reduce, not eliminate — breathless VO sounds robotic), normalize levels, remove noise. Apply consistent EQ per character.
|
|
201
|
+
5. **Implementation**: Import into middleware, assign to dialogue events, set up subtitles, configure lip-sync data.
|
|
202
|
+
6. **Localization**: Record all supported languages. Budget localization time equal to original language recording time.
|
|
203
|
+
7. **QA**: Playthrough with every language enabled, checking for missing lines, incorrect triggers, subtitle mismatches, and audio clipping.
|
|
204
|
+
|
|
205
|
+
**File naming convention:**
|
|
206
|
+
- `{character}_{scene}_{lineID}_{take}.wav`
|
|
207
|
+
- Example: `npc_merchant_shop_0042_01.wav`
|
|
208
|
+
- Consistent naming enables automated import pipelines and batch processing
|
|
209
|
+
|
|
210
|
+
**Memory management for VO:**
|
|
211
|
+
- VO is typically the largest single audio asset category (hours of recorded dialogue)
|
|
212
|
+
- Stream from disk rather than loading into memory (except for combat barks that need instant playback)
|
|
213
|
+
- Pre-load upcoming dialogue lines during gameplay based on narrative triggers
|
|
214
|
+
- Compress with Vorbis/Opus at 96–128 kbps for production, 48 kbps for low-memory platforms
|
|
215
|
+
- Unload VO banks when leaving a narrative area
|
|
216
|
+
|
|
217
|
+
### Audio Compression Per Platform
|
|
218
|
+
|
|
219
|
+
Different platforms have different memory, storage, and CPU constraints that affect audio format selection:
|
|
220
|
+
|
|
221
|
+
**Console (PS5, Xbox Series X, Switch):**
|
|
222
|
+
- Format: Platform-native compressed (Atrac9 on PlayStation, XMA on Xbox, ADPCM or Opus on Switch)
|
|
223
|
+
- Wwise/FMOD handle platform-specific encoding automatically during build
|
|
224
|
+
- Sample rate: 48 kHz for music and VO, 24 kHz acceptable for ambient SFX
|
|
225
|
+
- Channels: 5.1 or 7.1 master output for home theater; stereo for handheld Switch
|
|
226
|
+
|
|
227
|
+
**PC:**
|
|
228
|
+
- Format: Vorbis or Opus for compressed, PCM for low-latency SFX
|
|
229
|
+
- Sample rate: 48 kHz standard
|
|
230
|
+
- Channels: Support stereo, 5.1, and 7.1 output; detect and configure at runtime
|
|
231
|
+
- PC has the most memory headroom — use higher quality compression settings
|
|
232
|
+
|
|
233
|
+
**Mobile:**
|
|
234
|
+
- Format: AAC (iOS native), Vorbis/Opus (Android), ADPCM for low-latency SFX
|
|
235
|
+
- Sample rate: 44.1 kHz or 24 kHz to save memory
|
|
236
|
+
- Channels: Stereo only (mono for non-spatial SFX to halve memory)
|
|
237
|
+
- Aggressive compression: 64–96 kbps for music, 48 kbps for VO
|
|
238
|
+
- Budget total audio memory at 50–100 MB (compared to 500+ MB on console)
|
|
239
|
+
|
|
240
|
+
### Sound Design Patterns for Gameplay
|
|
241
|
+
|
|
242
|
+
**Layered SFX construction:**
|
|
243
|
+
- Build complex sounds from multiple simple layers: a gunshot = transient (click/snap) + body (boom/crack) + tail (reverb/echo) + mechanical (bolt action)
|
|
244
|
+
- Each layer can vary independently for variety: 5 transients x 5 bodies x 3 tails = 75 unique combinations from 13 assets
|
|
245
|
+
- Randomize pitch (+/- 2 semitones) and volume (+/- 2 dB) per playback for further variation
|
|
246
|
+
- Never play the same exact sound twice in a row — the brain detects repetition instantly
|
|
247
|
+
|
|
248
|
+
**Priority and voice stealing:**
|
|
249
|
+
- Audio hardware has a limited number of simultaneous voices (typically 32–256 virtual voices)
|
|
250
|
+
- When the limit is reached, the system must steal the lowest-priority voice
|
|
251
|
+
- Priority order (highest to lowest): player weapon fire > VO dialogue > nearby enemy SFX > music > distant ambient
|
|
252
|
+
- Implement a priority system in middleware; configure max instances per event type (e.g., max 4 simultaneous footstep voices)
|
|
253
|
+
|
|
254
|
+
**Ducking and sidechain:**
|
|
255
|
+
- When important audio plays (VO, critical UI), duck less important buses (music, ambient)
|
|
256
|
+
- Implement via sidechain compression on the music bus keyed to the VO bus
|
|
257
|
+
- Duck by 6–12 dB during dialogue; fade duck in/out over 200–500 ms to avoid pumping artifacts
|
|
258
|
+
- Avoid ducking SFX during gameplay — players need spatial awareness from SFX even during dialogue
|
|
259
|
+
|
|
260
|
+
### Reverb and Environment Design
|
|
261
|
+
|
|
262
|
+
```yaml
|
|
263
|
+
# Reverb zone presets — configure per-area in the game world
|
|
264
|
+
# Values are approximate starting points; tune by ear in-game
|
|
265
|
+
|
|
266
|
+
reverb_presets:
|
|
267
|
+
outdoor_open:
|
|
268
|
+
decay_time: 0.8s
|
|
269
|
+
pre_delay: 10ms
|
|
270
|
+
wet_mix: 0.15
|
|
271
|
+
diffusion: 0.7
|
|
272
|
+
hf_damping: 0.3
|
|
273
|
+
notes: "Minimal reverb; sounds dissipate quickly"
|
|
274
|
+
|
|
275
|
+
outdoor_canyon:
|
|
276
|
+
decay_time: 2.5s
|
|
277
|
+
pre_delay: 40ms
|
|
278
|
+
wet_mix: 0.35
|
|
279
|
+
diffusion: 0.5
|
|
280
|
+
hf_damping: 0.4
|
|
281
|
+
notes: "Distinct echoes, longer decay, directional reflections"
|
|
282
|
+
|
|
283
|
+
indoor_small_room:
|
|
284
|
+
decay_time: 0.5s
|
|
285
|
+
pre_delay: 5ms
|
|
286
|
+
wet_mix: 0.25
|
|
287
|
+
diffusion: 0.8
|
|
288
|
+
hf_damping: 0.5
|
|
289
|
+
notes: "Tight, intimate; voices feel close"
|
|
290
|
+
|
|
291
|
+
indoor_large_hall:
|
|
292
|
+
decay_time: 3.0s
|
|
293
|
+
pre_delay: 25ms
|
|
294
|
+
wet_mix: 0.45
|
|
295
|
+
diffusion: 0.9
|
|
296
|
+
hf_damping: 0.3
|
|
297
|
+
notes: "Cavernous; footsteps echo, VO needs ducking"
|
|
298
|
+
|
|
299
|
+
underground_cave:
|
|
300
|
+
decay_time: 4.0s
|
|
301
|
+
pre_delay: 15ms
|
|
302
|
+
wet_mix: 0.55
|
|
303
|
+
diffusion: 0.6
|
|
304
|
+
hf_damping: 0.6
|
|
305
|
+
notes: "Heavy reverb, muffled high end, dripping emphasis"
|
|
306
|
+
|
|
307
|
+
underwater:
|
|
308
|
+
decay_time: 0.3s
|
|
309
|
+
pre_delay: 0ms
|
|
310
|
+
wet_mix: 0.7
|
|
311
|
+
diffusion: 1.0
|
|
312
|
+
hf_damping: 0.9
|
|
313
|
+
low_pass_cutoff: 800Hz
|
|
314
|
+
notes: "Extreme LPF, muted, disorienting"
|
|
315
|
+
|
|
316
|
+
metal_corridor:
|
|
317
|
+
decay_time: 1.2s
|
|
318
|
+
pre_delay: 8ms
|
|
319
|
+
wet_mix: 0.35
|
|
320
|
+
diffusion: 0.4
|
|
321
|
+
hf_damping: 0.1
|
|
322
|
+
notes: "Bright, ringing, metallic character"
|
|
323
|
+
|
|
324
|
+
# Implementation notes:
|
|
325
|
+
# - Blend between presets when crossing zone boundaries (over 0.5-1 second)
|
|
326
|
+
# - Use ray-traced or portal-based occlusion for realistic transitions
|
|
327
|
+
# - Wwise Rooms/Portals automate zone blending; FMOD uses snapshot blending
|
|
328
|
+
# - Apply reverb as a send effect, not an insert, to maintain dry signal clarity
|
|
329
|
+
```
|
|
330
|
+
|
|
331
|
+
### Audio Testing Checklist
|
|
332
|
+
|
|
333
|
+
Before shipping, verify the following across all target platforms:
|
|
334
|
+
|
|
335
|
+
1. **Loudness compliance**: Measure integrated LUFS over a 30-minute representative session. Must be within platform tolerance.
|
|
336
|
+
2. **Clipping/distortion**: Play the loudest possible gameplay scenario (explosion chain, multiple weapons, full music). No digital clipping on the master bus.
|
|
337
|
+
3. **Missing audio**: Walk through every game state and transition. No silent gaps where audio should play.
|
|
338
|
+
4. **Spatial accuracy**: Can the player locate enemies by sound alone with eyes closed? Test with headphones and speakers.
|
|
339
|
+
5. **Ducking behavior**: Is dialogue always audible? Does music duck appropriately? Do critical gameplay sounds cut through?
|
|
340
|
+
6. **Memory budget**: Monitor audio memory throughout a full play session. No leaks, no budget overruns.
|
|
341
|
+
7. **CPU budget**: Audio should consume less than 10% of a single CPU core. Profile during the most audio-dense gameplay moment.
|
|
342
|
+
8. **Platform output**: Test stereo, 5.1, 7.1, and headphone output on each platform. Verify surround panning works correctly.
|
|
343
|
+
9. **Interruption handling**: On mobile, verify correct behavior when a phone call, alarm, or notification interrupts. Audio should pause and resume cleanly.
|
|
344
|
+
10. **Localization**: Every localized VO line plays correctly, subtitles match, lip-sync is acceptable in all supported languages.
|