Pepper.SFX
All Guidance pages

Guidance / API reference

Editor Tools

Note: These tools are Unity Editor extensions and not available at runtime.

AudioAuditionWindow and AudioAudition

Access: Window > Audio System > Audition (USER_GUIDE §10.5)

Plays a container tree, or an event’s Play actions, outside Play mode with a slider for every parameter it reads (Bypass Slew While parameters included), its switch values, any number of sweeps, a recording’s replay and a live table of its layers; it follows the selected container or event, keeps playing while it is edited, and reads the tree again when it changes in the Inspector. The window runs an AudioAudition (namespace AudioSystem, in the Runtime assembly but used only outside Play mode):

public enum SweepMode { Once, Repeat, BackAndForth }

public sealed class AudioAudition : System.IDisposable
{
    public static AudioAudition Current { get; }
    public static AudioAudition Begin(out string whyNot);   // the running one; null in Play mode or with another Audio Manager
    public AudioContainer Container { get; }                // what plays: a container...
    public AudioEvent Event { get; }                        // ...or an event
    public int SkippedActions { get; }                      // the event's actions not auditioned
    public bool IsPlaying { get; }                          // also while an event's delayed Play is to come
    public float Distance { get; set; }                     // m from the listening point at the origin
    public float Angle { get; set; }                        // °, 0 ahead, + right
    public void Play(AudioContainer container);
    public void Play(AudioEvent audioEvent);
    public void Stop();                                     // immediate
    public void Tick(float dt);                             // call every editor update

    public void SetParameter(AudioParameter p, float v);  public void SetParameter(string name, float v);   // takes it off its sweep or the replay
    public void SnapParameter(AudioParameter p);
    public float GetParameter(AudioParameter p);           public float GetParameter(string name);          // heard
    public float GetWrittenParameter(AudioParameter p);    public float GetWrittenParameter(string name);   // written: what a slider shows

    public void Sweep(AudioParameter p, float from, float to, float seconds, SweepMode mode);
    public void Sweep(string name, float from, float to, float seconds, SweepMode mode);
    public void Sweep(AudioParameter p, float from, float to, float seconds, bool backAndForth = false);   // as before
    public void Sweep(string name, float from, float to, float seconds, bool backAndForth = false);
    public void StopSweep();                                // every sweep
    public void StopSweep(AudioParameter p);              public void StopSweep(string name);
    public bool IsSweeping { get; }                         // any
    public bool IsSweepingParameter(AudioParameter p);    public bool IsSweepingParameter(string name);

    public void Replay(AudioParameterRecording recording);  // from its start, looping; null stops it
    public AudioParameterRecording Recording { get; }
    public bool IsReplaying { get; }
    public bool ReplayLooping { get; set; }                 // default true; false stops at the end
    public float ReplayTime { get; set; }                   // set = scrub (snapped)
    public void SetReplayLoop(float start, float end);      // end <= start = all of it
    public float ReplayLoopStart { get; }  public float ReplayLoopEnd { get; }
    public void StopReplay();
    public bool IsReplayed(AudioParameter p);              public bool IsReplayed(string name);

    public void SetSwitch(AudioSwitchGroup g, string v);  public void SetSwitch(string group, string v);
    public string GetSwitch(AudioSwitchGroup g);          public string GetSwitch(string group);
    public void GetLayers(List<AuditionLayer> into);       // Container, Clip, LevelDb, PitchSemitones, LowPassHz, Virtual, Bus
    public static void FindInputs(AudioContainer root, AuditionInputs into);   // Parameters, ParameterNames, SwitchGroups, SwitchGroupNames, SwitchValues
    public static void FindInputs(AudioEvent audioEvent, AuditionInputs into); // every Play action's tree
    public void Dispose();
}

How it runs. Begin creates a hidden (HideAndDontSave) Audio Manager in Manual update mode and starts it without Awake (edit mode doesn’t call it): the voice pool only, no coroutines, no PlayerLoop step, no event, bus or occlusion loading. It registers a listening point at the origin facing +z and a hidden source object that Distance and Angle move. Values are set on that manager’s global scope: assets through their smoothing, names through the string API. Tick runs the event’s delayed actions, the replay, the manager’s step, the sweeps and, every 0.1 s, the voice pass. A play is placed in 3D but heard 2D (spatial blend 0). A Next Play Only Switch in the tree plays again when a switch value is set by hand (not by a replay). Built-in parameters and driven Switch Groups follow the place and their parameter, not SetParameter/SetSwitch. Outside Play mode a Sequence plays its first clip only and a stop is immediate. Dispose stops everything and destroys the hidden objects and the listening point; the window calls it before Play mode, before a script reload and when it closes.

