Pepper.SFX

Features

Events and containers

Author sounds as assets and play them with one call: events decide what happens, containers decide which clips play and how.

Without middleware, every sound in a Unity game is an AudioSource and a clip wired up in code, and picking variations, stopping spam, fading and routing are all yours to write. Pepper.SFX moves that work into assets. You build an Audio Event and the containers under it, and your code plays it with one call that returns a handle.

How it works

  • Audio Event is what your code posts. It holds a list of actions that run in order, each with an optional Delay: Play, Stop, Pause, Resume, SetSwitch, SetRTPC, SetState, TriggerDucking and CrossFade. One post can start a sound, change a state and duck the music.
  • Voice Settings keep an event in check: Priority, Max Instances with a Steal Behavior (Oldest, Quietest, Furthest, Lowest Priority), Cooldown, and the same limits per Audio Emitter. Tick Persistent for sounds that must never be stolen, such as an engine. Time picks game or real time, so pause-menu sounds work at time scale 0.
  • Post returns an AudioHandle. Stop it with a fade, pause it, change its volume or pitch, or wait for OnFinished.
  • Containers decide which clips play, and they nest inside each other:
    • Random Container: one clip per post, with weights and Avoid Repeat Last, remembered per Audio Emitter. Footsteps, gunshots, clicks.
    • Sequence Container: clips in order (Forward, Reverse, Ping Pong or Random), with Auto Advance, Loop Sequence and a Delay After per entry.
    • Switch Container: plays the child that matches a switch value, such as the surface under a foot.
    • Blend Container: layers that crossfade along a parameter, such as engine RPM or combat intensity.
    • Routing Container: plays all its clips at once, for layered sounds like an explosion’s blast and debris.
  • Every container also has volume and pitch randomisation, 3D settings, a Mixer Group and Parameter Curves.

Example

using UnityEngine;
using AudioSystem;

public class Generator : MonoBehaviour
{
    [SerializeField] private AudioEvent switchOn;   // Random Container: three clunks
    [SerializeField] private AudioEvent hum;        // Routing Container with Loop ticked

    private AudioHandle humHandle;

    public void TurnOn()
    {
        switchOn.Post(gameObject, transform.position);              // fire and forget
        if (humHandle == null)
            humHandle = hum.Post(gameObject, transform.position);   // keep the loop's handle
    }

    public void SetLoad(float load01)
    {
        humHandle?.SetPitchOffset(load01 * 2f);   // up to two semitones higher under load
    }

    public void TurnOff()
    {
        humHandle?.Stop(0.5f);                    // fade out over half a second
        humHandle = null;
    }
}

The clunk is posted and forgotten. The hum loops, so the script keeps its handle to bend its pitch and fade it out. Posting by name (AudioManager.Instance.PostEvent("Generator_Hum")) needs the event in an Audio Event Registry or Resources/Audio/Events.

Setting it up

  1. Add the AudioManager component to a GameObject in your first scene.
  2. Create a container with Assets > Create > Audio System > Random Container (or Sequence, Switch, Blend or Routing Container) and add your clips.
  3. Create the event with Assets > Create > Audio System > Audio Event. Add a Play action and set its Container and Target Bus.
  4. Set Priority, Max Instances and Cooldown under Voice Settings.
  5. Drag the event into an AudioEvent field on your script and call Post.

Window > Audio System > Sound Builder (Simple) makes a bus, container and event in one step, and Window > Audio System > Audition plays a container outside Play mode.

Good to know

  • A Stop action only stops sounds that its own event started. To stop music started by another event, keep the handle from Post and call Stop on it.
  • Calling Stop() on a container stops every sound playing from that container asset. To stop one of them, stop its handle.
  • Each Sequence Container asset keeps a single position, so two objects playing the same one share it. Duplicate the asset if you need two independent sequences.
  • Posting a Blend Container event again plays a second copy alongside the first. Set the event’s Max Instances to 1 if you want it to restart instead.
  • A post blocked by Cooldown returns a handle that has already finished, so OnFinished still fires.

Learn more