https://www.fmod.com/resources/documentation-unity?version=2.0&page=examples-programmer-sounds.html
https://alessandrofama.com/tutorials/fmod-unity/programmer-sounds/
https://www.fmod.com/resources/documentation-api?version=1.10&page=content/generated/engine_ue4/programmer_sounds.html
//--------------------------------------------------------------------
//
// 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.
//
//--------------------------------------------------------------------
using System;
using System.Collections.Generic;
using UnityEngine;
using System.Runtime.InteropServices;
using FMOD.Studio;
class ScriptUsageProgrammerSounds : MonoBehaviour
{
FMOD.Studio.EVENT_CALLBACK dialogueCallback;
private EventInstance dialogueInstance;
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);
//dialogueInstance = FMODUnity.RuntimeManager.CreateInstance("event:/Tone/Dialogue");
}
public void Stop(bool stopPre = false)
{
dialogueInstance.stop(FMOD.Studio.STOP_MODE.IMMEDIATE);
}
void PlayDialogue(string key, bool stopPre = false)
{
if (stopPre)
{
dialogueInstance.stop(FMOD.Studio.STOP_MODE.IMMEDIATE);
}
else
{
dialogueInstance.release();
// Pin the key string in memory and pass a pointer through the user data
dialogueInstance = FMODUnity.RuntimeManager.CreateInstance("event:/Tone/Dialogue");
}
GCHandle stringHandle = GCHandle.Alloc(key, GCHandleType.Pinned);
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, FMOD.Studio.EventInstance instance, IntPtr parameterPtr)
{
// 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));
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:
// Now the event has been destroyed, unpin the string memory so it can be garbage collected
stringHandle.Free();
break;
}
return FMOD.RESULT.OK;
}
public void PlayA()
{
Stop(true);
}
public void PlayB()
{
PlayDialogue("456", false);
}
}