Sweeps run one per parameter, any number at once: a new sweep of a parameter replaces its earlier one, and setting a parameter by hand stops only its own. Once ends at to (the written value stays there); Repeat starts again from from; BackAndForth turns round.

An event (Play(AudioEvent)) runs its Play actions as a post would: through each action’s Target Bus (volume, mute), with the event’s priority and Persistent flag, after the action’s Delay; its Set RTPC and Set Switch actions set the audition’s values; the rest are counted in SkippedActions. Max Instances and cooldowns don’t apply, and the event’s own state is never touched.

A replay writes every recorded value at once, as the game wrote it, through the parameter’s smoothing, holding each key until the next; the recorded switch values are set as the game set them. Going round the loop and setting ReplayTime snap the values (heard at once). A parameter set by hand or swept is taken off the replay; Replay again restores it.

AudioLiveViewWindow, AudioEmitterRecorder and AudioParameterRecording

Access: Window > Audio System > Live View (USER_GUIDE §10.6), in Play mode

Every Audio Emitter with its values (written and heard) and switches, and each play on it (AudioManager.GetPlaysDebug): event, container, bus, Persistent, real or virtual, its own values (AudioHandle.ParameterCount and the listing beside it) and each voice’s level, pitch, region and reason for being virtual. Record and Stop and Save record the chosen emitter:

public sealed class AudioEmitterRecorder
{
    public static AudioEmitterRecorder Begin(AudioEmitter emitter, out string whyNot);   // Play mode only
    public AudioParameterRecording End();     // in memory; save it with AssetDatabase.CreateAsset
    public AudioEmitter Emitter { get; }
    public AudioParameterRecording Recording { get; }
    public float Seconds { get; }             // unscaled
    public bool IsRecording { get; }          // false after End, or once the emitter is destroyed
}

public sealed class AudioParameterRecording : ScriptableObject
{
    public string EmitterName { get; }
    public float Length { get; }              // seconds
    public IReadOnlyList<ParameterTrack> Parameters { get; }   // parameter (asset or null), parameterName, times, values; ValueAt(t): NaN = not set
    public IReadOnlyList<SwitchTrack> Switches { get; }        // group, times, values; ValueAt(t): "" = not set
    public ParameterTrack Find(AudioParameter p);  public ParameterTrack Find(string name);
}

A recorder samples its emitter at the start of each of Pepper’s steps, after the frame’s game code: every value set on it as written (a ramp’s position while it runs), Bypass While ones included, and its switch values, keeping a key only when one changes; a value the game clears is a NaN key. Values set on a play’s handle and global values aren’t recorded. While nothing records, the step does nothing for it.

LoopAnalysisWindow

Access: Window > Audio System > Loop Analysis (USER_GUIDE §10.7)

Per clip (Decompress On Load): its fundamental by the YIN method and the Root Value it gives, RPM = fundamental × 120 ÷ cylinders (a four-stroke engine), with ×2 and ÷2 for an octave slip; a seam check at the loop point (the first sample against the line through the last two, over the clip’s own RMS second difference: over 4× clicks) and the level of the first against the last 50 ms; a preview of the seam; RMS and peak in dBFS and integrated loudness in LUFS (ITU-R BS.1770-4, a mono clip as one channel). A Regions Blend’s Inspector has Detect Root Values, which sets each layer’s Root Value from its clip (with Undo) for the cylinder count set beside it. Cylinders is a scale, one setting shared by the three tools. A reading more than half an octave from the RPM in its clip’s name is flagged; when most readings sit 2 semitones or more from them, the tools name the cylinder count that puts them within a semitone (Use N in the windows; a Console warning from Detect Root Values, which still writes the raw reading).

EngineBuilderWindow

Access: Window > Audio System > Engine Builder (USER_GUIDE §10.8)

From selected loops (each one’s set, OnLoad or OffLoad, and RPM guessed from its name, typed, or detected with its own Cylinders slider, shared with Loop Analysis; a detected RPM far from its name’s is flagged): one looping single-clip container per loop (Uses Parent Positioning and Output, Avoid Repeat Last 0); an on-load and an off-load Regions Blend on RPM (Root Values, Auto Layout, Equal Power, Pitch Follow, Silent Layers Virtualize, Force Loop); a Regions Blend on load crossfading them at constant power from 0.3 to 0.7 (3D, Doppler Level 0); one Persistent event on the chosen Target Bus. Empty RPM and Load fields make EngineRpm (0–9000 RPM) and EngineLoad01 (0–1). The clips are set to mono and Decompress On Load after a confirmation listing them; no asset is ever overwritten. With one set only, the RPM Blend is the root and there is no load Blend; the window and its dialog say so.

