Pepper.SFX
All Guidance pages

Guidance / Cookbook

Per-Zone Reverb

The “wet path” sibling of the occlusion section. SFX voices send a copy of their dry signal to a per-zone reverb bus; each bus’s character is defined by its ReverbSendBus asset, which is the single source of truth (the zone only decides which bus a voice sends to). See Manual chapter 15 for the architecture.

🧱 Prerequisite: the Occlusion Slot Pool must already be authored. Reverb sends are written into the voice’s occlusion slot — no slot, no sends. If you haven’t done it yet, jump to Occluding SFX Through Geometry → One-Time Project Setup first. Come back here once the layout exists.

⚠️ Silent failures to know up front

  • A bus’s character lives on its ReverbSendBus asset, not the zone. A new bus’s Room is 0 mB (millibels; full level), so it’s audible once generated. A bus whose Room has been turned down to -10000 mB is silent until you raise it. Tagging a zone and pointing its Reverb Bus at that asset routes voices there, but the sound comes from the asset.
  • The Reverb Bus field on AudioZone wants the mixer group reference inside the SendBus asset — not the SendBus asset itself. Drag from the SendBus’s ReverbBus field, not from the Project window.
  • AudioManager.Reverb Send Bus Registry must be assigned. Without it, the registry is empty and nothing routes.
  • After adding a new bus, re-run the Occlusion Layout Builder so existing slots get the new bus’s Send parameter authored. Skipping this means existing containers can’t send to the new bus.

Setup Path

Follow these in order. Each recipe assumes the previous one is done.

  1. Author a Reverb Send Bus — once per acoustic archetype (small room, large hall, outdoors).
  2. Tag a Zone to Use This Bus — for each physical room in your scene.
  3. Send an SFX Container Into the Reverb — flip the per-sound Allow Reverb Send flag.
  4. (Optional) Override Routing for Music or Narration — for sounds with authored, non-zone-driven character.
  5. (Optional) Tune a Bus’s Character While Editing — iteration workflow.

Recipe: Author a Reverb Send Bus

📋 What: Create a single reverb bus and wire it up so voices physically in a tagged zone send to it.

🎯 Use Case: First step for any per-zone reverb in the project. Authoring is one-time per acoustic space.

Asset Setup

1. Create the SendBus asset:

  • Project ▸ Create ▸ Audio System ▸ Reverb Send Bus
  • Name it after the room: Reverb_Bathroom (the asset name becomes the bus id and the basis for exposed parameter names)

2. Configure the SendBus:

  • Reverb Mixer: drag in your voice mixer asset (the same one assigned to AudioManager ▸ Voice Mixer)
  • Leave Reverb Bus blank — it auto-fills on Generate
  • Leave Output Destination blank for single-mixer setups (the wet tail flows up the group hierarchy naturally)
  • (Optional) Parent Group: assign a ReverbsWet return-bus group if you use the DAW-style convention — Generate will nest this SendBus under it
  • Parametric reverb — Basic:
    • Dry Level: -10000 (the default; SendBus groups are wet-only by design)
    • Room: 0 (overall wet gain; lower to attenuate)
    • Decay Time: tune for the space — bathroom ≈ 0.8 s, cathedral ≈ 5 s, cave ≈ 4 s
    • Reverb Level: 200 (Unity’s SFX Reverb default)

3. Generate:

  • Select the SendBus asset
  • In the inspector, click Generate Mixer Group
  • Console should log success: “Generated ‘Bathroom’: groups +1, effects +1, exposed params +6, values applied 14/14, output set: no”
  • The mixer now has a Bathroom mixer group with an SFX Reverb effect; Reverb_Bathroom_Wet, _Decay, _Room, _RoomHF, _DecayHFRatio, _Reflections are exposed for the runtime driver

4. Register the bus in the project registry:

  • Open Window ▸ Audio System ▸ Reverb Send Buses
  • If no registry exists yet, create one: Project ▸ Create ▸ Audio System ▸ Reverb Send Bus Registry
  • Drop the registry into AudioManager ▸ Reverb Send Bus Registry
  • Click Refresh in the window — your new SendBus appears in the list

