using System; using System.Collections.Generic; using UnityEngine; using System.Runtime.InteropServices; using UnityEngine.InputSystem; // https://qa.fmod.com/t/how-to-create-programmer-sound-from-audioclip/19466/2 public class PlayAudioClipInFmod : MonoBehaviour { public AudioClip clip; //public string event_name_str = "event:/VO/testProgrammerInstrumentVO"; public FMODUnity.EventReference EventName; 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(PlayFileCallBackUsingAudioFile); if (clip != null) PlayClipInFmod(clip); } public void PlayClipInFmod(AudioClip audioclip) { UnityEngine.Debug.Log("PlayClipinFmod " + 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); string key = audioclip.name; // I have no idea what this is for //////////////// HELP! I have no idea what to put as these parameters. SoundRequirements sound_requirements = new SoundRequirements(audioclip.name, audioclip.samples, 1, FMOD.SOUND_FORMAT.PCM16, audioclip.frequency, audioclip_data); //////////////////////////////////////////////////////////////////////////////// var dialogueInstance = FMODUnity.RuntimeManager.CreateInstance(EventName); // Pin the key string in memory and pass a pointer through the user data GCHandle stringHandle = GCHandle.Alloc(key); dialogueInstance.setUserData(GCHandle.ToIntPtr(stringHandle)); dialogueInstance.setCallback(dialogueCallback); dialogueInstance.start(); dialogueInstance.release(); } FMOD.Studio.EVENT_CALLBACK dialogueCallback; #if UNITY_EDITOR void Reset() { EventName = FMODUnity.EventReference.Find("event:/Character/Radio/Command"); } #endif [AOT.MonoPInvokeCallback(typeof(FMOD.Studio.EVENT_CALLBACK))] static FMOD.RESULT PlayFileCallBackUsingAudioFile(FMOD.Studio.EVENT_CALLBACK_TYPE type, IntPtr instPrt, IntPtr paramsPrt) { UnityEngine.Debug.Log("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); } 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; } /// /// Debug FMOD Function results only in Editor /// 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; } } class SoundRequirements { public string name; public int samples; public int channels; public FMOD.SOUND_FORMAT format; public int defaultFrequency; public float[] sampleData; /// /// /// /// /// /// /// /// /// public SoundRequirements(string name, int samples, int channel, FMOD.SOUND_FORMAT format, int defaultFrequency, float[] sampleData) { this.name = name; this.samples = samples; this.channels = channel; this.format = format; this.defaultFrequency = defaultFrequency; this.sampleData = sampleData; } }