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:

In Unity creiamo una sottocartella in Assets/StreamingAssets e salviamo lì i nostri 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:

Nella parte inferiore della finestra selezioniamo la cartella in cui si trovano i nostri file 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!