Scripting guide
This page is the public runtime API a game engineer uses to drive Audity from
C#. Everything lives in the DarkEffekt.Audity namespace. The exact contract of
each member (parameters, ranges, remarks) is in the generated Scripting API
reference; this page narrates the workflow and shows the signatures you reach
for most.
The Audity Source component
Section titled “The Audity Source component”AuditySource is the primary API. It plays an AudityGraph on an AudioSource
with per-instance control. Add it via Add Component > Audio > Audity Source;
it requires an AudioSource.
public AudityPlayable graph; // the Sound Graph to play (AudityGraph is an AudityPlayable)public bool playOnEnable; // play automatically on enablepublic AudityBatchGroup batchGroup;public List<AuditySourceOverride> overrides;
public event System.Action Finished; // raised on the main thread when playback endspublic bool IsPlaying { get; }Interface overrides (the inspector form)
Section titled “Interface overrides (the inspector form)”overrides is the per-component form over the graph’s interface: a list of
AuditySourceOverride entries, each a member name plus a value (a number for
Float/Bool/Int/Enum/Time members, a vector for Vector 2/3/4 members, or an
object for a Sample Set member). You edit
it in the Audity Source inspector, not usually in code - it is how one
placement of a graph tweaks another’s exposed values without a script. An entry
exists only for a field you actually changed; everything else tracks the graph’s
own defaults live. Overrides apply on every Play(), before any values you set
from code, so a scripted SetFloat still wins over an inspector override.
Instance lifetime
Section titled “Instance lifetime”A playing graph ends in one of two ways:
- It finishes on its own. If the graph is finite - it has no indefinitely
sustaining source (no looping Wave Player, no held ADSR sustain) - the instance
ends the moment its last voice completes and nothing is pending.
Finishedfires on the main thread andIsPlayinggoes false. A one-shot footstep does this. - You stop it. A graph with a looping voice or a held envelope is infinite:
it renders until you call
Stop()(or fire the Output node’s Stop trigger). It will not end by itself - a looping voice never completes.Stopruns the Output’s release fade, then raisesFinished.
So a looping ambience keeps rendering until stopped; it does not fall silent and retire on its own.
Play, stop, trigger
Section titled “Play, stop, trigger”public void Play(float fadeInSeconds = 0f);public void PlayQuantized(AudityQuantize startQuantize, float fadeInSeconds = 0f);public void Stop(float fadeOutSeconds = 0f);
public void Trigger(AudityQuantize quantize = AudityQuantize.Immediate);public void Trigger(AudityParameterId id, AudityQuantize quantize = AudityQuantize.Immediate);public void Trigger(string name, AudityQuantize quantize = AudityQuantize.Immediate);
public void SetTempo(double bpm, int beatsPerBar = 4);Play assigns the graph and starts it. PlayQuantized holds the onset until the
next musical boundary (see Musical timing). Trigger
with no id fires every Trigger In; with an id or name it fires just that named
one.
Parameters
Section titled “Parameters”Parameter setters on AuditySource are sticky: the value applies to the live
instance immediately (gliding over the member’s Smooth time) and is re-applied to
every future Play(). Setting a parameter before Play is therefore fine.
public void SetFloat(AudityParameterId id, float value, float smoothSeconds = -1f, int elementIndex = 0);public void SetFloat(string name, float value, float smoothSeconds = -1f, int elementIndex = 0);public void SetBool(AudityParameterId id, bool value);public void SetInt(AudityParameterId id, int value);public void SetVector(AudityParameterId id, Vector3 value, float smoothSeconds = -1f);// SetParameter(...) is the general form; Set* are typed conveniences.Each has a string overload alongside the AudityParameterId overload. A
negative smoothSeconds uses the member’s authored glide.
Reading values back
Section titled “Reading values back”The members the GRAPH writes - Direction Out - go the other way. Getters are per live instance and are not sticky: a stopped source reads as nothing at all, never as the last value it had.
public bool TryGetFloat(AudityParameterId id, out float value, int element = 0);public bool TryGetFloat(string name, out float value, int element = 0);public float GetFloat(AudityParameterId id, float fallback = 0f, int element = 0);public bool TryGetVector(AudityParameterId id, out Vector4 value, int componentCount = 4);
public event System.Action<AudityParameterId> TriggerFired;TryGetFloat returns false when the source is not playing, the member is not
marked Out, or the engine has not reported it yet (the first frame). GetFloat
collapses all three into a fallback.
TriggerFired is raised on the main thread for an Out Trigger member, once
per fire, and carries the member id. Subscribe in OnEnable and unsubscribe in
OnDisable; handlers may safely stop or restart the source.
A read value is a snapshot as of the engine’s last report - roughly a frame old, because it crosses the audio thread. Every trigger fire is delivered, but its timing is approximate for the same reason. Drive gameplay, animation and UI from these; keep anything that must be sample-accurate inside the graph. See Reading a graph from code.
Caching parameter ids
Section titled “Caching parameter ids”The string overloads hash the name on every call. On a hot path (a value you set
every frame), cache an AudityParameterId once and reuse it:
static readonly AudityParameterId Cutoff = AudityParameterId.FromName("Cutoff");// ...source.SetFloat(Cutoff, value); // no per-call hashingRuntime source binding
Section titled “Runtime source binding”To swap the content behind a Sample Set member at runtime, bind a bank to its key. See Samples and sample sets for the concepts.
public void BindSource(string key, AudityBankHandle bank); // hot path: repoint + refcountpublic void BindSource(string key, AuditySampleSet set); // convenience: loads if coldpublic void ClearSource(string key); // back to the baked default
// per-call source argument (dialogue semantics): this Play uses this bankpublic void Play(string sourceKey, AudityBankHandle bank, AudityQuantize quantize = AudityQuantize.Immediate);A bind is a persistent per-source slot: it survives across Play() calls and
applies to future triggers. Voices already playing ride their old bank to
completion, so retrigger a looping voice to hear a rebind.
Parameter ids
Section titled “Parameter ids”public readonly struct AudityParameterId{ public readonly uint value; public AudityParameterId(uint value); public static AudityParameterId FromName(string name); public static uint Hash(string name); // FNV-1a over the name}AudityBank is the residency registry for prepared Sample Sets. Warm banks up
front (level load, weapon equip) so binding is free later.
public static AudityBankHandle Load(AuditySampleSet set);public static AudityBankHandle Load(UnityEngine.Object source); // clip/sample/generator promotedpublic static bool IsReady(AudityBankHandle handle);public static void Release(AudityBankHandle handle);public static AudityColdBindPolicy ColdBindPolicy { get; set; }
public readonly struct AudityBankHandle{ public bool IsValid { get; } public bool IsReady { get; } // true once every entry's PCM is resident}Two references keep a bank alive: the registry (one per outstanding Load
handle) and playing instances. Identity is a content hash, so two identical sets
share one resident bank. Release drops your handle; the bank frees only when
nothing else holds it.
var bank = AudityBank.Load(weaponSet);// ...wait until bank.IsReady, then:source.BindSource("Weapon", bank);Global control
Section titled “Global control”AudityGlobal reaches every playing instance and owns tempo and transports. Main
thread only.
public static void SetParameter(AudityParameterId id, float value);public static void SetParameter(string name, float value); // hashes each callpublic static bool TryGetParameter(AudityParameterId id, out float value);
public static void SetTransport(string name, double bpm, int beatsPerBar = 4, int phraseBars = 4, ulong? anchorDspSample = null);public static bool TryGetTransport(string name, out AudityTransportDesc transport);public static void ClearTransport(string name);public static void PublishDrive(AudityTransportSettings settings, AudityQuantize startQuantize = AudityQuantize.Immediate);
public static ulong NowDspSample();public static ulong NextBoundary(in AudityTransportDesc transport, ulong dspSample, AudityQuantize quantize);Use named transports for anything musical across instances; see Musical timing.
Low-level messaging
Section titled “Low-level messaging”AudityMessaging sends control messages straight to the instance on an
AudioSource. It is the same path AuditySource uses internally, exposed for
cases where you hold an AudioSource rather than an AuditySource, or want
strictly live-instance messaging with no stickiness. Every method returns true
if a live Audity instance handled it.
public static bool SetParameter(AudioSource source, AudityParameterId id, float value, float smoothSeconds = -1f, int elementIndex = 0);public static bool Trigger(AudioSource source, AudityParameterId id, AudityQuantize quantize = AudityQuantize.Immediate);public static bool SetTempo(AudioSource source, double bpm, int beatsPerBar = 4);public static bool Stop(AudioSource source, float fadeSeconds);public static bool SetSpatial(AudioSource source, Vector3 listenerPosition, Vector3 emitterPosition);public static bool SetSpatial(AudioSource source, Vector3 listenerPosition, Vector3 emitterPosition, Vector3 listenerForward, Vector3 listenerUp, Vector3 listenerVelocity, Vector3 emitterVelocity);SetSpatial is what an AuditySource calls every frame to feed
Listener Info; call it yourself only if you drive a graph
without an Audity Source.
Playing without the component
Section titled “Playing without the component”Fire-and-forget one-shots
Section titled “Fire-and-forget one-shots”AudityPlayback.Play plays a graph at a point in the world with no GameObject
or component of your own, and nothing to clean up afterwards. It leases a hidden
AudioSource from a pool, plays, and returns the mount to the pool when the graph
finishes:
// A 3D one-shot at the impact point: full volume within 3 m, gone by 70 m.AudityPlayback.Play( impactGraph, hit.point, mixerGroup: sfxGroup, mountSpec: AudityMountSpec.Spatial(minDistance: 3f, maxDistance: 70f));Pooled mounts are hidden, so everything a scene AudioSource would carry in its
inspector is passed at the call instead. mixerGroup is the routing;
AudityMountSpec is the physical state: volume, spatial blend, rolloff shape
and range, Doppler, and speaker spread. Omitting the spec plays 2D at full
volume. Every play applies its spec in full, so a lease never inherits the
previous sound’s settings. Build one spec per kind of sound and reuse it.
A graph that spatializes itself (Listener Info and Pan) should stay 2D; host 3D on top of in-graph spatial pans and attenuates twice, the same double-spatialization rule as on the component.
Play returns an AudityInstance handle. Drop it for true fire-and-forget,
or keep it to drive the live instance:
var handle = AudityPlayback.Play(impactGraph, hit.point, mountSpec: AudityMountSpec.Spatial(3f, 70f));handle.SetFloat("Force", strength); // live value, not stickyhandle.Trigger("Ping");handle.Stop(fadeOutSeconds: 0.2f);The handle is generation-counted: once the instance ends, every method harmlessly no-ops and returns false. Handles do not remember values across plays; stickiness is the component’s job.
The pool holds AudityPlayback.MountCapacity mounts (default 8, shared with
batch composites). A play beyond capacity stops an earlier sound and logs a
warning; raise the capacity at startup if your density is intended. Two things
stay with AuditySource on a GameObject by design: moving emitters, which
need a transform to ride, and edit-mode audition, because AudityPlayback is
play-mode only.
The bare generator
Section titled “The bare generator”You do not need any Audity API at all. Assigning a graph to
AudioSource.generator and calling AudioSource.Play() works, with global
parameters only:
audioSource.generator = myGraph;audioSource.Play();AudityGlobal.SetParameter("Cutoff", 8000f);The component exists for per-instance control (sticky parameters, binding, overrides, batching); the bare-generator path is the minimal one.
Batch groups
Section titled “Batch groups”Assign the same AudityBatchGroup asset to several sources to cap how many play
at once (dense bursts collapse into a composite). It is authored data, configured
in the inspector, not called at runtime; see
Performance and limits.
Telemetry
Section titled “Telemetry”AudityTelemetry is an editor and tooling hook (it feeds the audition panel’s
live badges). In a player its Sink is null unless something installs one (the
diagnostics AudityPerfHud does), and with no sink instances send nothing. Game
code leaves it alone.
Driving Audity without code
Section titled “Driving Audity without code”The same surface this page describes is reachable from Unity’s animation systems: Timeline tracks and markers call Play/Stop/Trigger, and AnimationClips drive parameters through the Audity Animation Bridge component. See Timeline and animation.