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:
In Unity erstellen wir unter Assets/StreamingAssets ein Unterordner und legen dort unsere Dialog-Audiodateien ab:
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:
Im unteren Bereich des Fensters wählen wir den Ordner aus, in dem sich unsere Audiodateien befinden:
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!