claude-code-arcane 2.3.0 → 2.4.0
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/CHANGELOG.md +15 -0
- package/README.md +54 -6
- package/agents/game/ue-blueprint-specialist.md +125 -0
- package/agents/game/ue-gas-specialist.md +133 -0
- package/agents/game/ue-umg-specialist.md +131 -0
- package/dist/cli.js +5 -0
- package/docs/SKILLS-CATALOG.md +42 -3
- package/docs/USER-GUIDE.md +2 -2
- package/hooks/detect-unreal.sh +90 -0
- package/package.json +1 -1
- package/profiles/unreal-dev.yaml +97 -0
- package/rules/gamedev/unreal-code.md +125 -0
- package/skills/install-mcp/SKILL.md +135 -46
- package/skills/install-mcp/references/unreal-operations.md +55 -0
- package/skills/ue-actor-component-architecture/SKILL.md +509 -0
- package/skills/ue-actor-component-architecture/references/actor-lifecycle.md +301 -0
- package/skills/ue-actor-component-architecture/references/component-types.md +592 -0
- package/skills/ue-ai-navigation/SKILL.md +526 -0
- package/skills/ue-ai-navigation/references/behavior-tree-patterns.md +392 -0
- package/skills/ue-ai-navigation/references/behavior-tree-workflow.md +107 -0
- package/skills/ue-ai-navigation/references/custom-bttask.md +104 -0
- package/skills/ue-ai-navigation/references/eqs-reference.md +423 -0
- package/skills/ue-animation-system/SKILL.md +521 -0
- package/skills/ue-animation-system/references/anim-notify-reference.md +486 -0
- package/skills/ue-animation-system/references/locomotion-setup.md +550 -0
- package/skills/ue-async-threading/SKILL.md +433 -0
- package/skills/ue-async-threading/references/thread-safety-guide.md +213 -0
- package/skills/ue-async-threading/references/threading-patterns.md +345 -0
- package/skills/ue-audio-system/SKILL.md +527 -0
- package/skills/ue-audio-system/references/audio-setup-patterns.md +700 -0
- package/skills/ue-blueprints/SKILL.md +134 -0
- package/skills/ue-blueprints/references/communication.md +82 -0
- package/skills/ue-character-movement/SKILL.md +475 -0
- package/skills/ue-character-movement/references/cmc-extension-patterns.md +335 -0
- package/skills/ue-character-movement/references/movement-pipeline.md +189 -0
- package/skills/ue-cpp-foundations/SKILL.md +533 -0
- package/skills/ue-cpp-foundations/references/components-and-gc.md +107 -0
- package/skills/ue-cpp-foundations/references/container-patterns.md +544 -0
- package/skills/ue-cpp-foundations/references/delegate-patterns.md +497 -0
- package/skills/ue-cpp-foundations/references/gameplay-classes-cpp.md +136 -0
- package/skills/ue-cpp-foundations/references/property-specifiers.md +306 -0
- package/skills/ue-data-assets-tables/SKILL.md +527 -0
- package/skills/ue-data-assets-tables/references/asset-loading-patterns.md +306 -0
- package/skills/ue-data-assets-tables/references/data-driven-design.md +378 -0
- package/skills/ue-editor-tools/SKILL.md +523 -0
- package/skills/ue-editor-tools/references/detail-customization-patterns.md +395 -0
- package/skills/ue-editor-tools/references/editor-module-setup.md +480 -0
- package/skills/ue-game-features/SKILL.md +477 -0
- package/skills/ue-game-features/references/experience-system.md +222 -0
- package/skills/ue-game-features/references/game-feature-patterns.md +308 -0
- package/skills/ue-gameplay-abilities/SKILL.md +518 -0
- package/skills/ue-gameplay-abilities/references/ability-task-reference.md +391 -0
- package/skills/ue-gameplay-abilities/references/gameplay-effect-reference.md +397 -0
- package/skills/ue-gameplay-abilities/references/gas-setup-patterns.md +369 -0
- package/skills/ue-gameplay-framework/SKILL.md +466 -0
- package/skills/ue-gameplay-framework/references/framework-class-map.md +243 -0
- package/skills/ue-input-system/SKILL.md +394 -0
- package/skills/ue-input-system/references/cpp-setup.md +131 -0
- package/skills/ue-input-system/references/enhanced-input-workflow.md +117 -0
- package/skills/ue-input-system/references/input-action-reference.md +731 -0
- package/skills/ue-mass-entity/SKILL.md +476 -0
- package/skills/ue-mass-entity/references/mass-entity-patterns.md +319 -0
- package/skills/ue-mass-entity/references/mass-fragment-reference.md +119 -0
- package/skills/ue-materials-rendering/SKILL.md +526 -0
- package/skills/ue-materials-rendering/references/material-parameter-reference.md +216 -0
- package/skills/ue-materials-rendering/references/post-process-settings.md +383 -0
- package/skills/ue-module-build-system/SKILL.md +487 -0
- package/skills/ue-module-build-system/references/build-cs-reference.md +418 -0
- package/skills/ue-module-build-system/references/common-build-errors.md +381 -0
- package/skills/ue-naming-conventions/SKILL.md +142 -0
- package/skills/ue-naming-conventions/references/asset-name-modifiers.md +233 -0
- package/skills/ue-naming-conventions/references/content-structure.md +83 -0
- package/skills/ue-networking-replication/SKILL.md +452 -0
- package/skills/ue-networking-replication/references/replication-patterns.md +526 -0
- package/skills/ue-networking-replication/references/rpc-decision-guide.md +393 -0
- package/skills/ue-niagara-effects/SKILL.md +531 -0
- package/skills/ue-niagara-effects/references/niagara-data-interfaces.md +491 -0
- package/skills/ue-niagara-effects/references/niagara-parameter-types.md +153 -0
- package/skills/ue-niagara-effects/references/niagara-workflow.md +115 -0
- package/skills/ue-packaging/SKILL.md +116 -0
- package/skills/ue-physics-collision/SKILL.md +423 -0
- package/skills/ue-physics-collision/references/collision-channel-setup.md +218 -0
- package/skills/ue-physics-collision/references/trace-patterns.md +499 -0
- package/skills/ue-procedural-generation/SKILL.md +505 -0
- package/skills/ue-procedural-generation/references/pcg-node-reference.md +381 -0
- package/skills/ue-procedural-generation/references/procedural-mesh-patterns.md +940 -0
- package/skills/ue-project-context/SKILL.md +305 -0
- package/skills/ue-sequencer-cinematics/SKILL.md +506 -0
- package/skills/ue-sequencer-cinematics/references/sequencer-patterns.md +629 -0
- package/skills/ue-serialization-savegames/SKILL.md +524 -0
- package/skills/ue-serialization-savegames/references/save-system-architecture.md +705 -0
- package/skills/ue-state-trees/SKILL.md +489 -0
- package/skills/ue-state-trees/references/state-tree-mass-integration.md +184 -0
- package/skills/ue-state-trees/references/state-tree-patterns.md +321 -0
- package/skills/ue-testing-debugging/SKILL.md +520 -0
- package/skills/ue-testing-debugging/references/automation-test-patterns.md +387 -0
- package/skills/ue-testing-debugging/references/profiling-commands.md +357 -0
- package/skills/ue-ui-umg-slate/SKILL.md +431 -0
- package/skills/ue-ui-umg-slate/references/common-ui-setup.md +484 -0
- package/skills/ue-ui-umg-slate/references/widget-types.md +487 -0
- package/skills/ue-world-level-streaming/SKILL.md +518 -0
- package/skills/ue-world-level-streaming/references/streaming-patterns.md +414 -0
- package/templates/gamedev/unreal-project-context.md +107 -0
|
@@ -0,0 +1,527 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: ue-audio-system
|
|
3
|
+
description: "UAudioComponent, SoundCue, MetaSound, attenuation, concurrency, audio analysis"
|
|
4
|
+
category: "gamedev"
|
|
5
|
+
argument-hint: "[sound o audio system]"
|
|
6
|
+
user-invocable: true
|
|
7
|
+
allowed-tools: Read, Glob, Grep, Bash, Write, Edit
|
|
8
|
+
---
|
|
9
|
+
|
|
10
|
+
# UE Audio System
|
|
11
|
+
|
|
12
|
+
You are an expert in Unreal Engine's audio systems, covering UAudioComponent, sound asset types,
|
|
13
|
+
spatial attenuation, concurrency management, submix routing, MetaSounds, and runtime audio analysis.
|
|
14
|
+
|
|
15
|
+
Ask before writing: this skill edits audio components, MetaSound and Sound Cue assets. Propose the change and get approval before using Write or Edit.
|
|
16
|
+
|
|
17
|
+
## Context Check
|
|
18
|
+
|
|
19
|
+
Before implementing audio, read `docs/unreal/project-context.md` for:
|
|
20
|
+
|
|
21
|
+
- **Audio plugins** enabled (Resonance Audio, Steam Audio, Wwise, FMOD, MetaSound plugin version)
|
|
22
|
+
- **Target platforms** — mobile has strict voice limits; consoles differ from PC
|
|
23
|
+
- **Dedicated server** flag — audio must be skipped server-side or it will crash/log errors
|
|
24
|
+
- **VR flag** — VR projects require binaural spatialization settings
|
|
25
|
+
|
|
26
|
+
## Information Gathering
|
|
27
|
+
|
|
28
|
+
Ask about:
|
|
29
|
+
|
|
30
|
+
1. One-shot SFX, looping ambient, music, UI feedback, or dialogue?
|
|
31
|
+
2. Spatialized (follows actor) or global 2D?
|
|
32
|
+
3. Concurrency concern (gunshots, footsteps, explosions)?
|
|
33
|
+
4. Runtime control needed (fade, pause, parameter changes)?
|
|
34
|
+
5. MetaSound procedural or pre-authored SoundCue/SoundWave?
|
|
35
|
+
|
|
36
|
+
---
|
|
37
|
+
|
|
38
|
+
## Sound Asset Hierarchy
|
|
39
|
+
|
|
40
|
+
```
|
|
41
|
+
USoundBase // abstract base (SoundBase.h)
|
|
42
|
+
├── USoundWave // raw PCM/compressed audio asset
|
|
43
|
+
├── USoundCue // node-graph: random, modulator, mixer, attenuator nodes
|
|
44
|
+
└── UMetaSoundSource // procedural audio graph (MetaSound plugin)
|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
**USoundWave** — Import .wav/.ogg/.flac. Set `SoundClassObject` and `AttenuationSettings` on asset.
|
|
48
|
+
|
|
49
|
+
**USoundCue** — Node graph combining multiple waves. Key nodes:
|
|
50
|
+
`USoundNodeRandom`, `USoundNodeModulator`, `USoundNodeMixer`, `USoundNodeAttenuation`,
|
|
51
|
+
`USoundNodeLooping`, `USoundNodeDelay`, `USoundNodeDistanceCrossFade`.
|
|
52
|
+
|
|
53
|
+
**UMetaSoundSource** — Procedural audio graph. Declare typed inputs (float, bool, int32, trigger).
|
|
54
|
+
Set parameters at runtime via `UAudioComponent::SetFloatParameter`, `SetBoolParameter`, `SetIntParameter`.
|
|
55
|
+
|
|
56
|
+
### Streaming Long Audio
|
|
57
|
+
|
|
58
|
+
For music and ambient tracks exceeding ~30 seconds, set `USoundWave::LoadingBehavior`:
|
|
59
|
+
`ESoundWaveLoadingBehavior::ForceInline` for short SFX, `RetainOnLoad` for music loaded at level start.
|
|
60
|
+
Long files should use `LoadOnDemand` to avoid loading the full waveform into memory.
|
|
61
|
+
In the editor: SoundWave asset → Details → Loading → Loading Behavior.
|
|
62
|
+
|
|
63
|
+
---
|
|
64
|
+
|
|
65
|
+
## Playing Sounds from C++
|
|
66
|
+
|
|
67
|
+
### Fire-and-Forget
|
|
68
|
+
|
|
69
|
+
```cpp
|
|
70
|
+
#include "Kismet/GameplayStatics.h"
|
|
71
|
+
|
|
72
|
+
// 2D — not spatialized (UI, music)
|
|
73
|
+
UGameplayStatics::PlaySound2D(
|
|
74
|
+
this, ImpactSound, 1.0f /*Vol*/, 1.0f /*Pitch*/, 0.0f /*StartTime*/,
|
|
75
|
+
ConcurrencySettings, OwningActor
|
|
76
|
+
);
|
|
77
|
+
|
|
78
|
+
// 3D — spatialized, requires AttenuationSettings on the sound asset
|
|
79
|
+
UGameplayStatics::PlaySoundAtLocation(
|
|
80
|
+
this, GunShotSound, GetActorLocation(), FRotator::ZeroRotator,
|
|
81
|
+
1.0f, 1.0f, 0.0f,
|
|
82
|
+
AttenuationOverride, // USoundAttenuation* (nullptr = use asset default)
|
|
83
|
+
ConcurrencyOverride, // USoundConcurrency* (nullptr = use asset default)
|
|
84
|
+
this // OwningActor for per-owner concurrency
|
|
85
|
+
);
|
|
86
|
+
```
|
|
87
|
+
|
|
88
|
+
### Spawn with Handle
|
|
89
|
+
|
|
90
|
+
```cpp
|
|
91
|
+
// Returns UAudioComponent* — auto-destroyed when sound finishes if bAutoDestroy=true
|
|
92
|
+
UAudioComponent* Comp = UGameplayStatics::SpawnSoundAtLocation(
|
|
93
|
+
this, ExplosionSound, Location, FRotator::ZeroRotator,
|
|
94
|
+
1.0f, 1.0f, 0.0f, AttenuationSettings, nullptr, /*bAutoDestroy=*/true
|
|
95
|
+
);
|
|
96
|
+
|
|
97
|
+
// Attach to a moving component (vehicle engine)
|
|
98
|
+
UAudioComponent* EngineAudio = UGameplayStatics::SpawnSoundAttached(
|
|
99
|
+
EngineLoopSound, GetMesh(), NAME_None,
|
|
100
|
+
FVector::ZeroVector, FRotator::ZeroRotator,
|
|
101
|
+
EAttachLocation::SnapToTargetIncludingScale,
|
|
102
|
+
/*bStopWhenAttachedToDestroyed=*/true,
|
|
103
|
+
1.0f, 1.0f, 0.0f, AttenuationSettings, nullptr,
|
|
104
|
+
/*bAutoDestroy=*/false // keep alive for looping
|
|
105
|
+
);
|
|
106
|
+
```
|
|
107
|
+
|
|
108
|
+
### UAudioComponent as Permanent Actor Component
|
|
109
|
+
|
|
110
|
+
```cpp
|
|
111
|
+
// In constructor:
|
|
112
|
+
AudioComponent = CreateDefaultSubobject<UAudioComponent>(TEXT("AudioComponent"));
|
|
113
|
+
AudioComponent->SetupAttachment(RootComponent);
|
|
114
|
+
AudioComponent->bAutoActivate = false;
|
|
115
|
+
AudioComponent->bStopWhenOwnerDestroyed = true;
|
|
116
|
+
```
|
|
117
|
+
|
|
118
|
+
### Playback Control
|
|
119
|
+
|
|
120
|
+
```cpp
|
|
121
|
+
AudioComponent->SetSound(EngineLoopSound);
|
|
122
|
+
AudioComponent->Play(/*StartTime=*/0.0f);
|
|
123
|
+
AudioComponent->Stop();
|
|
124
|
+
AudioComponent->SetPaused(true);
|
|
125
|
+
AudioComponent->FadeIn(0.5f, 1.0f, 0.0f, EAudioFaderCurve::Linear);
|
|
126
|
+
AudioComponent->FadeOut(1.0f, 0.0f, EAudioFaderCurve::Linear);
|
|
127
|
+
AudioComponent->SetVolumeMultiplier(0.5f);
|
|
128
|
+
AudioComponent->SetPitchMultiplier(1.2f);
|
|
129
|
+
|
|
130
|
+
// Query play state (EAudioComponentPlayState: Playing, Stopped, Paused, FadingIn, FadingOut)
|
|
131
|
+
EAudioComponentPlayState State = AudioComponent->GetPlayState();
|
|
132
|
+
```
|
|
133
|
+
|
|
134
|
+
### Delegates (AudioComponent.h)
|
|
135
|
+
|
|
136
|
+
```cpp
|
|
137
|
+
// Declared in AudioComponent.h:
|
|
138
|
+
// DECLARE_DYNAMIC_MULTICAST_DELEGATE(FOnAudioFinished)
|
|
139
|
+
// DECLARE_DYNAMIC_MULTICAST_DELEGATE_TwoParams(FOnAudioPlaybackPercent, const USoundWave*, PlayingSoundWave, const float, PlaybackPercent)
|
|
140
|
+
// DECLARE_DYNAMIC_MULTICAST_DELEGATE_OneParam(FOnAudioPlayStateChanged, EAudioComponentPlayState, PlayState)
|
|
141
|
+
|
|
142
|
+
AudioComponent->OnAudioFinished.AddDynamic(this, &AMyActor::OnSoundFinished);
|
|
143
|
+
AudioComponent->OnAudioPlaybackPercent.AddDynamic(this, &AMyActor::OnPlaybackPercent);
|
|
144
|
+
AudioComponent->OnAudioPlayStateChanged.AddDynamic(this, &AMyActor::OnPlayStateChanged);
|
|
145
|
+
|
|
146
|
+
// Native (non-UObject) binding — no GC overhead:
|
|
147
|
+
// DECLARE_MULTICAST_DELEGATE_OneParam(FOnAudioFinishedNative, UAudioComponent*)
|
|
148
|
+
// DECLARE_MULTICAST_DELEGATE_ThreeParams(FOnAudioPlaybackPercentNative, const UAudioComponent*, const USoundWave*, const float)
|
|
149
|
+
AudioComponent->OnAudioFinishedNative.AddUObject(this, &AMyActor::OnSoundFinishedNative);
|
|
150
|
+
AudioComponent->OnAudioPlaybackPercentNative.AddUObject(this, &AMyActor::OnPlaybackPercentNative);
|
|
151
|
+
```
|
|
152
|
+
|
|
153
|
+
---
|
|
154
|
+
|
|
155
|
+
## Sound Attenuation (SoundAttenuation.h)
|
|
156
|
+
|
|
157
|
+
Defined in `USoundAttenuation` assets (wrapping `FSoundAttenuationSettings`).
|
|
158
|
+
Assign via `USoundBase::AttenuationSettings` or pass as override to play functions.
|
|
159
|
+
|
|
160
|
+
**Attenuation shapes** (`EAttenuationShape`): `Sphere` (default, omnidirectional), `Capsule` (elongated sources), `Box` (room-shaped), `Cone` (directional like spotlights).
|
|
161
|
+
|
|
162
|
+
**Distance model** (`EAttenuationDistanceModel`): `Linear`, `Logarithmic` (realistic), `NaturalSound` (perception-matched, recommended), `Inverse`, `LogReverse`, `Custom` (curve-driven).
|
|
163
|
+
|
|
164
|
+
```cpp
|
|
165
|
+
// Key FSoundAttenuationSettings fields:
|
|
166
|
+
uint8 bAttenuate : 1; // enable distance-based volume falloff
|
|
167
|
+
uint8 bSpatialize : 1; // enable 3D spatialization
|
|
168
|
+
// SpatializationAlgorithm: SPATIALIZATION_Default (panning), SPATIALIZATION_HRTF (binaural plugin)
|
|
169
|
+
|
|
170
|
+
uint8 bAttenuateWithLPF : 1; // air absorption (distance-based lowpass)
|
|
171
|
+
float LPFRadiusMin; // LPF starts at this distance (cm)
|
|
172
|
+
float LPFRadiusMax; // LPF fully applied at this distance
|
|
173
|
+
float LPFFrequencyAtMin; // Hz at min distance (e.g. 20000.f = bypass)
|
|
174
|
+
float LPFFrequencyAtMax; // Hz at max distance (e.g. 800.f = muffled)
|
|
175
|
+
|
|
176
|
+
uint8 bEnableListenerFocus : 1;
|
|
177
|
+
float FocusAzimuth; // in-focus cone half-angle (degrees)
|
|
178
|
+
float NonFocusAzimuth; // non-focus cone half-angle (degrees)
|
|
179
|
+
float FocusDistanceScale; // < 1.0 makes focused sound seem closer
|
|
180
|
+
float NonFocusVolumeAttenuation;
|
|
181
|
+
|
|
182
|
+
uint8 bEnableOcclusion : 1;
|
|
183
|
+
TEnumAsByte<ECollisionChannel> OcclusionTraceChannel; // e.g. ECC_Visibility
|
|
184
|
+
float OcclusionLowPassFilterFrequency; // Hz when fully occluded
|
|
185
|
+
float OcclusionVolumeAttenuation; // 0..1 volume scale when occluded
|
|
186
|
+
float OcclusionInterpolationTime; // seconds to interpolate
|
|
187
|
+
|
|
188
|
+
uint8 bEnableReverbSend : 1;
|
|
189
|
+
EReverbSendMethod ReverbSendMethod; // Linear, CustomCurve, Manual
|
|
190
|
+
float ReverbWetLevelMin;
|
|
191
|
+
float ReverbWetLevelMax;
|
|
192
|
+
float ReverbDistanceMin;
|
|
193
|
+
float ReverbDistanceMax;
|
|
194
|
+
|
|
195
|
+
uint8 bEnablePriorityAttenuation : 1; // reduce priority of distant sounds
|
|
196
|
+
float PriorityAttenuationMin;
|
|
197
|
+
float PriorityAttenuationMax;
|
|
198
|
+
|
|
199
|
+
// Override attenuation inline on a UAudioComponent:
|
|
200
|
+
AudioComponent->bOverrideAttenuation = true;
|
|
201
|
+
AudioComponent->AttenuationOverrides.bAttenuate = true;
|
|
202
|
+
AudioComponent->AttenuationOverrides.bSpatialize = true;
|
|
203
|
+
AudioComponent->AttenuationOverrides.FalloffDistance = 3000.f;
|
|
204
|
+
```
|
|
205
|
+
|
|
206
|
+
### Audio LOD
|
|
207
|
+
|
|
208
|
+
Distant sounds can skip processing. Use `bAttenuateWithLPF = true` with `LPFRadiusMin`/`LPFRadiusMax`
|
|
209
|
+
to low-pass-filter far sounds before full attenuation drops them. Set `bEnableSendToAudioLink = false`
|
|
210
|
+
for background ambience that does not need external routing. `USoundBase::Priority` (0.0–100.0, default 1.0, higher =
|
|
211
|
+
more important) determines which voices survive when hitting the max channel count set in Audio Settings.
|
|
212
|
+
|
|
213
|
+
---
|
|
214
|
+
|
|
215
|
+
## Concurrency (SoundConcurrency.h)
|
|
216
|
+
|
|
217
|
+
`USoundConcurrency` controls simultaneous voice count. Assign via
|
|
218
|
+
`USoundBase::ConcurrencySet` (`TSet<USoundConcurrency*>`) or `ConcurrencyOverrides`
|
|
219
|
+
(inline `FSoundConcurrencySettings` when `bOverrideConcurrency = true`).
|
|
220
|
+
|
|
221
|
+
```cpp
|
|
222
|
+
// FSoundConcurrencySettings key fields:
|
|
223
|
+
int32 MaxCount; // max simultaneous voices in this group
|
|
224
|
+
// USoundBase::Priority (0.0–100.0, default 1.0) determines which voices survive at MaxCount
|
|
225
|
+
uint8 bLimitToOwner : 1; // limit per owning actor if true
|
|
226
|
+
TEnumAsByte<EMaxConcurrentResolutionRule::Type> ResolutionRule;
|
|
227
|
+
// PreventNew | StopOldest | StopFarthestThenPreventNew | StopFarthestThenOldest
|
|
228
|
+
// StopLowestPriority | StopQuietest | StopLowestPriorityThenPreventNew
|
|
229
|
+
float RetriggerTime; // minimum seconds between plays in this group
|
|
230
|
+
float VoiceStealReleaseTime; // fade duration (s) for evicted sounds
|
|
231
|
+
EConcurrencyVolumeScaleMode VolumeScaleMode; // Default | Distance | Priority
|
|
232
|
+
float VolumeScaleAttackTime;
|
|
233
|
+
float VolumeScaleReleaseTime;
|
|
234
|
+
```
|
|
235
|
+
|
|
236
|
+
---
|
|
237
|
+
|
|
238
|
+
## Submixes and Sound Classes (SoundSubmix.h)
|
|
239
|
+
|
|
240
|
+
```
|
|
241
|
+
USoundSubmixBase (abstract)
|
|
242
|
+
USoundSubmixWithParentBase
|
|
243
|
+
USoundSubmix // standard submix with effects chain
|
|
244
|
+
USoundfieldSubmix // ambisonics / soundfield
|
|
245
|
+
UEndpointSubmix // external endpoint (haptics, extra device)
|
|
246
|
+
```
|
|
247
|
+
|
|
248
|
+
Typical tree: Master > {Music, SFX, Voice, Ambient}. Music submix uses `bMuteWhenBackgrounded = true`.
|
|
249
|
+
|
|
250
|
+
```cpp
|
|
251
|
+
// Runtime volume control:
|
|
252
|
+
MusicSubmix->SetSubmixOutputVolume(this, 0.5f); // linear gain multiplier
|
|
253
|
+
MusicSubmix->SetSubmixWetLevel(this, 1.0f);
|
|
254
|
+
MusicSubmix->SetSubmixDryLevel(this, 0.0f);
|
|
255
|
+
|
|
256
|
+
// Dynamic parenting:
|
|
257
|
+
MyChildSubmix->DynamicConnect(this, MasterSubmix);
|
|
258
|
+
MyChildSubmix->DynamicDisconnect(this);
|
|
259
|
+
```
|
|
260
|
+
|
|
261
|
+
`USoundSubmix::SubmixEffectChain` holds `USoundEffectSubmixPreset` assets
|
|
262
|
+
(reverb `USubmixEffectReverbPreset`, EQ `USubmixEffectEQPreset`, dynamics).
|
|
263
|
+
|
|
264
|
+
### Submix Effect Chain
|
|
265
|
+
|
|
266
|
+
```cpp
|
|
267
|
+
// Add reverb to a submix at runtime
|
|
268
|
+
USoundSubmix* ReverbSubmix = LoadObject<USoundSubmix>(nullptr,
|
|
269
|
+
TEXT("/Game/Audio/Submixes/ReverbSubmix"));
|
|
270
|
+
USubmixEffectReverbPreset* Preset = NewObject<USubmixEffectReverbPreset>();
|
|
271
|
+
Preset->Settings.Density = 0.85f;
|
|
272
|
+
Preset->Settings.Diffusion = 0.8f;
|
|
273
|
+
Preset->Settings.DecayTime = 2.5f;
|
|
274
|
+
ReverbSubmix->SubmixEffectChain.Add(Preset);
|
|
275
|
+
```
|
|
276
|
+
|
|
277
|
+
**Sound classes** define volume/pitch hierarchy parallel to submixes. Assign via `USoundBase::SoundClassObject`.
|
|
278
|
+
|
|
279
|
+
```cpp
|
|
280
|
+
// Sound Mix modifiers — layer temporary volume/pitch adjustments by sound class:
|
|
281
|
+
UGameplayStatics::SetBaseSoundMix(this, DefaultMix); // set the base mix (usually once)
|
|
282
|
+
UGameplayStatics::PushSoundMixModifier(this, CombatMix); // push a modifier (stacks)
|
|
283
|
+
// ... later, when leaving combat:
|
|
284
|
+
UGameplayStatics::PopSoundMixModifier(this, CombatMix); // remove the modifier layer
|
|
285
|
+
// ClearSoundMixModifiers removes all pushed modifiers at once
|
|
286
|
+
UGameplayStatics::ClearSoundMixModifiers(this);
|
|
287
|
+
```
|
|
288
|
+
|
|
289
|
+
`USoundMix` assets define per-`USoundClass` volume and pitch adjustments. Push/pop lets you layer context-dependent audio profiles (combat, stealth, underwater) without manual volume bookkeeping.
|
|
290
|
+
|
|
291
|
+
---
|
|
292
|
+
|
|
293
|
+
## MetaSounds
|
|
294
|
+
|
|
295
|
+
`UMetaSoundSource` derives from `USoundBase` — plays anywhere a `USoundBase` is accepted.
|
|
296
|
+
|
|
297
|
+
```cpp
|
|
298
|
+
// UAudioComponent implements ISoundParameterControllerInterface:
|
|
299
|
+
MetaComp->SetFloatParameter(FName("Pitch"), 1.5f);
|
|
300
|
+
MetaComp->SetBoolParameter(FName("IsUnderwater"), true);
|
|
301
|
+
MetaComp->SetIntParameter(FName("SurfaceType"), 2);
|
|
302
|
+
MetaComp->SetTriggerParameter(FName("OnImpact")); // impulse trigger input
|
|
303
|
+
MetaComp->ResetParameters();
|
|
304
|
+
```
|
|
305
|
+
|
|
306
|
+
| Criterion | SoundCue | MetaSound |
|
|
307
|
+
|---|---|---|
|
|
308
|
+
| Runtime parameters | Limited (wave params) | Typed inputs, full parameter system |
|
|
309
|
+
| Procedural audio | No | Yes (oscillators, noise, DSP filters) |
|
|
310
|
+
| Reactive to gameplay | Via parameter nodes | Native — bind any float/bool/trigger |
|
|
311
|
+
| Use when | Randomized pre-authored sounds | Adaptive music, procedural SFX, state-driven audio |
|
|
312
|
+
|
|
313
|
+
---
|
|
314
|
+
|
|
315
|
+
## Submix Spectrum Analysis and Envelope Following (SoundSubmix.h)
|
|
316
|
+
|
|
317
|
+
```cpp
|
|
318
|
+
// Envelope following:
|
|
319
|
+
SFXSubmix->StartEnvelopeFollowing(this);
|
|
320
|
+
FOnSubmixEnvelopeBP Env;
|
|
321
|
+
Env.BindDynamic(this, &AMyActor::OnSubmixEnvelope);
|
|
322
|
+
SFXSubmix->AddEnvelopeFollowerDelegate(this, Env);
|
|
323
|
+
SFXSubmix->StopEnvelopeFollowing(this);
|
|
324
|
+
// Callback: void OnSubmixEnvelope(const TArray<float>& Envelope);
|
|
325
|
+
|
|
326
|
+
// Spectrum analysis:
|
|
327
|
+
SFXSubmix->StartSpectralAnalysis(this,
|
|
328
|
+
EFFTSize::Medium, EFFTPeakInterpolationMethod::Linear,
|
|
329
|
+
EFFTWindowType::Hann, 0.0f, EAudioSpectrumType::MagnitudeSpectrum
|
|
330
|
+
);
|
|
331
|
+
|
|
332
|
+
TArray<FSoundSubmixSpectralAnalysisBandSettings> Bands;
|
|
333
|
+
FSoundSubmixSpectralAnalysisBandSettings LowBand;
|
|
334
|
+
LowBand.BandFrequency = 80.f; LowBand.AttackTimeMsec = 10.f; LowBand.ReleaseTimeMsec = 100.f;
|
|
335
|
+
Bands.Add(LowBand);
|
|
336
|
+
|
|
337
|
+
FOnSubmixSpectralAnalysisBP Spectral;
|
|
338
|
+
Spectral.BindDynamic(this, &AMyActor::OnSpectralAnalysis);
|
|
339
|
+
SFXSubmix->AddSpectralAnalysisDelegate(
|
|
340
|
+
this, Bands, Spectral,
|
|
341
|
+
30.f /*UpdateRateHz*/, -40.f /*DecibelFloor*/, true /*Normalize*/, false /*AutoRange*/
|
|
342
|
+
);
|
|
343
|
+
SFXSubmix->StopSpectralAnalysis(this);
|
|
344
|
+
// Callback: void OnSpectralAnalysis(const TArray<float>& Magnitudes);
|
|
345
|
+
```
|
|
346
|
+
|
|
347
|
+
---
|
|
348
|
+
|
|
349
|
+
## Module Dependencies
|
|
350
|
+
|
|
351
|
+
```csharp
|
|
352
|
+
// In .Build.cs:
|
|
353
|
+
PublicDependencyModuleNames.AddRange(new string[] { "Engine", "AudioMixer" });
|
|
354
|
+
PublicDependencyModuleNames.Add("MetasoundEngine"); // for MetaSound parameters
|
|
355
|
+
PublicDependencyModuleNames.Add("MetasoundFrontend");
|
|
356
|
+
```
|
|
357
|
+
|
|
358
|
+
```cpp
|
|
359
|
+
#include "Components/AudioComponent.h"
|
|
360
|
+
#include "Kismet/GameplayStatics.h"
|
|
361
|
+
#include "Sound/SoundBase.h"
|
|
362
|
+
#include "Sound/SoundCue.h"
|
|
363
|
+
#include "Sound/SoundWave.h"
|
|
364
|
+
#include "Sound/SoundAttenuation.h"
|
|
365
|
+
#include "Sound/SoundConcurrency.h"
|
|
366
|
+
#include "Sound/SoundSubmix.h"
|
|
367
|
+
```
|
|
368
|
+
|
|
369
|
+
---
|
|
370
|
+
|
|
371
|
+
## Audio Analysis
|
|
372
|
+
|
|
373
|
+
### Submix Spectrum and Envelope
|
|
374
|
+
|
|
375
|
+
See the existing submix analysis section above for real-time analysis via `USoundSubmix`.
|
|
376
|
+
|
|
377
|
+
### Non-Real-Time Analysis (NRT)
|
|
378
|
+
|
|
379
|
+
`UAudioAnalyzerNRT` is the abstract base class for offline analyzers. `ULoudnessNRT` and `UOnsetNRT` derive from `UAudioSynesthesiaNRT`, which in turn derives from `UAudioAnalyzerNRT`.
|
|
380
|
+
|
|
381
|
+
For offline audio analysis (e.g., beat detection for rhythmic gameplay), use the Audio Synesthesia plugin:
|
|
382
|
+
|
|
383
|
+
```cpp
|
|
384
|
+
// Build.cs: "AudioSynesthesia"
|
|
385
|
+
#include "AudioSynesthesiaModule.h"
|
|
386
|
+
|
|
387
|
+
// Create an analyzer — LoudnessNRT analyzes an entire sound asset offline
|
|
388
|
+
ULoudnessNRT* Analyzer = NewObject<ULoudnessNRT>();
|
|
389
|
+
ULoudnessNRTSettings* Settings = NewObject<ULoudnessNRTSettings>();
|
|
390
|
+
Settings->AnalysisPeriod = 0.01f; // 10ms windows
|
|
391
|
+
|
|
392
|
+
Analyzer->Settings = Settings;
|
|
393
|
+
Analyzer->Sound = MySoundWave;
|
|
394
|
+
Analyzer->AnalyzeAudio(); // WITH_EDITOR only; call from editor utility or cook-time code
|
|
395
|
+
|
|
396
|
+
// Query results at specific timestamps
|
|
397
|
+
float Loudness;
|
|
398
|
+
Analyzer->GetLoudnessAtTime(1.5f, Loudness);
|
|
399
|
+
|
|
400
|
+
// For beat detection, use OnsetNRT:
|
|
401
|
+
UOnsetNRT* OnsetAnalyzer = NewObject<UOnsetNRT>();
|
|
402
|
+
OnsetAnalyzer->Sound = MySoundWave;
|
|
403
|
+
OnsetAnalyzer->AnalyzeAudio(); // WITH_EDITOR only
|
|
404
|
+
TArray<float> OnsetTimestamps;
|
|
405
|
+
TArray<float> OnsetStrengths;
|
|
406
|
+
OnsetAnalyzer->GetNormalizedChannelOnsetsBetweenTimes(
|
|
407
|
+
0.f, Duration, 0, OnsetTimestamps, OnsetStrengths);
|
|
408
|
+
```
|
|
409
|
+
|
|
410
|
+
**Why NRT**: Pre-analyze tracks to generate beat maps, loudness curves, or onset markers. Use the data at runtime for music-driven gameplay without per-frame FFT overhead.
|
|
411
|
+
|
|
412
|
+
---
|
|
413
|
+
|
|
414
|
+
## Common Mistakes and Anti-Patterns
|
|
415
|
+
|
|
416
|
+
**Spawning a new AudioComponent every fire event**
|
|
417
|
+
```cpp
|
|
418
|
+
// WRONG — leaks a component instance per call
|
|
419
|
+
UAudioComponent* Comp = NewObject<UAudioComponent>(this);
|
|
420
|
+
Comp->SetSound(FireSound); Comp->Play();
|
|
421
|
+
|
|
422
|
+
// CORRECT — fire-and-forget for one-shots
|
|
423
|
+
UGameplayStatics::PlaySoundAtLocation(this, FireSound, GetActorLocation());
|
|
424
|
+
// CORRECT — cache a single component for repeated/looping sounds
|
|
425
|
+
if (!CachedFireAudio) { CachedFireAudio = UGameplayStatics::SpawnSoundAttached(..., /*bAutoDestroy=*/false); }
|
|
426
|
+
CachedFireAudio->Play();
|
|
427
|
+
```
|
|
428
|
+
|
|
429
|
+
**Playing 3D sounds without attenuation**
|
|
430
|
+
```cpp
|
|
431
|
+
// WRONG — full volume at any distance
|
|
432
|
+
UGameplayStatics::PlaySoundAtLocation(this, FootstepSound, Location);
|
|
433
|
+
// CORRECT — pass or assign USoundAttenuation with sphere falloff tuned to gameplay scale
|
|
434
|
+
```
|
|
435
|
+
|
|
436
|
+
**Ignoring concurrency on high-frequency sounds**
|
|
437
|
+
```cpp
|
|
438
|
+
// WRONG — 20 simultaneous explosions with default concurrency
|
|
439
|
+
UGameplayStatics::PlaySoundAtLocation(this, ExplosionSound, Location);
|
|
440
|
+
// CORRECT — pass USoundConcurrency: MaxCount=4, ResolutionRule=StopFarthestThenOldest
|
|
441
|
+
```
|
|
442
|
+
|
|
443
|
+
**Playing audio on a dedicated server**
|
|
444
|
+
```cpp
|
|
445
|
+
// WRONG — FAudioDevice not initialized on server, causes crash/log spam
|
|
446
|
+
void AWeapon::Fire() { UGameplayStatics::PlaySoundAtLocation(this, FireSound, GetActorLocation()); }
|
|
447
|
+
// CORRECT
|
|
448
|
+
void AWeapon::Fire() {
|
|
449
|
+
if (GetNetMode() != NM_DedicatedServer) {
|
|
450
|
+
UGameplayStatics::PlaySoundAtLocation(this, FireSound, GetActorLocation());
|
|
451
|
+
}
|
|
452
|
+
}
|
|
453
|
+
```
|
|
454
|
+
|
|
455
|
+
**Forgetting to unbind delegates before destruction**
|
|
456
|
+
```cpp
|
|
457
|
+
// In EndPlay:
|
|
458
|
+
if (AudioComponent) { AudioComponent->OnAudioFinished.RemoveAll(this); AudioComponent->Stop(); }
|
|
459
|
+
```
|
|
460
|
+
|
|
461
|
+
**Using PlaySound2D for in-world sounds**
|
|
462
|
+
```cpp
|
|
463
|
+
// WRONG — no attenuation or spatialization
|
|
464
|
+
UGameplayStatics::PlaySound2D(this, GunShot);
|
|
465
|
+
// CORRECT
|
|
466
|
+
UGameplayStatics::PlaySoundAtLocation(this, GunShot, GetActorLocation());
|
|
467
|
+
```
|
|
468
|
+
|
|
469
|
+
---
|
|
470
|
+
|
|
471
|
+
## Platform and Edge Case Considerations
|
|
472
|
+
|
|
473
|
+
- **Mobile** — 16–32 voice limit. Use aggressive concurrency. Prefer resident loading for SFX. Disable HRTF unless the platform supports it.
|
|
474
|
+
- **Dedicated servers** — Guard all audio calls with `GetNetMode() != NM_DedicatedServer`.
|
|
475
|
+
- **Streaming audio** — Set `LoadingBehavior = LoadOnDemand` on long music SoundWave assets. Never load minutes of music resident.
|
|
476
|
+
- **App focus loss** — Set `bMuteWhenBackgrounded = true` on music/SFX submixes. For custom handling:
|
|
477
|
+
|
|
478
|
+
### Focus Loss Handling
|
|
479
|
+
|
|
480
|
+
```cpp
|
|
481
|
+
// In your GameInstance or AudioManager
|
|
482
|
+
FCoreDelegates::ApplicationWillDeactivateDelegate.AddUObject(
|
|
483
|
+
this, &UMyAudioManager::OnAppDeactivate);
|
|
484
|
+
|
|
485
|
+
void UMyAudioManager::OnAppDeactivate()
|
|
486
|
+
{
|
|
487
|
+
FAudioDeviceHandle Device = GEngine->GetMainAudioDevice();
|
|
488
|
+
if (Device.IsValid()) { Device->SetTransientPrimaryVolume(0.f); }
|
|
489
|
+
}
|
|
490
|
+
```
|
|
491
|
+
|
|
492
|
+
- **VR** — Enable `bSpatialize = true` and `SpatializationAlgorithm = SPATIALIZATION_HRTF` on all 3D attenuation assets.
|
|
493
|
+
- **Audio LOD** — Use `bEnablePriorityAttenuation` to reduce priority of distant sounds before voice-budget culling.
|
|
494
|
+
|
|
495
|
+
---
|
|
496
|
+
|
|
497
|
+
## Related Skills
|
|
498
|
+
|
|
499
|
+
- `/ue-actor-component-architecture` — UAudioComponent lifetime, attachment, and replication patterns
|
|
500
|
+
- `/ue-niagara-effects` — synchronizing audio events with particle system callbacks
|
|
501
|
+
- `/ue-cpp-foundations` — delegate binding patterns, UPROPERTY and UFUNCTION macros
|
|
502
|
+
- `/ue-naming-conventions` — asset prefixes and Content folder layout for these assets
|
|
503
|
+
|
|
504
|
+
## Reference Files
|
|
505
|
+
|
|
506
|
+
- `references/audio-setup-patterns.md` — attenuation, concurrency and submix setup patterns
|
|
507
|
+
|
|
508
|
+
---
|
|
509
|
+
|
|
510
|
+
## Checklist
|
|
511
|
+
|
|
512
|
+
Validate before considering the work done:
|
|
513
|
+
|
|
514
|
+
- [ ] Concurrency and priority are configured so voice count stays bounded
|
|
515
|
+
- [ ] Attenuation settings are shared through assets rather than tuned per instance
|
|
516
|
+
- [ ] Sounds are not started every frame or on every overlap event
|
|
517
|
+
- [ ] Conventions in `docs/unreal/project-context.md` were read and followed
|
|
518
|
+
- [ ] The Common Mistakes section of this skill was reviewed against the change
|
|
519
|
+
|
|
520
|
+
**PASS** — every item holds. **CONCERNS** — the work stands but at least one item is unresolved and worth flagging to the user. **FAIL** — an item is violated in a way that breaks correctness, replication or the frame budget; fix it before handing the work over.
|
|
521
|
+
|
|
522
|
+
## Next Steps
|
|
523
|
+
|
|
524
|
+
- `/audio-mix` — place the new sounds in the bus hierarchy (install the `audio` profile: `arcane add +audio`)
|
|
525
|
+
- `/audio-audit` — check voice count, memory and loudness (same profile)
|
|
526
|
+
- `/code-review` — architectural and quality review of the change
|
|
527
|
+
- `/commit` — conventional commit once the change is verified
|