Error using Localised Audio Tables for Dialogue

Hi there.

I’m getting the following error message when trying to play an event with a programmer event containing a localised audio table.

[FMOD] SoundSourceInstrumentInstance::startChannelIfReady : Waveform instance in error state 18
UnityEngine.Debug:LogWarning (object)
FMODUnity.RuntimeUtils:DebugLogWarning (string) (at Assets/Plugins/FMOD/src/RuntimeUtils.cs:558)
FMODUnity.RuntimeManager:DEBUG_CALLBACK (FMOD.DEBUG_FLAGS,intptr,int,intptr,intptr) (at Assets/Plugins/FMOD/src/RuntimeManager.cs:81)

I’ve tried setting the script up according to this link:
https://www.fmod.com/docs/2.02/unity/examples-programmer-sounds.html

There must be a step I’ve missed. Thanks!

FMOD Version: 2.02.07
Unity Version: 2021.2.7f1

Hi,

Did you copy the whole example script or have you used it as a template? If so, could I see your script?

Could you also try changing soundMode from:

FMOD.MODE soundMode = FMOD.MODE.LOOP_NORMAL | FMOD.MODE.CREATECOMPRESSEDSAMPLE | FMOD.MODE.NONBLOCKING;

to

FMOD.MODE soundMode = FMOD.MODE.CREATESTREAM;

Sure. Here it is:

//--------------------------------------------------------------------
//
// This is a Unity behaviour script that demonstrates how to use
// Programmer Sounds and the Audio Table in your game code. 
//
// Programmer sounds allows the game code to receive a callback at a
// sound-designer specified time and return a sound object to the be
// played within the event.
//
// The audio table is a group of audio files compressed in a Bank that
// are not associated with any event and can be accessed by a string key.
//
// Together these two features allow for an efficient implementation of
// dialogue systems where the sound designer can build a single template 
// event and different dialogue sounds can be played through it at runtime.
//
// This script will play one of three pieces of dialog through an event
// on a key press from the player.
//
// This document assumes familiarity with Unity scripting. See
// https://unity3d.com/learn/tutorials/topics/scripting for resources
// on learning Unity scripting. 
//
// For information on using FMOD example code in your own programs, visit
// https://www.fmod.com/legal
//
//--------------------------------------------------------------------

using System;
using System.Collections.Generic;
using UnityEngine;
using System.Runtime.InteropServices;

class ScriptUsageProgrammerSounds : MonoBehaviour
{
    FMOD.Studio.EVENT_CALLBACK dialogueCallback;

    [SerializeField] private FMODUnity.EventReference DialogueEvent;
    [SerializeField] private string dialogueKey;

    private FMOD.Studio.EventInstance dialogueInstance;

#if UNITY_EDITOR
    void Reset()
    {
        //EventName = FMODUnity.EventReference.Find("event:/Character/Radio/Command");
    }
#endif

    void Start()
    {
        // Explicitly create the delegate object and assign it to a member so it doesn't get freed
        // by the garbage collected while it's being used
        dialogueCallback = new FMOD.Studio.EVENT_CALLBACK(DialogueEventCallback);
    }

    void PlayDialogue(string key)
    {
        dialogueInstance = FMODUnity.RuntimeManager.CreateInstance(DialogueEvent);

        // Pin the key string in memory and pass a pointer through the user data
        GCHandle stringHandle = GCHandle.Alloc(key);
        dialogueInstance.setUserData(GCHandle.ToIntPtr(stringHandle));

        dialogueInstance.setCallback(dialogueCallback);
        dialogueInstance.start();
        dialogueInstance.release();
    }

