Documentation index for AI agents (llms.txt) A Markdown version of every page is available: request the page's source under /docs/, follow the "alternate" link in this page's head, or start from /llms.txt.
Visual Script logo Scripting API

Audio#

AudioManager plays and stops sounds, while VolumeManager stores and saves the six volume settings. Both managers are singletons that initialize on first access.

Playing#

AudioManager.Play takes an AudioResource and AudioConfig, then returns the sound's runtime Guid:

AudioConfig config = new AudioConfig(
    timeScale: TimeScale.GameTime,
    transition: 0f,
    channel: AudioChannel.SoundEffect,
    loop: false,
    priority: 128,
    volume: 1f,
    pitch: 1f,
    stereoPan: 0f,
    spatialBlend: 1f,
    reverbZoneMix: 1f,
    volumeRolloff: AudioRolloffMode.Logarithmic,
    minDistance: 1f,
    maxDistance: 500f,
    dopplerLevel: 0f,
    spread: 0f,
    hasTarget: true,
    target: this.gameObject,
    locationTransform: this.transform
);

Guid audioId = AudioManager.Play(this.m_Resource, config);

AudioConfig is a read-only struct configured through its constructor. Use named arguments to keep each value associated with its setting. Only the last three arguments are optional: target, locationTransform, and locationPosition.

These arguments control timing, channel assignment, and the sound's relationship to a game object:

Argument Is
timeScale An ITimeScale. TimeScale.GameTime and TimeScale.RealTime are ready-made; a component implementing ITimeScale gives the sound a local clock.
transition Fade-in seconds. 0 starts at full volume.
channel Which channel the sound belongs to, and therefore which volume and mixer group apply.
hasTarget / target Marks the sound as belonging to a game object, so Stop(GameObject, float) and IsPlaying(GameObject) can find it.
locationTransform Followed every frame. Takes precedence over locationPosition.
locationPosition A fixed world point, used when locationTransform is null.

The rest map one-to-one onto AudioSource and are described in Playing a sound.

Destroying the target doesn't stop its sound

target and locationTransform hold references without parenting the sound to the object. When you destroy the object, the sound keeps playing. A destroyed locationTransform falls back to locationPosition, which for a targeted sound is Vector3.zero.

Stop the sound before you destroy its target.

Stopping#

Choose a stop method based on whether you need one sound, every instance of a resource, or a group of sounds:

Method Stops Returns
Stop(Guid) One sound, immediately. void
Stop(Guid, float) One sound, fading over the given seconds. Awaitable
Stop(AudioResource, float) Every sound playing that resource. Awaitable
Stop(GameObject, float) Every sound targeting that object. Awaitable
StopChannel(AudioChannel, float) Every sound on that channel. Awaitable

Await a channel fade before starting the next operation when the sequence depends on silence:

await AudioManager.StopChannel(AudioChannel.Music, 2f);
await SceneManager.LoadSceneAsync(nextScene);

StopChannel finishes the music fade before LoadSceneAsync starts. If you don't need to wait for the fade, you can call the method without awaiting its result.

Queries#

Use IsPlaying to check a specific instance, resource, or target:

Method Returns
IsPlaying(Guid) Whether that specific sound is still active.
IsPlaying(AudioResource) Whether any sound is playing that resource.
IsPlaying(GameObject) Whether any sound targets that object.

Changing a sound while it plays#

GetActive returns the live IAudio for an ID, or null after the sound ends:

IAudio audio = AudioManager.GetActive(audioId);
if (audio != null) audio.Volume = 0.4f;

Setting Volume changes that active instance without affecting other sounds that use the same resource. Other members expose its configuration and writable playback settings:

Member Access
Resource, Channel, HasTarget, Target Read-only — fixed when the sound started.
Volume, Pitch Read/write. Re-applied every frame against the channel volume and time scale.
Priority, StereoPan, SpatialBlend, ReverbZoneMix Read/write. Applied directly to the AudioSource.
VolumeRolloff, MinDistance, MaxDistance, DopplerLevel, Spread Read/write. Applied directly to the AudioSource.

The ID distinguishes one sound from other instances playing the same resource. Play Instructions discard the returned Guid, so editor-authored Events cannot later address that individual instance.

Hold the ID only as long as the sound

