Hello, I’m trying to play a simple AudioClip reference as a Programmer Sound in FMOD, but I’m not getting any Audio output. I’m sure the event is correct as it plays just fine if instead of using a Programmer Instrument I use a Single Instrument.
Sadly, the documentation isn’t really clear on how to achieve what I’m trying to do. This is my current code:
public FMODUnity.EventReference GenericSFXEvent;
FMOD.Studio.EVENT_CALLBACK soundCallback;
private void Awake()
{
soundCallback = new FMOD.Studio.EVENT_CALLBACK(FMODWrapper.PlayFileCallBackUsingAudioFile);
}
public void PlayFMODSound(AudioClip audioclip)
{
UnityEngine.Debug.Log("PlayClip In Fmod " + audioclip.name);
// Get the sample data from the clip and assign in to an array
float[] audioclip_data = new float[audioclip.samples * audioclip.channels];
audioclip.GetData(audioclip_data, 0);
// We no longer require the 'key' parameter as it was used to access the FMOD audio table.
// string key = audioclip.name;
// We are getting the information out of the Unity Audio clip passed into the function
SoundRequirements sound_requirements = new SoundRequirements(
// The name of the clip we are playing, makes it easier to identify when in code
audioclip.name,
// Parameters required to create sound exit info: https://fmod.com/docs/2.02/api/core-api-system.html#fmod_createsoundexinfo
audioclip.samples,
audioclip.channels,
FMOD.SOUND_FORMAT.PCMFLOAT,
audioclip.frequency,
// The sample data that will be copied into the sound when we create it
audioclip_data);
//
// Renamed this for clarity.
var audioClipInstance = FMODUnity.RuntimeManager.CreateInstance(GenericSFXEvent);
// Instead of passing in the key we will pass in the sound requirements that we have created.
GCHandle stringHandle = GCHandle.Alloc(sound_requirements);
audioClipInstance.setUserData(GCHandle.ToIntPtr(stringHandle));
// The callback to make the create the sound and assign it to the instance
audioClipInstance.setCallback(soundCallback);
// Play the sound
audioClipInstance.start();
// Release the memory, however if you would like to access parameters or other functions of the instane,
// you don't have to release it now.
audioClipInstance.release();
}
public void Update()
{
if (Keyboard.current.gKey.wasPressedThisFrame)
{
PlayFMODSound(SelectSound);
}
}
/// <summary>
/// Debug FMOD Function results only in Editor
/// </summary>
private static FMOD.RESULT ERRCHECK(FMOD.RESULT result, string failMsg)
{
#if UNITY_EDITOR
if (result != FMOD.RESULT.OK)
{
Debug.Log(failMsg + " with result: " + result);
return result;
}
#endif
return result;
}
and this is the code snippet from FMODWrapper:
[AOT.MonoPInvokeCallback(typeof(FMOD.Studio.EVENT_CALLBACK))]
public static FMOD.RESULT PlayFileCallBackUsingAudioFile(FMOD.Studio.EVENT_CALLBACK_TYPE type, IntPtr instPrt, IntPtr paramsPrt)
{
UnityEngine.Debug.Log("[<b><color=green>FMOD</color></b>] PlayFileCallBackUsingAudioFile event type " + type.ToString());
FMOD.Studio.EventInstance inst = new FMOD.Studio.EventInstance(instPrt);
if (!inst.isValid())
{
return FMOD.RESULT.ERR_EVENT_NOTFOUND;
}
// Retrieving the user data from the instance
inst.getUserData(out IntPtr clipDataPtr);
GCHandle clipHandle = GCHandle.FromIntPtr(clipDataPtr);
// Assinging the our data to a new struct so we can access all the information
SoundRequirements clip = clipHandle.Target as SoundRequirements;
// Depending on the callback type will decide what happens next
switch (type)
{
case FMOD.Studio.EVENT_CALLBACK_TYPE.CREATE_PROGRAMMER_SOUND:
{
// This is what we will use to pass the sound back out to our instance
var param = (FMOD.Studio.PROGRAMMER_SOUND_PROPERTIES)Marshal.PtrToStructure(paramsPrt, typeof(FMOD.Studio.PROGRAMMER_SOUND_PROPERTIES));
// Retrieve the masterGroup, or the channel group you wish to play the clip too
ERRCHECK(FMODUnity.RuntimeManager.CoreSystem.getMasterChannelGroup(out FMOD.ChannelGroup masterGroup), "Failed to get masterGroup from core system");
// Calculating the length of the audio clip by the samples and channels
uint lenBytes = (uint)(clip.samples * clip.channels * sizeof(float));
// Sound exit info to be used when creating the sound
FMOD.CREATESOUNDEXINFO soundInfo = new FMOD.CREATESOUNDEXINFO();
soundInfo.cbsize = Marshal.SizeOf(typeof(FMOD.CREATESOUNDEXINFO));
soundInfo.length = lenBytes;
soundInfo.format = FMOD.SOUND_FORMAT.PCMFLOAT;
soundInfo.defaultfrequency = clip.defaultFrequency;
soundInfo.numchannels = clip.channels;
// Creating the sound using soundInfo
FMOD.RESULT result = ERRCHECK(FMODUnity.RuntimeManager.CoreSystem.createSound(clip.name, FMOD.MODE.OPENUSER, ref soundInfo, out FMOD.Sound sound), "Failed to create sound");
if (result != FMOD.RESULT.OK)
return result;
// Now we have created our sound, we need to give it the sample data from the audio clip
result = ERRCHECK(sound.@lock(0, lenBytes, out IntPtr ptr1, out IntPtr ptr2, out uint len1, out uint len2), "Failed to lock sound");
if (result != FMOD.RESULT.OK)
return result;
Marshal.Copy(clip.sampleData, 0, ptr1, (int)(len1 / sizeof(float)));
if (len2 > 0)
Marshal.Copy(clip.sampleData, (int)(len1 / sizeof(float)), ptr2, (int)(len2 / sizeof(float)));
result = ERRCHECK(sound.unlock(ptr1, ptr2, len1, len2), "Failed to unlock sound");
if (result != FMOD.RESULT.OK)
return result;
ERRCHECK(sound.setMode(FMOD.MODE.DEFAULT), "Failed to set the sound mode");
if (result == FMOD.RESULT.OK)
{
param.sound = sound.handle;
param.subsoundIndex = -1;
// Passing the sound back out again to be played
Marshal.StructureToPtr(param, paramsPrt, false);
Debug.Log("[<b><color=green>FMOD</color></b>] Successfully created Sound");
}
else
return result;
}
break;
case FMOD.Studio.EVENT_CALLBACK_TYPE.DESTROY_PROGRAMMER_SOUND:
{
var param = (FMOD.Studio.PROGRAMMER_SOUND_PROPERTIES)Marshal.PtrToStructure(paramsPrt, typeof(FMOD.Studio.PROGRAMMER_SOUND_PROPERTIES));
var sound = new FMOD.Sound(param.sound);
FMOD.RESULT result = ERRCHECK(sound.release(), "Failed to release sound");
if (result != FMOD.RESULT.OK)
return result;
}
break;
case FMOD.Studio.EVENT_CALLBACK_TYPE.DESTROYED:
clipHandle.Free();
break;
}
return FMOD.RESULT.OK;
}
/// <summary>
/// Debug FMOD Function results only in Editor
/// </summary>
private static FMOD.RESULT ERRCHECK(FMOD.RESULT result, string failMsg)
{
#if UNITY_EDITOR
if (result != FMOD.RESULT.OK)
{
Debug.Log(failMsg + " with result: " + result);
return result;
}
#endif
return result;
}
I’ve been scratching my head for days trying to figure out why this doesn’t work, so any help would be really appreciated!