    [AOT.MonoPInvokeCallback(typeof(FMOD.Studio.EVENT_CALLBACK))]
    static FMOD.RESULT DialogueEventCallback(FMOD.Studio.EVENT_CALLBACK_TYPE type, IntPtr instancePtr, IntPtr parameterPtr)
    {
        FMOD.Studio.EventInstance instance = new FMOD.Studio.EventInstance(instancePtr);

        // Retrieve the user data
        IntPtr stringPtr;
        instance.getUserData(out stringPtr);

        // Get the string object
        GCHandle stringHandle = GCHandle.FromIntPtr(stringPtr);
        String key = stringHandle.Target as String;

        switch (type)
        {
            case FMOD.Studio.EVENT_CALLBACK_TYPE.CREATE_PROGRAMMER_SOUND:
                {
                    FMOD.MODE soundMode = FMOD.MODE.LOOP_NORMAL | FMOD.MODE.CREATECOMPRESSEDSAMPLE | FMOD.MODE.NONBLOCKING;
                    var parameter = (FMOD.Studio.PROGRAMMER_SOUND_PROPERTIES)Marshal.PtrToStructure(parameterPtr, typeof(FMOD.Studio.PROGRAMMER_SOUND_PROPERTIES));

                    if (key.Contains("."))
                    {
                        FMOD.Sound dialogueSound;
                        var soundResult = FMODUnity.RuntimeManager.CoreSystem.createSound(Application.streamingAssetsPath + "/" + key, soundMode, out dialogueSound);
                        if (soundResult == FMOD.RESULT.OK)
                        {
                            parameter.sound = dialogueSound.handle;
                            parameter.subsoundIndex = -1;
                            Marshal.StructureToPtr(parameter, parameterPtr, false);
                        }
                    }
                    else
                    {
                        FMOD.Studio.SOUND_INFO dialogueSoundInfo;
                        var keyResult = FMODUnity.RuntimeManager.StudioSystem.getSoundInfo(key, out dialogueSoundInfo);
                        if (keyResult != FMOD.RESULT.OK)
                        {
                            break;
                        }
                        FMOD.Sound dialogueSound;
                        var soundResult = FMODUnity.RuntimeManager.CoreSystem.createSound(dialogueSoundInfo.name_or_data, soundMode | dialogueSoundInfo.mode, ref dialogueSoundInfo.exinfo, out dialogueSound);
                        if (soundResult == FMOD.RESULT.OK)
                        {
                            parameter.sound = dialogueSound.handle;
                            parameter.subsoundIndex = dialogueSoundInfo.subsoundindex;
                            Marshal.StructureToPtr(parameter, parameterPtr, false);
                        }
                    }
                    break;
                }
            case FMOD.Studio.EVENT_CALLBACK_TYPE.DESTROY_PROGRAMMER_SOUND:
                {
                    var parameter = (FMOD.Studio.PROGRAMMER_SOUND_PROPERTIES)Marshal.PtrToStructure(parameterPtr, typeof(FMOD.Studio.PROGRAMMER_SOUND_PROPERTIES));
                    var sound = new FMOD.Sound(parameter.sound);
                    sound.release();

                    break;
                }
            case FMOD.Studio.EVENT_CALLBACK_TYPE.DESTROYED:
                {
                    // Now the event has been destroyed, unpin the string memory so it can be garbage collected
                    stringHandle.Free();

                    break;
                }
        }
        return FMOD.RESULT.OK;
    }

    void Update()
    {
        //dialogueInstance.getTimelinePosition(out int position);
        //Debug.Log(position);
        if (Input.GetKeyDown(KeyCode.Space))
        {
            PlayDialogue(dialogueKey);
        }
        if (Input.GetKeyDown(KeyCode.Alpha2))
        {
            PlayDialogue("640165main_Lookin At It");
        }
        if (Input.GetKeyDown(KeyCode.Alpha3))
        {
            PlayDialogue("640169main_Press to ATO");
        }
    }
}

I’ll try changing the sound mode and see if that helps. Thanks!

Update I’ve made the changes the soundMode variable you recommended and I got this warning instead:

[FMOD] EventInstance::createProgrammerSoundImpl : Programmer sound callback for instrument ‘’ returned no sound.
UnityEngine.Debug:LogWarning (object)
FMODUnity.RuntimeUtils:DebugLogWarning (string) (at Assets/Plugins/FMOD/src/RuntimeUtils.cs:558)
FMODUnity.RuntimeManager:DEBUG_CALLBACK (FMOD.DEBUG_FLAGS,intptr,int,intptr,intptr) (at Assets/Plugins/FMOD/src/RuntimeManager.cs:81)

