Hi,
I’m having an issue getting programmable sounds to work in Unity with FMOD. I’m basing my test off of the example script in your documentation. I’ve managed to trigger the example event ok with the programmer sound when its created by passing in a key from an audio table. For my project though I will require the ability to create a programmer sound from a Unity AudioClip and pass that to the event with the programmer sound. I’ve managed to create the FMOD sound ok from an Audio Clip using code found on these forums but I can’t get the event to play it. The event will play with the sound that’s part of it but the programmer sound part of it will not play. I’ve hit a bit of a brick wall with it and am unsure what I need to do to get this to work. I have provided the full source code for my test below.
Thanks,
Tom
Demo Source Code:
using System;
using System.Collections.Generic;
using UnityEngine;
using System.Runtime.InteropServices;
class ScriptUsageProgrammerSounds : MonoBehaviour
{
FMOD.Studio.EVENT_CALLBACK dialogueCallback;
static AudioClip Clip;
static FMOD.Sound Sound;
static bool _unityAudio;
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);
Clip = Resources.Load<AudioClip>("banana");
Sound = CreateSoundFromAudioClip(Clip);
//FMOD.Channel channel;
//FMODUnity.RuntimeManager.LowlevelSystem.playSound(Sound, null, false, out channel);
}
static FMOD.Sound CreateSoundFromAudioClip(AudioClip audioClip)
{
var samplesSize = audioClip.samples * audioClip.channels;
var samples = new float[samplesSize];
audioClip.GetData(samples, 0);
var bytesLength = (uint)(samplesSize * sizeof(float));
var soundInfo = new FMOD.CREATESOUNDEXINFO();
soundInfo.cbsize = Marshal.SizeOf(typeof(FMOD.CREATESOUNDEXINFO));
soundInfo.length = bytesLength;
soundInfo.format = FMOD.SOUND_FORMAT.PCMFLOAT;
soundInfo.defaultfrequency = audioClip.frequency;
soundInfo.numchannels = audioClip.channels;
FMOD.Sound sound;
var result = FMODUnity.RuntimeManager.LowlevelSystem.createSound("", FMOD.MODE.OPENUSER, ref soundInfo, out sound);
if (result == FMOD.RESULT.OK)
{
IntPtr ptr1, ptr2;
uint len1, len2;
result = sound.@lock(0, bytesLength, out ptr1, out ptr2, out len1, out len2);
if (result == FMOD.RESULT.OK)
{
var samplesLength = (int)(len1 / sizeof(float));
Marshal.Copy(samples, 0, ptr1, samplesLength);
if (len2 > 0)
{
Marshal.Copy(samples, samplesLength, ptr2, (int)(len2 / sizeof(float)));
}
result = sound.unlock(ptr1, ptr2, len1, len2);
if (result == FMOD.RESULT.OK)
{
result = sound.setMode(FMOD.MODE.LOOP_NORMAL);
if (result == FMOD.RESULT.OK)
{
Debug.Log("[FMOD] Successfully loaded programmer sound!");
return sound;
}
else
{
Debug.LogError("[FMOD] Failed to set mode to loop for programmer sound with error: " + result);
}
}
else
{
Debug.LogError("[FMOD] Failed to unlock programmer sound with error: " + result);
}
}
else
{
Debug.LogError("[FMOD] Failed to lock programmer sound with error: " + result);
}
}
else
{
Debug.LogError("[FMOD] Failed to load programmer sound with error: " + result);
}
return null;
}
void PlayDialogue(string key)
{
var dialogueInstance = FMODUnity.RuntimeManager.CreateInstance("event:/Character/Radio/Command");
// Pin the key string in memory and pass a pointer through the user data
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, IntPtr instancePtr, IntPtr parameterPtr)
{
// Recreate the event instance C# object
FMOD.Studio.EventInstance instance = new FMOD.Studio.EventInstance(instancePtr);
// 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;
Debug.Log("Event = " + type);
switch (type)
{
case FMOD.Studio.EVENT_CALLBACK_TYPE.CREATE_PROGRAMMER_SOUND:
{
var parameter = (FMOD.Studio.PROGRAMMER_SOUND_PROPERTIES)Marshal.PtrToStructure(parameterPtr, typeof(FMOD.Studio.PROGRAMMER_SOUND_PROPERTIES));
parameter.sound = Sound.getRaw();
//FMOD.Studio.SOUND_INFO dialogueSoundInfo;
//var keyResult = FMODUnity.RuntimeManager.StudioSystem.getSoundInfo(key, out dialogueSoundInfo);
//if (keyResult != FMOD.RESULT.OK)
//{
// Debug.Log("Result = " + keyResult);
// break;
//}
//FMOD.Sound dialogueSound;
//var soundResult = FMODUnity.RuntimeManager.LowlevelSystem.createSound(dialogueSoundInfo.name_or_data, dialogueSoundInfo.mode, ref dialogueSoundInfo.exinfo, out dialogueSound);
//if (soundResult == FMOD.RESULT.OK)
//{
// parameter.sound = dialogueSound.getRaw();
// 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(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;
}
void Update()
{
if (Input.GetKeyDown(KeyCode.Q))
{
PlayDialogue("640166main_MECO");
}
}
}