Pepper.SFX
All Guidance pages

Guidance / API reference

AudioVoice & AudioVoiceEnhanced

AudioVoice (Base)

Namespace: AudioSystem Description: Base voice representation.

Properties

public AudioSource source { get; }
public bool isPlaying { get; }
public float volumeMultiplier { get; set; }

Methods

public void SetVolume(float volume)
public void UpdateMasterVolume(float masterVolume)
public void Stop(float fadeTime = 0f)
public void StopImmediate()

AudioVoiceEnhanced

Namespace: AudioSystem Inheritance: AudioVoice Description: Enhanced voice with gain stack, virtualization, and scheduling. Not typically accessed directly.

Properties

public GainStack GainStack { get; }
public AudioEvent SourceEvent { get; }
public AudioContainer Container { get; }        // the innermost container that configured this voice (its
                                                // occlusion/reverb/propagation flags drive it)
public AudioContainer RootContainer { get; }    // the container that was played (e.g. the Blend around a layer)
public AudioBus Bus { get; }
public int Priority { get; }
public bool IsVirtual { get; }
public float VirtualTime { get; }               // where a virtual voice is in its clip now, in seconds
public double VirtualSamples { get; }           // the same in the clip's samples; written back on MakeReal
public double ScheduledStartTime { get; }
public double ScheduledEndTime { get; }
public OcclusionSlot OcclusionSlot { get; }     // mixer slot held while playing (null when not occluding)

Methods

public GainStack GainStack { get; }
public PitchStack PitchStack { get; }
public void UpdateFinalVolume()
public void UpdateFinalPitch()    // writes PitchStack.GetFinal(container's Pitch Limit) to source.pitch
public void MakeVirtual()         // from your code: held virtual until MakeReal (the budget won't undo it);
                                  // an audible voice fades out over ~25 ms, then its source pauses
public void MakeReal()            // seeks to VirtualSamples while paused, resumes, fades in over ~25 ms;
                                  // over Max Real Voices, the least important other sounds go virtual
public void UpdateVirtualTime(float deltaTime)   // advance by deltaTime at the voice's pitch; only for a
                                                 // voice no AudioManager steps. No-op while paused; wraps
public float GetImportance()      // distance × GainStack.GetGainWithoutRealize() × priority

Virtual position. While a voice is virtual, the AudioManager’s per-frame step moves VirtualSamples on by the audio clock’s advance (AudioSettings.dspTime) × the voice’s pitch (source.pitch, which the pitch stack writes), and wraps it for a loop. A pitch change counts from the next step, when Unity first plays it. Paused voices and starts still scheduled ahead don’t advance. A virtual one-shot ends once its position passes the end of its clip. AudioHandle.SeekTo on a virtual voice moves the position it comes back at. Unity’s own Doppler isn’t seen; see AudioContainer.DopplerLevel.

The fade. MakeVirtual on a voice that can be heard (playing, started, not muted, above −80 dB) fades GainStack.RealizeGain to 0 over about 25 ms, in at least three steps of at most one per mixed DSP buffer (two volume changes in one buffer can leave Unity’s own short ramp unfinished), then pauses the source; any other voice pauses at once. MakeReal fades it back to 1 the same way. A pause during the fade out finishes it at once. A Stop(fadeTime) during it lets it finish and then ends the voice. A voice with no AudioManager has no fade.


GainStack (Nested Class)

public class GainStack
{
    public float BaseGain { get; set; }       // Container/Event volume
    public float BusGain { get; set; }        // Bus hierarchy
    public float OcclusionGain { get; set; }  // Occlusion attenuation
    public float RtpcGain { get; set; }       // Blend curves. RESERVED: sole writer is the Blend's
                                              // per-frame step (product of every enclosing Blend's curve).
                                              // No second writer — see the reservation note in GainStack.cs.
    public float SchedulerGain { get; set; }  // Crossfade/transition
    public float FadeGain { get; set; }       // Stop(fadeTime) ramp, 1 → 0. RESERVED: sole writer is
                                              // AudioVoice's fade-out. Reset to 1 at the pool boundary.
    public float MultiplierGain { get; set; } // Per-voice multiplicative — volume randomization,
                                              // SwitchContainer/BlendContainer outer Volume,
                                              // and AudioExtensions.PlayWithVolume write here.
    public float UserGain { get; set; }       // AudioHandle.SetVolumeScale / SetVolumeOffset — idempotent runtime scale,
                                              // given to every voice of the handle's plays, later ones too.
    public float EmitterGain { get; set; }    // the Audio Emitter's Volume Offset; sole writer: the manager.
    public float DuckingGain { get; set; }    // (Deprecated) ducking is applied at the bus, not the voice.
                                              // Settable for back-compat but NOT included in GetFinalGain.

