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.