• Skip to primary navigation
  • Skip to main content

Alessandro Famà

  • Portfolio
  • Game Audio Tutorials
  • Wiki
  • Über Mich
  • Impressum
Alessandro Famà > Game Audio Tutorials > FMOD + Unity Tutorials > FMOD Programmer Sounds in Unity

FMOD Programmer Sounds in Unity

Programmer Sounds sind dafür da, um Sounds direkt aus einer Gruppe von Audiodateien über einen erhaltenen Callback abzuspielen. Das passiert über Audio-Tables. Das sind eine Gruppe von Audiodateien, die keinem Event zugeordnet sind. Diese Dateien können über einen String-Key aufgerufen werden. Die Verwendung von Programmer Sounds ermöglicht z.B. eine effiziente Implementierung von Dialogsystemen, bei denen der Sound Designer ein einziges Event als Dialogvorlage erstellt und worüber die Audiodateien anschließend abgespielt werden.

Lade dir das Unity & FMOD Projekt zu diesem Tutorial herunter.

Vorbereitung für die Verwendung von FMOD Programmer Sounds in Unity

In FMOD Studio erstellen wir ein neues Event und fügen in die erste Spur ein Programmer Instrument ein:

FMOD Studio Programmer Instrument
FMOD Studio Programmer Instrument

In Unity erstellen wir unter Assets/StreamingAssets ein Unterordner und legen dort unsere Dialog-Audiodateien ab:

Unity StreamingAssets-Ordner mit Dialog-Audiodateien
Unity StreamingAssets-Ordner mit Dialog-Audiodateien

Zurück zu FMOD Studio wechseln wir in den Banks-Tab und mit einen Rechtsklick auf eine Bank (in unserem Fall auf die Master-Bank) wählen wir New Audio Table -> New Audio Table:

FMOD Studio "New Audio Table" Option
FMOD Studio „New Audio Table“ Option

Im unteren Bereich des Fensters wählen wir den Ordner aus, in dem sich unsere Audiodateien befinden:

FMOD Studio Audio Table Source Ordner
FMOD Studio Audio Table Source Ordner

Code für FMOD Programmer Sounds in Unity schreiben

Die FMOD Docs zeigen uns ein nur leicht veraltetes Beispiel über die Verwendung von Programmer Sounds in Unity an. LoweLevelSystem wurde durch CoreSystem ersetzt. Ansonsten kann der Skript Eins-zu-eins übernommen werden:

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

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

    [FMODUnity.EventRef]
    public string fmodEvent;
    
    void Start()
    {
        dialogueCallback = new FMOD.Studio.EVENT_CALLBACK(DialogueEventCallback);
    }

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

        GCHandle stringHandle = GCHandle.Alloc(key, GCHandleType.Pinned);
        dialogueInstance.setUserData(GCHandle.ToIntPtr(stringHandle));

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

    static FMOD.RESULT DialogueEventCallback(FMOD.Studio.EVENT_CALLBACK_TYPE type, FMOD.Studio.EventInstance instance, IntPtr parameterPtr)
    {
        IntPtr stringPtr;
        instance.getUserData(out stringPtr);

        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();
                    sound.handle = parameter.sound;
                    sound.release();
                }
                break;
            case FMOD.Studio.EVENT_CALLBACK_TYPE.DESTROYED:
                stringHandle.Free();
                break;
        }
        return FMOD.RESULT.OK;
    }

    void Update()
    {
        if (Input.GetKeyDown(KeyCode.Alpha1))
        {
            PlayDialogue("dialogue-001");
        }
        if (Input.GetKeyDown(KeyCode.Alpha2))
        {
            PlayDialogue("dialogue-002");
        }
        if (Input.GetKeyDown(KeyCode.Alpha3))
        {
            PlayDialogue("dialogue-003");
        }
        if (Input.GetKeyDown(KeyCode.Alpha4))
        {
            PlayDialogue("dialogue-004");
        }
        if (Input.GetKeyDown(KeyCode.Alpha5))
        {
            PlayDialogue("dialogue-005");
        }
    }
}

Füge den Skript in ein beliebiges GameObject als Component ein und wähle im Inspector das Event, welches wir im ersten Schritt erstellt haben. Ändere gegebenenfalls die „Keys“, die in Unitys Update()-Methode stehen, wenn deine Audiodateien andere Namen besitzen sollten. Im Play-Modus wirst du beim Drücken der Tasten 1-5 die jeweiligen Audiodateien hören. Herzlichen Glückwunsch!