5. Sanity-check:

  • Click Validate Wiring on the SendBus asset. It should say “Wiring OK.”

✅ Result: The reverb bus exists on the mixer, exposes the right runtime parameters, and is registered. Voices won’t send to it yet — that requires tagging an AudioZone (next recipe).


Recipe: Tag a Zone to Use This Bus

📋 What: Tell an AudioZone “voices in here send to this reverb bus.”

🎯 Use Case: After authoring a SendBus, every zone that should produce that bus’s reverb needs to be tagged.

Asset Setup

1. Select the AudioZone GameObject in your scene.

2. In the AudioZone component:

  • Reverb Bus: drag in the Reverb_Bathroom SendBus’s ReverbBus field (open the SendBus inspector and drag from there — it’s the mixer group reference). This is the only reverb setting on the zone.

The zone has no reverb character of its own. How the room sounds (Room, Room HF, Decay Time, Decay HF Ratio, Reflections, Reverb Level) is set on the Reverb_Bathroom SendBus asset from the previous recipe. To make two rooms sound different, give them separate SendBus assets.

What Happens at Runtime

  • Source-side: voices in this zone whose container has Allow Reverb Send = ✓ send a copy of their signal to Reverb_Bathroom at their authored level. The send level scales by the listener’s audibility to the zone (1.0 same-zone, <1 through portals).
  • Listener-side: the bus’s six runtime-driven parameters are written from the SendBus asset every reverb-sends tick. They don’t change with where the listener stands; only the send level does.

✅ Result: The bathroom zone is now acoustically alive. Voices in the bathroom contribute to the bathroom bus, which sounds the way its SendBus asset is authored.


Recipe: Send an SFX Container Into the Reverb

📋 What: Flip an existing SFX container into the per-zone reverb path.

🎯 Use Case: Take a gunshot / footstep / impact container and have its voices contribute to the reverb of the room they’re fired in.

Asset Setup

On the AudioContainer:

  • Allow Reverb Send: ✓
  • Reverb Send Level Db: per-sound tuning
    • 0 dB — full wet contribution. Right for big impacts (gunshots, explosions) that should ring out the room.
    • -6 dB — half-loud wet contribution. Good baseline for most SFX.
    • -12 dB — quiet wet contribution. Right for small detail sounds (footstep grain, weapon foley) that should colour the mix but not dominate the reverb.
    • -80 dB — effectively silent. Use Allow Reverb Send = off instead if you want zero contribution.
  • Static Emitter: ✓ if the voice doesn’t move during its lifetime (impacts, stingers, fixed-prop ambiences). Off for vehicle sounds, footsteps parented to a character, etc.

What Happens at Runtime

  1. The container’s Use Occlusion and Allow Reverb Send flags both feed the same slot decision: the voice acquires an OcclusionSlot on play (see chapter 14 §14.4).
  2. WriteReverbSendsImmediate runs synchronously when the voice is configured, so its very first audio frame already has the correct send level.
  3. The reverb-sends driver re-evaluates every ~50 ms while the voice is playing — sends respond to listener motion (audibility changes) even on static emitters.

✅ Result: This sound, fired anywhere in the world, contributes to whichever zone’s reverb bus its source position is in — without any code changes.


Recipe: Override Routing for Music or Narration

📋 What: Make a specific container always send to a fixed reverb bus, regardless of where the listener stands or what zone the source is in.

🎯 Use Case: Music that should always carry a “cathedral choir” reverb. Narrator VO that should always have a tight studio reverb. UI tails that should bypass per-zone routing. Anything whose acoustic character should be authored, not derived.

Asset Setup

On the AudioContainer:

  • Allow Reverb Send: ✓
  • Explicit Reverb Bus: drag in the target ReverbSendBus asset
  • Reverb Send Level Db: as desired

What Happens at Runtime

Per-tick, the reverb-sends driver sees the explicit bus reference and takes the explicit-bus short-circuit:

  • The named bus gets the container’s ReverbSendLevelDb at all times (no audibility or membership scaling).
  • Every other registered bus is silenced for this voice.
  • Source zone resolution is bypassed entirely.

