Skip to main content

Audio

StoryFlow supports audio playback tied to dialogue nodes, standalone audio triggers, and audio variables. This guide covers how audio assets are handled, configured, and played back in the Unity plugin.

How Audio Works

Dialogue nodes in the StoryFlow Editor can have audio attached. When the runtime reaches a dialogue node with audio assigned, the StoryFlowComponent automatically plays the AudioClip through an AudioSource component that is created on demand on the same GameObject.

The dialogue state exposes audio as StoryFlowDialogueState.Audio (AudioClip). This value is null when no audio is assigned to the dialogue node.

C#
// Access audio from the current dialogue state
void OnDialogueUpdated(StoryFlowDialogueState state)
{
    // state.Audio is an AudioClip - may be null if no audio is assigned
    if (state.Audio != null)
    {
        // Audio is available for this dialogue node.
        // The plugin handles playback automatically via AudioSource,
        // but you can also access the clip directly for custom handling.
    }
}

Fresh Entry vs Return

Audio only plays on a fresh entry to a dialogue node - that is, when the runtime arrives at the node by following an edge from another node. When a Set* node (such as setBool, setInt, etc.) has no outgoing edge and returns to the dialogue for re-rendering, audio does not re-trigger. This prevents audio from restarting every time a variable changes during an active dialogue.

Audio Settings

The StoryFlowComponent exposes several audio-related properties in the Inspector under the Audio header. These settings apply globally to all dialogue audio played by the component.

Setting Type Default Description
StopAudioOnDialogueEnd bool true When enabled, stops all playing dialogue audio when the dialogue session ends (End node reached or StopDialogue() called).
DialogueAudioMixerGroup AudioMixerGroup null Assigns all dialogue audio to a specific mixer group. Use this to create a dedicated "Dialogue" volume slider separate from music, SFX, and other audio categories.
DialogueVolumeMultiplier float 1.0 Volume scaling multiplier (range 0-2) applied to all dialogue audio. Stacks with the mixer group volume.
C#
// Configure audio settings in C#
StoryFlowComponent sf = GetComponent<StoryFlowComponent>();

// Stop audio when dialogue ends (default behavior)
sf.StopAudioOnDialogueEnd = true;

// Assign a mixer group for volume control
sf.DialogueAudioMixerGroup = dialogueMixerGroup;

// Set volume to 80%
sf.DialogueVolumeMultiplier = 0.8f;

Audio Format

Unity imports audio files natively as AudioClip assets. The plugin resolves audio asset keys to AudioClip references during import, so they are ready for playback at runtime.

Recommended Format: WAV

WAV is the recommended format for dialogue audio. Unity supports WAV, MP3, OGG, and other common formats natively. WAV files provide the best compatibility and avoid any codec-related issues. Unity handles audio compression internally based on your import settings, so you get optimal file sizes regardless of the source format.

Looping and Reset

Each dialogue node in the StoryFlow Editor has two audio-related settings that control playback behavior:

  • AudioLoop (bool) - When enabled, the dialogue's audio loops continuously for as long as the dialogue is active. The plugin sets the AudioSource.loop property to achieve this.
  • AudioReset (bool) - When enabled and the dialogue has no audio assigned, any previously playing dialogue audio is stopped. This gives you explicit control over when audio should be cut - for example, a narrative dialogue node that should play in silence after a voiced line.

These properties are available on the StoryFlowDialogueState as AudioLoop and AudioReset if you need to inspect them from your UI code.

Two additional audio properties on the dialogue state control auto-advance behavior:

  • AudioAdvanceOnEnd (bool) - When enabled, the dialogue automatically advances when the audio clip finishes playing. The component polls the AudioSource each frame and calls AdvanceDialogue() when playback ends. Note: this is automatically disabled when AudioLoop is true, since looping audio never finishes.
  • AudioAllowSkip (bool) - When enabled alongside AudioAdvanceOnEnd, the player can manually advance past the audio-gated wait. When disabled, the dialogue remains locked until the audio finishes. This is automatically false when AudioAdvanceOnEnd is false. Use SetAudioAdvanceState(bool waiting, bool allowSkip) to control this programmatically.
C#
// Simplified internal logic for dialogue audio playback
void ProcessDialogueAudio(StoryFlowDialogueState state, bool isFreshEntry)
{
    if (isFreshEntry && state.Audio != null)
    {
        // Fresh entry with audio - play it
        PlayDialogueAudio(state.Audio, state.AudioLoop);

        // If AudioAdvanceOnEnd is set, the dialogue will auto-advance
        // when the audio clip finishes playing
        if (state.AudioAdvanceOnEnd)
            SetAudioAdvanceState(true, state.AudioAllowSkip);
    }
    else if (isFreshEntry && state.Audio == null && state.AudioReset)
    {
        // Fresh entry, no audio, reset enabled - stop any playing audio
        StopDialogueAudio();
    }
    // Returning from a Set* node: do nothing with audio
}

Custom Audio Handling

For standalone audio triggers (via the playAudio node in the graph), the plugin broadcasts the OnAudioPlayRequested event rather than playing audio automatically. Subscribe to this event to handle playback yourself:

C#
void Start()
{
    var sf = GetComponent<StoryFlowComponent>();
    sf.OnAudioPlayRequested += HandleAudioPlayRequested;
}

void OnDestroy()
{
    var sf = GetComponent<StoryFlowComponent>();
    if (sf != null)
        sf.OnAudioPlayRequested -= HandleAudioPlayRequested;
}

void HandleAudioPlayRequested(AudioClip clip, bool loop)
{
    // Handle audio playback yourself
    // Useful for ambient sounds, music, stingers, etc.
    // Route through your own audio manager if needed
    myAudioSource.clip = clip;
    myAudioSource.loop = loop;
    myAudioSource.Play();
}

PlayAudio is a broadcast, not automatic playback

Unlike dialogue-attached audio which the plugin plays automatically, the playAudio node only broadcasts an event. Your game code is responsible for handling playback. This gives you full control - for example, routing music through a separate audio manager or layering ambient sounds.

Programmatic Control

The StoryFlowComponent provides public methods for direct audio control:

Method Parameters Description
PlayDialogueAudio AudioClip clip, bool loop Plays the given clip through the component's AudioSource. Stops any currently playing dialogue audio first. Creates the AudioSource on demand if needed.
StopDialogueAudio none Stops the dialogue AudioSource if it is currently playing and clears the clip reference.
IsDialogueAudioPlaying none Returns true if the dialogue AudioSource is currently playing.
SetAudioAdvanceState bool waiting, bool allowSkip Controls the audio-advance gate. When waiting is true, the component polls for audio completion and auto-advances when done. allowSkip determines whether the player can advance manually before audio finishes.
C#
StoryFlowComponent sf = GetComponent<StoryFlowComponent>();

// Play a clip manually
sf.PlayDialogueAudio(myClip, loop: false);

// Check if audio is playing
if (sf.IsDialogueAudioPlaying())
{
    Debug.Log("Dialogue audio is active.");
}

// Stop dialogue audio
sf.StopDialogueAudio();

The AudioSource is created lazily on the component's GameObject the first time audio is played. It is configured as 2D audio (spatialBlend = 0) with playOnAwake disabled. The mixer group and volume multiplier from the component settings are applied automatically each time PlayDialogueAudio is called.

Need Help?

Join our Discord community to ask questions, share your projects, report bugs, and get support from the team and other users.

Join Discord