• Skip to primary navigation
  • Skip to main content

Alessandro Famà

Technical Audio Design

  • Portfolio
  • Tutorial
  • About
  • Alessandro Famà
  • Tutorial FMOD-Unity
  • FMOD Programmer Sounds in Unity

    I Programmer Sounds di FMOD ci permettono di riprodurre i suoni direttamente da un gruppo di file audio tramite un callback ricevuto. Questo avviene tramite tabelle audio. Si tratta di un gruppo di file audio non assegnati ad un evento. Questi file sono accessibili tramite un string-key (stringa). L’uso di Programmer Sounds consente, ad esempio, un’efficiente implementazione di dialoghi, nei quali il Sound Designer crea un singolo evento come template e riproduce i file audio all’interno di questo evento.

    Scarica il progetto Unity & FMOD su questo tutorial..

    Preparazione all’uso dei Programmer Sounds in Unity

    In FMOD Studio creiamo un nuovo evento e inseriamo il Programmer Instrument nella prima traccia:

    FMOD Studio Programmer Instrument
    FMOD Studio Programmer Instrument

    In Unity creiamo una sottocartella in Assets/StreamingAssets e salviamo lì i nostri file audio di dialogo:

    Cartella all'interno di StreamingAssets con file audio di dialogo
    Cartella all’interno di StreamingAssets con file audio di dialogo

    Nella scheda delle bank di FMOD Studio clicchiamo con il tasto destro del mouse su una bank (nel nostro caso la Master Bank) e selezioniamo New Audio Table -> New Audio Table:

    FMOD Studio opzione "New Audio Table"
    FMOD Studio opzione “New Audio Table”

    Nella parte inferiore della finestra selezioniamo la cartella in cui si trovano i nostri file audio:

    Percorso dei file audio della tabella audio
    Percorso dei file audio della tabella audio

    Codice C# per i Programmer Sounds di FMOD

    La documentazione di FMOD ci mostra un esempio leggermente datato sull’ utilizzo dei Programmer Sounds in Unity. LoweLevelSystem è stato sostituito da CoreSystem. Altrimenti lo script può essere copiato così com’è:

    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");
            }
        }
    }

    Inserisci lo script in qualsiasi GameObjecto e seleziona nell’inspector l’evento che abbiamo creato nella prima parte del tutorial. Se necessario, cambia le stringhe nella funziona Update() se i file audio sono chiamati diversamente. In modalità play verranno ripredotti i rispettivi file audio premendo premendo i tasti 1-5. Congratulazioni!