The voice’s character is now authored, not zone-derived. Listener motion changes nothing about the routing.

✅ Result: A music container that always plays with cathedral reverb, regardless of whether the player is inside a cathedral or outdoors.


Recipe: Tune a Bus’s Character While Editing

📋 What: Iterate on a reverb’s sound by tweaking values on the SendBus asset and pushing them to the mixer without re-running the full Generate.

🎯 Use Case: Dialing in a room’s character during gameplay-tuning sessions.

Workflow

Option A — Edit the SO, push to mixer:

  1. Select the ReverbSendBus asset
  2. Tweak Decay Time, Room HF, Reflections Level, etc. on the SO
  3. Click Apply Params → Mixer
  4. Enter play mode and listen

Use when the SO is your source of truth. Apply Params skips the group/effect/expose work and only writes the parametric values — fast iteration.

Option B — Edit the mixer window, pull back to SO:

  1. Open the Audio Mixer window, select the SendBus’s group
  2. Edit the SFX Reverb effect’s parameters directly (snapshot must be the target snapshot, which is the default for fresh mixers)
  3. Back on the SendBus asset inspector, click Pull Params ← Mixer
  4. The SO now reflects your mixer-window tweaks

Use when the mixer window’s UI is more convenient (it has the per-parameter sliders right there). Pull ensures the SO catches up so re-running Generate later doesn’t undo your work.

⚠️ Caveat: Generate always overwrites the mixer effect’s parameter values from the SO. If you’ve been tuning in the mixer window without pulling, Generate will wipe your tweaks. The safe workflow is Edit-mixer → Pull → Generate, or just stay on Option A.

✅ Result: Live iteration on reverb character without breaking the schema or losing changes.


Troubleshooting

“My voice has Allow Reverb Send = ✓ but I hear no wet tail.”

  • Confirm AudioManager.ReverbSendBusRegistry is assigned and contains at least one bus.
  • Confirm the source’s zone has its ReverbBus field set to a bus that’s in the registry.
  • Confirm the bus’s ReverbSendBus asset isn’t silent: a parametric bus with Room at -10000 mB produces no tail — raise it toward 0 (the default). A convolution bus with no Impulse Response assigned is likewise silent.
  • Confirm the listener can reach the source’s zone (unreachable zones produce audibility = 0).
  • Confirm the container’s Mixer Group is a bus that appears in the Occlusion Layout’s bus list — without a slot, there are no Send level params to write to.

“Several zones share one bus and they all sound identical.”

  • This is by design as of the source-of-truth unification: a bus has one acoustic identity, defined by its ReverbSendBus asset, regardless of which zone routed the voice to it. Per-zone variation on a shared bus is no longer supported.
  • If you need Cathedral and Cathedral_Crypt to sound different, give them separate ReverbSendBus assets and point each zone’s ReverbBus at its own.

“I added a new ReverbSendBus but it doesn’t appear in the dropdowns.”

  • Open Window ▸ Audio System ▸ Reverb Send Buses and click Refresh. The registry only updates when refreshed.
  • After refreshing, re-run the Occlusion Layout Builder so existing occlusion slots get the new bus’s Send param authored.

“Voices on this bus sound dry on the first frame, then reverb kicks in.”

  • This was a previous bug — voices used to play dry for up to one driver tick (50 ms) before sends were written. The fix is WriteReverbSendsImmediate, which is called synchronously by AudioContainer.ConfigureAudioSource. If you’re seeing this on a custom playback path that bypasses ConfigureAudioSource, call WriteReverbSendsImmediate(voice, container) yourself right after setting voice.OcclusionSlot.

“My mixer-window tweaks vanish whenever I re-Generate.”

  • Generate is non-destructive only if the SO already matches the mixer. Click Pull Params ← Mixer first to sync the SO to your live tweaks, then Generate becomes a no-op on those values. Or stay in the SO-first workflow and use Apply Params → Mixer for iteration.

From the Pepper.SFX 3.1 guides (USER_GUIDE.md). Something wrong or unclear? Tell me.