Hi,

Thank you for sharing the code.

Apologies, that is for when you are using a file rather than an audio table my mistake.

What is the value you are using for dialogueKey? Could I also get a screenshot of your Audio Table in your FMOD Studio project?
image

Sure thing. Do these screenshots show what you’re looking for?


And no worries on the script. Should I go ahead and change it back to how it was by default then?

1 Like

Hi, yes they are perfect!

In your first image, you have the key as Level1_1.Welcome2Cell in the audio table the key is listed as en_US/Level1_1.Welcome2Cell could you try using this as the key instead and see if it solves the issue?

Yes, that can be changed back to the default.

Hope this helps!


Tried changing the dialogueKey to accomodate the localisation key (which I’m sure I must have tried earlier), but sadly didn’t help.

Would it be possible to get a packaged project uploaded to your profile? You will have to register a project with us to be able to upload the project. When packaging the project please ensure built banks are included:
image

Sure thing Connor. Just uploaded it to my profile. The event in question is called ‘DogmaDialogue’. It has a corresponding audio table of the same name and both are the only things built to the ‘Dialogue’ bank. There are some other dialogue events in the ‘Master’ bank, but they’re just placeholders for the moment. Let me know if you have any questions about it.

1 Like

Hi,

Thank you for sharing the project. I think it might be an issue with the Programmer Instrument not being able to find the Audio Table files.

Could you try relocating the folder containing the Audio Table files and rebuilding the banks and making sure that the key is the same as the one in the Audio Table window. Let me know how that goes.

No worries.

By this, do you simply mean make sure that the Programmer Instrument sees and has a reference to the Audio Table? (rather than moving the location of the audio table folder itself?) I’ve attached a video of myself recreating the audio table from scratch and hooking it up to the Programmer Instrument. Can you tell from this whether or not I’ve been missing a step?

At the end of all this, I’m still getting the same “Waveform instance in error state 18” warning message. And of course no sound. When I change the dialogue key to one that’s not listed in the audio table, I get a different warning message:

[FMOD] EventInstance::createProgrammerSoundImpl : Programmer sound callback for instrument ‘’ returned no sound.

UnityEngine.Debug:LogWarning (object)
FMODUnity.RuntimeUtils:DebugLogWarning (string) (at Assets/Plugins/FMOD/src/RuntimeUtils.cs:558)
FMODUnity.RuntimeManager:DEBUG_CALLBACK (FMOD.DEBUG_FLAGS,intptr,int,intptr,intptr) (at Assets/Plugins/FMOD/src/RuntimeManager.cs:81)

So I’m fairly sure the dialogue key I’ve been using is the correct one.

Apologies, that wasn’t very clear.

Thank you for the video, it might have included what I was missing. error 18 is ERR_FILE_NOTFOUND which I was making me think that it was an issue with the folder directory. Rather it might be you have to enable the Include sub directories option in the Audio Table view:
image

“FMOD Studio searches recursively through every subfolder from the source directory for all audio files if the “Include sub directories” checkbox is checked. If this checkbox is not checked, FMOD Studio searches the directory itself, but none of its subfolders.” (FMOD Studio | Dialogue and Localization - Audio Tables) this would explain why we are getting the ERR_FILE_NOTFOUND error. Enable that option and let me know if that helps!

Ah! Think I’ve found it!

On a whim, I tried putting in a bunch of other dialogue keys and one of the shorter ones worked! Then I tried converting one of the longer ones from mp3 (yuck I know) to wav and that one worked too. I don’t know what the common thread is here, but it’s at least enough of a thread to pull on. Could it be that programmer instruments don’t play well with different file types?

Haha! Nope! The common thread was that the dialogue keys that WEREN’T working all had full stops in the title (ie “L1_1.FileName”). Removing them from the key name fixes the issue with (presumably) any file format.

1 Like

Hi,

Thank you for sharing the solution. I will make a note to add this to our documentation so it is clearer for others.