    public float CurveGain { get; set; }      // volume curves (ParameterCurve), summed in dB; sole writer: the play tree
    public float RealizeGain { get; set; }    // the fade around virtualization, 0 while parked; sole writer:
                                              // AudioVoice's virtualization. Reset to 1 at the pool boundary.
    public float SwitchGain { get; set; }     // a playing Switch's crossfade (equal power); sole writer: the play
                                              // tree. Left out of the silent-layer check. Reset to 1 at the pool boundary.
    public float SpatialGain { get; set; }    // Spatial Mode = Pepper: the level from the listening points (largest
                                              // weight × attenuation, less what Spread takes); 1 in Unity mode. Sole
                                              // writer: Pepper's spatial step (3.1.0-dev.8). Reset to 1 at the pool boundary.
    public float GetGainWithoutRealize()      // BaseGain * BusGain * OcclusionGain * RtpcGain * CurveGain * SchedulerGain * FadeGain * MultiplierGain * UserGain * SwitchGain * EmitterGain * SpatialGain
    public float GetFinalGain()               // GetGainWithoutRealize() * RealizeGain
    public void ApplyToSource(AudioSource source)
    public void Reset()
}

PitchStack (Nested Class)

The pitch counterpart of GainStack: every contributor to a voice’s playback rate owns one slot, and only AudioVoice.UpdateFinalPitch() writes AudioSource.pitch. Every slot is a ratio (1 = unchanged).

public class PitchStack
{
    public const float MaxRatio = 3f;           // Unity's AudioSource.pitch ceiling
    public const float MinRatio = 0.001f;       // floor: a voice is never stopped by its pitch

    public float Randomization { get; set; }    // container pitch randomization
    public float Decorrelation { get; set; }    // Decorrelated multi-position nudge
    public float Follow { get; set; }           // a Blend's pitch follow (value ÷ root), set by the play tree
    public float Curve { get; set; }            // pitch curves (ParameterCurve, cents), set by the play tree
    public float Doppler { get; set; }          // Pepper's Doppler (a container with Doppler = Pepper), set by the play tree;
                                                // applied after the limit
    public float TimeScale { get; set; }        // reserved: slow motion (planned)
    public float User { get; set; }             // AudioHandle.SetPitchOffset (every voice of its plays, later ones too)
    public float Emitter { get; set; }          // the Audio Emitter's Pitch Offset

    public bool HasAbsolute { get; }            // SetPitchAbsolute / the obsolete SetPitch
    public float Absolute { get; }
    public void SetAbsolute(float ratio);       // play at exactly this ratio, ignoring every slot
    public void ClearAbsolute();

    public float GetFinal(float limitSemitones = 0f);   // product of the slots (or the absolute ratio), clamped;
                                                        // the limit leaves Doppler out (it comes after)
    public void Reset();
    public static float SemitonesToRatio(float semitones);
}

DopplerMath

public enum DopplerMode { Unity, Pepper }

public static class DopplerMath
{
    public const float SpeedOfSound = 343f;    // m/s
    public static float Cents(float closingSpeed, float exaggeration, float maxCents);   // 1200·log2(c ÷ (c − v)) × exaggeration, within ±maxCents
    public static float Ratio(float closingSpeed, float exaggeration, float maxCents);   // the same as a playback-rate ratio
}

Description: Pepper’s Doppler shift (3.1.0-dev.7), as a container set to DopplerMode.Pepper applies it. closingSpeed is positive when the sound and the listener close in; a speed at or past 90% of the speed of sound reads as 90%. 50 m/s is about +272.7 cents, −50 m/s about −235.7.

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