EngineGrainsWindow

Access: Window > Audio System > Engine Grains (Unity 6000.3 and later)

Cuts an engine sweep (Decompress On Load) into a GrainTable. The sweep’s RPM is Known, typed from one RPM to another over the whole clip along a Curve (Straight Line or Even Pitch: a synthesised sweep), or measured From Pitch with the Cylinders scale shared with Loop Analysis, looked for between the two RPMs typed. Each cut is one engine cycle long at that RPM, then moved, by less than half a period of the fundamental and at most 6% of a cycle, to where the waveform best matches the start of the grain before it, stretched to the new pitch. With a typed RPM, the periods of the fundamental per cycle are measured against it, and the sweep’s own curve is measured from a strong harmonic followed through it: when it disagrees with the one typed (the other curve, or the RPM changing by more than 3% more or less over the clip), the window says so and offers the curve that fits, with the two ranges that keep one typed end, each cut on trial and the one whose cuts match better first. The report gives the range covered and warns of gaps (no grain over 250 RPM), a fast sweep (under 10 grains per 1000 RPM), a typed curve the grains don’t follow (over 3% off on average) and cuts that found nothing like the cycle before within reach (over 20% of them below a 0.5 match); it notes held stretches (under 50 RPM of change for 0.3 s or more). One Grain At loops the grain nearest an RPM, unchanged, to hear whether its cuts are clean. Saving makes <sweep>_Grains.asset beside the clip, or updates the table it was given (with Undo).

AudioContainerValidator (Container Validator)

Namespace: AudioSystem.Editor Access: Window > Audio System > Container Validator (USER_GUIDE §10.9)

public static void Validate(AudioContainer container, List<ValidationIssue> issues);
public static void ValidateEvent(AudioEvent audioEvent, List<ValidationIssue> issues);
public static void ApplyFix(ValidationIssue issue);   // under Undo
public class ValidationIssue { AudioContainer container; Object target; string issue; MessageType severity; Action fix; }

Every container and event in the project: empty or null entries and zero weights; a Routing container with no clip; Regions gaps, dips and 0–0 regions; a layer following pitch with no Root Value; pitch past a Blend’s Tuning Warning (Pitch Follow over the follow parameter’s own range, plus pitch curves); a 3D loop with Doppler in a Virtualize Blend; stereo clips on 3D layers and streaming clips on layers that go virtual; 3D distances, or the Attenuation asset’s curve at its Max Distance; a Play action with no Target Bus (a warning without a Mixer Group, else Info); a looping event that isn’t Persistent (Info). target is the event for an event’s issue (container is null then).

Audio Import Settings and folder rules

Namespace: AudioSystemEditor.Import

The project’s AudioImportSettings asset (Create ▸ Audio System ▸ Import Settings, under Assets; the first by path when there are several, never one inside a package) holds the category presets and Folder Rules:

public class FolderImportRule { string name; string folder; bool includeSubfolders; bool enabled; CategoryPreset settings; }
public List<FolderImportRule> FolderRules { get; }
public FolderImportRule RuleFor(string assetPath);   // the most specific enabled folder; null when none

AudioImportRulesPostprocessor applies a clip’s rule when the clip is first imported (a new file); later reimports keep the clip’s settings. The inspector’s Apply to Existing Clips re-applies a rule to the clips already in its folder.

SoundBuilderSimpleWindow

Namespace: AudioSystemEditor Type: EditorWindow Access: Window > Audio System > Sound Builder (Simple)

Description

One-click sound setup wizard that creates Bus + Container + Event with all references pre-filled.

Features:

  • 5 creation modes: Complete Setup, Container Only, Event Only, Bus Only, Batch Import
  • All 5 container types supported
  • Auto-create folder structure
  • Validate Resources placement

Usage

  1. Window > Audio System > Sound Builder (Simple)
  2. Drop AudioClip(s) in field
  3. Choose a creation mode and container type
  4. Click “Create Complete Sound Setup”
  5. Done!

AudioEventEditor

Namespace: AudioSystemEditor Type: Custom Inspector (Editor Only) Applies To: AudioEvent assets

Description

Custom Inspector for AudioEvent: whether the event can be found by name or id, and the stable id.

Features:

  • Says whether the event is in the AudioEventRegistry (or, with no registry, in Resources/Audio/Events), with Add to Registry or Move to Resources buttons. Only posting by name or id (AudioManager.PostEvent, networked posts) needs that: an event held in a field (myEvent.Post()) plays wherever it is. Earlier versions said such an event “will NOT load at runtime” and warned in the Console on import; both were wrong and are gone.
  • Bakes the asset’s GUID into the event on import (the stable network id).