An ID whose sound has finished is not reused, but it no longer resolves. Treat a null from GetActive as it ended, not as an error, and don't keep IDs in long-lived state expecting them to stay valid.

Volumes#

VolumeManager exposes the six volumes as Volume objects and provides channel-based accessors:

VolumeManager.Music.Value = 0.5f;
VolumeManager.Set(AudioChannel.Ambient, 0.2f);

float music = VolumeManager.Music.Value;
float ambient = VolumeManager.Get(AudioChannel.Ambient);

Every value is clamped to 0–1 on assignment. Assigning the current value doesn't fire an event or notify subscribers.

Final sound volume equals its own volume multiplied by its channel volume and Master.

AudioVolume includes Master#

Choose the enum based on whether the field needs to include the master volume:

Enum Values Used by
AudioChannel The five channels. Everything that plays, stops or queries a sound, and every VolumeManager method.
AudioVolume The five channels plus Master. Serialized fields that pick a volume to change.

AudioVolume uses the same values as AudioChannel for channel members. Handle Master separately before casting:

float value = this.m_Volume == AudioVolume.Master
    ? VolumeManager.Master.Value
    : VolumeManager.Get((AudioChannel) this.m_Volume);

The guard handles the only extra AudioVolume member. Master is a property rather than a channel, so channel-based Get, Set, Subscribe, and Unsubscribe reject it.

Use VolumeManager.Master directly, including VolumeManager.Master.Subscribe(…) for change notifications.

Use AudioVolume for a serialized field a designer picks a volume from, and AudioChannel everywhere else. Casting a Master into an AudioChannel and handing it to VolumeManager throws ArgumentOutOfRangeException.

Reacting to changes#

Use Subscribe when your callback needs a channel's Args context, and keep its returned ID for cleanup:

Guid subscriptionId = VolumeManager.Subscribe(AudioChannel.Music, this.OnMusicChanged, args);
VolumeManager.Unsubscribe(AudioChannel.Music, subscriptionId);

The subscription owns its context and disposes it during Unsubscribe. For a callback that recomputes all volume state, use the notification without arguments:

VolumeManager.EventChange += this.RefreshVolume;

EventChange fires when any channel or Master changes.

Each Volume also has its own EventChange taking the new value, if you'd rather watch one directly.

Unsubscribe in OnDisable

Both notification mechanisms are static and outlive your components. A subscription that isn't released keeps its callback alive after the object is gone. A channel subscription also retains its Args.

Volumes save themselves#

VolumeManager implements ISaveLoad as shared and persistent data under unity-audio-volume-info. The manager registers itself and follows this lifecycle:

  • SaveLoadManager.SaveShared() writes the six values.
  • Loading restores the same values across every profile.
  • Unload preserves them when starting a new game.

The manager subscribes when it initializes. Subscribing applies the values already held by the snapshot, so the stored volumes are available on first audio access.

Apply volume to hand-placed Audio Sources#

The managers govern only sources created by AudioManager. A hand-placed AudioSource ignores channel volume because Visual Script applies that volume on managed sources rather than mixer groups.

In a component with m_AudioSource and m_Channel fields, these methods apply channel and Master volume whenever either changes:

private void OnEnable()
{
    VolumeManager.EventChange += this.RefreshVolume;
    this.RefreshVolume();
}

private void OnDisable()
{
    VolumeManager.EventChange -= this.RefreshVolume;
}

private void RefreshVolume()
{
    this.m_AudioSource.volume = VolumeManager.Get(this.m_Channel) * VolumeManager.Master.Value;
}

The free Audio Source Volume package provides this behavior with a channel dropdown. Its component assigns volume directly, so write a custom version when another system must also contribute to that field.

Upgrading from the Audio Unity package#

Audio previously lived in a separate package under VisualScript.Runtime.AudioUnity. It now uses the VisualScript.Runtime namespace and VisualScript.Runtime.Core assembly.

Replace using VisualScript.Runtime.AudioUnity; with using VisualScript.Runtime;. Remove the old audio reference from assembly definitions because VisualScript.Runtime.Core now contains these types.

The AudioSourceVolume component remains in the extension package with its original namespace.

Where to go next#

  • Audio — inspect the designer-facing playback model.
  • Channels — choose channel roles and mixer groups.
  • ISaveLoad — follow the interface implemented by VolumeManager.
Visual Script logoVisual Script © Catsoft Works 2026. All rights reserved.