# V2 Vertical Music Layering

Phase 72.22.1.3 adds vertical layering for Maya adaptive music. It evaluates
instrument stems from the current adaptive state and context tags, then returns
the active layers to add and inactive layers to remove.

## Source Of Truth

- Contract:
  [VerticalMusicLayering_V2_Contract.json](../../ue/Content/V2/Audio/VerticalMusicLayering_V2_Contract.json)
- Runtime module: `V2Audio`
- Core types: `EV2VerticalMusicInstrumentLayer`, `FV2VerticalMusicLayerSpec`,
  `FV2VerticalMusicLayerRequest`, `FV2ResolvedVerticalMusicLayers`, and
  `FV2VerticalMusicLayeringArrangement`
- Builder:
  `UV2AudioBlueprintLibrary::BuildDefaultVerticalMusicLayeringArrangement`
- Validator:
  `UV2AudioBlueprintLibrary::ValidateVerticalMusicLayeringArrangement`
- Resolver: `UV2AudioBlueprintLibrary::ResolveVerticalMusicLayers`
- Registrar: `UV2AudioSubsystem::RegisterVerticalMusicLayeringArrangement`
- Subsystem route: `UV2AudioSubsystem::EvaluateVerticalMusicLayers`
- State input:
  [adaptive-music-state-machine.md](adaptive-music-state-machine.md)

## Instrument Layers

The default arrangement validates `AmbientPad`, `Bass`, `Drums`, and `Strings`
as required launch stems. It also authors `Brass`, `Melody`, and `Choir` layers
for higher-intensity combat and result states.

| State       | Always available           | Conditional layers                     |
| ----------- | -------------------------- | -------------------------------------- |
| Exploration | AmbientPad, Melody         | Strings at `Context.Sunset`            |
| Tension     | AmbientPad, Bass           | Strings at `Context.Sunset`            |
| Combat      | Bass, Drums, Brass, Melody | Drums enter above low combat intensity |
| Victory     | Choir                      | None                                   |
| Defeat      | AmbientPad                 | None                                   |
| Menu        | AmbientPad                 | None                                   |

## Add Remove Rules

`FV2VerticalMusicLayeringArrangement::ResolveLayers` returns active layers and
`RemovedLayerIds`. A layer is active only when its adaptive state, normalized
intensity range, and required context tag match. All other valid authored layers
are reported as removed so the runtime can mute stems that no longer belong to
the current game state.

The named task examples are explicit contract requirements:

- Combat activates `Drums` through `Music.Layer.Combat.Drums`.
- Sunset activates `Strings` through `Context.Sunset` layers.
- Contract behavior ids: `combat-drums-enter`, `sunset-strings-swell`,
  `state-driven-add-remove`, and `inactive-layers-removed`.

## Runtime Evidence

`UV2AudioConfigAsset` owns the default `FV2VerticalMusicLayeringArrangement`.
`UV2AudioSubsystem` registers it, evaluates active layer sets, tracks
`CurrentVerticalMusicLayerIds`, and exposes layer count, active layer count,
add/remove coverage, combat-drums coverage, sunset-strings coverage, and
registration status through `FV2AudioRuntimeSnapshot`.

## Validation Commands

```bash
python3 V2/ue/Tools/check-v2-vertical-music-layering.py
python3 V2/ue/Tools/check-v2-horizontal-music-resequencing.py
python3 V2/ue/Tools/check-v2-adaptive-music-state-machine.py
python3 V2/ue/Tools/check-v2-audio-module.py
python3 -m json.tool V2/ue/Content/V2/Audio/VerticalMusicLayering_V2_Contract.json
python3 V2/tools/validate-v2-docs.py
```