AudioEventRegistryEditor

Namespace: AudioSystemEditor Type: Custom Inspector (Editor Only) Applies To: AudioEventRegistry assets

Description

Custom Inspector for AudioEventRegistry with utility buttons and migration guide.

Buttons:

  • Populate from Resources Folders - Fast for existing Resources-based projects
  • Populate from Entire Project - Searches entire project
  • Validate Registry (Remove Nulls) - Cleans up missing references
  • Clear All - Removes all registered assets (with confirmation)

Occlusion Layout Builder Window

Namespace: AudioSystemEditor.Occlusion Type: EditorWindow Access: Window > Audio System > Occlusion Layout

Authors the per-bus occlusion slot hierarchy on the project’s voice mixer and serializes it to an OcclusionLayout asset. See Manual §14.3.

Top-bar fields:

  • Voice Mixer — the mixer to author into
  • Occlusion Layout — the asset to populate (or click “Create New”)
  • Reverb Send Bus Registry (optional) — when assigned, each generated slot also receives one Send effect per registered reverb bus
  • Slots Per Bus — concurrent occluded voices per bus (default 6)

Actions:

  • Scan, Auto-Create, Refresh — walks the project for containers with useOcclusion, allowReverbSend or usePropagation (each takes a slot at play time) and ambient sources with useOcclusion, collects the unique mixer groups they play through (a layer with usesParentOutput counts its parent’s), authors <Bus>_OcclusionLayer + slot groups under each, exposes their cutoff parameters and (optional) Send level parameters, writes the result to the OcclusionLayout asset.
  • Scan only (no mixer changes) — read-only sanity check.
  • Diagnose Reflection — dumps a reflection report to the Console for the audio internals (debug aid when the auto-creator misbehaves on a new Unity version).

A foldout at the bottom shows the manual schema for designers who prefer to hand-author the slot hierarchy.


Reverb Send Buses Window

Namespace: AudioSystemEditor.Reverb Type: EditorWindow Access: Window > Audio System > Reverb Send Buses

Project-wide overview of ReverbSendBus assets. See Manual §15.6.

Top-bar actions:

  • Create New Bus — Save File panel for authoring a fresh ReverbSendBus asset
  • Refresh — re-scans the project for t:ReverbSendBus and re-runs Validate per asset
  • Validate All — same as Refresh but with a summary HelpBox
  • Generate All Missing — runs ReverbAutoCreator.EnsureSendBus on every bus whose ReverbBus is null and whose ReverbMixer is assigned

Per-row UI: bus name (link-label, pings the asset), assigned mixer, assigned bus group, and a foldable issue list from ReverbAutoCreator.Validate. Auto-refreshes on window focus.


ReverbSendBusInspector

Namespace: AudioSystemEditor.Reverb Type: Custom Inspector (Editor Only) Applies To: ReverbSendBus assets

Adds four top-of-inspector action buttons that drive ReverbAutoCreator:

Button What it does
Generate Mixer Group Authors / refreshes the mixer group + SFX Reverb effect + exposed parameters. Disabled until Reverb Mixer is assigned.
Validate Wiring Read-only check; reports “Wiring OK” or a bullet list of issues. Always enabled.
Apply Params → Mixer Pushes the SO’s parametric values into the mixer effect without re-running the group/expose work. Enabled once Reverb Bus is generated.
Pull Params ← Mixer Copies the mixer effect’s current values back onto the SO.

The ten Advanced parametric reverb fields live behind an EditorPrefs-backed foldout (closed by default); the four Basic fields stay visible. EditorPrefs key is project-wide so the toggle survives selection changes.


AudioPortalEditor / AudioZoneEditor / PropagationManagerEditor

Namespace: AudioSystemEditor.Propagation Type: Custom Inspectors (Editor Only)

Diagnostic inspectors for the propagation subsystem’s runtime components.

  • AudioPortalEditor — adds a Portal Diagnostics panel showing door source status, current transmission / cutoff (live in play mode), and the auto-detected blend-axis side mapping. Includes a “Re-detect zone sides” button.
  • AudioZoneEditor — adds a Zone Diagnostics panel showing live reverb profile values, volume collider counts, and the list of AudioPortals in loaded scenes referencing this zone.
  • PropagationManagerEditor — adds a Runtime Debug panel (play mode only) showing registered zone/portal/source counts, active zone/portal counts after culling, the listener’s zone stack, blend-portal membership, pending hysteresis events, and emitter pool counters.

All three refresh every repaint while in play mode (via RequiresConstantRepaint).

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