Pepper.SFX

Features

Ambient propagation

Rooms, doorways and doors for ambient beds: hear rain through the window, and the next room's machinery through a door as it opens.

Rain outside a house shouldn’t sound the same in the hallway as on the porch. Indoors you hear it through the open window, quieter, duller and from the window’s direction; shut the door to that room and it fades further. Pepper.SFX models this with zones and portals, and routes long-running ambient loops through them.

How it works

  • An Audio Zone is a room: a GameObject with one or more trigger BoxColliders. An L-shaped room is one zone with two boxes.
  • An Audio Portal is an opening between two zones: a doorway, a window, a vent. It sets how much gets through open (Base Transmission, Open Low Pass Hz) and closed (Closed Transmission, Closed Low Pass Hz).
  • A portal can follow a door. Any MonoBehaviour that implements IPortalDoorSource (an OpenProgress from 0 to 1 and an OnChanged event) drives it, so Pepper doesn’t need to know how your doors work. Half open gives values halfway between.
  • An Ambient Source declares a looping clip in a zone. The Propagation Manager finds the best path from that zone to the listener’s, adding up the loss at each portal and keeping the lowest cutoff, and plays the loop from a pooled emitter at the portal you hear it through. Walk along the wall and the rain slides along the window.
  • In a doorway you hear a blend of both sides, so there’s no snap at the threshold.
  • The manager creates itself in Play mode, solves 15 times a second (Solve Rate Hz) and smooths volume, cutoff and position every frame.
  • One-shot sounds can use the same rooms: tick Use Propagation on a container and a knock behind a closed door is muffled through the portals. This needs the occlusion slots.

Example

A door that swings open and shut and tells its portal as it moves.

using System;
using UnityEngine;
using AudioSystem.Propagation;

public class AudioDoor : MonoBehaviour, IPortalDoorSource
{
    [SerializeField] private float swingSeconds = 0.8f;
    [SerializeField] private float openAngle = 90f;

    private float progress;   // 0 = closed, 1 = open
    private bool wantOpen;

    public float OpenProgress => progress;
    public event Action OnChanged;

    public void Open()  => wantOpen = true;
    public void Close() => wantOpen = false;

    void Update()
    {
        float target = wantOpen ? 1f : 0f;
        if (Mathf.Approximately(progress, target)) return;

        progress = Mathf.MoveTowards(progress, target, Time.deltaTime / swingSeconds);
        transform.localRotation = Quaternion.Euler(0f, progress * openAngle, 0f);
        OnChanged?.Invoke();   // the portal re-solves now, not on the next tick
    }
}

Without OnChanged, the portal still picks up the change on the next solve, up to about 67 ms later.

Setting it up

  1. For each room, make a GameObject and add Audio > Propagation > Audio Zone. It adds a trigger BoxCollider; size it to the room. For the outdoors, set Activation Radius to Infinity so it’s never culled.
  2. At each opening, add Audio > Propagation > Audio Portal to a GameObject. Size its box to span the opening and overlap both rooms’ boxes by at least 5 cm. Set Zone A and Zone B (or tick Auto Detect Zones), and point the object’s +Z through the opening.
  3. For a door, drag a component that implements IPortalDoorSource into the field under the portal’s Door Source heading. Leave it empty for openings that are always open.
  4. Add Audio > Propagation > Ambient Source to an object in the zone the sound comes from. Set Source Zone, Looping Clip and Ambience Mixer Group.
  5. Add Audio > Propagation > Audio Listener Zone Tracker to the player object that has the Collider, not to the camera with the AudioListener.
  6. Press Play and walk through. Select the Propagation Manager in the Hierarchy to see the listener’s zone and the active emitters.

Good to know

  • Web builds: beds still route through zones, portals and doors, but aren’t muffled and get no reverb: the emitters use Unity’s Low Pass and Reverb filter components, which Web audio doesn’t support.
  • Ambient emitters sit outside Pepper’s voice pool, capped by Max Ambient Emitters (16); past the cap, the farthest goes silent.
  • A source is heard through its single best path unless you raise Max Paths Per Source (up to 6), at one emitter per path.
  • Clutter inside a room doesn’t block ambient beds unless you tick Enable Obstruction on the Propagation Manager.
  • Beds take on the reverb of the room you’re in, from that zone’s Reverb Send Bus.
  • A bad loop point in the clip clicks every time round. Sound doesn’t bend round corners, so split large open spaces into more zones.

Learn more