General advice on user-friendly process for players to upload audio assets then pipe them through FMOD-powered Unity?

Hi,

An option you have is using Programmer Instrument, explained in the Glossary. These allow for files outside of the FMOD and game project files to be used as audio sources.

You will need to include: using System; and using System.Runtime.InteropServices; at the top of your code file.

Create an FMODUnity.EventReference variable which will be used to instantiate your Programmer Instrument from the FMOD Project.

Then create an FMOD.Studio.EVENT_CALLBACK variable which will be used to create the sound to be played by FMOD.

In

void Start()
{
	yourPlayBackVariable = new FMOD.Studio.EVENT_CALLBACK(PlayFileCallBack);
}

This instantiates your EVENT_CALLBACK to be used in the PlayAudioFile(string location) function. Call this when the sound is ready to be played, how it gets the parameter location is up to you. Be sure that location is the full file path to the audio source.

PlayAudioFile(string location) Function
public void PlayAudioFile(string location)
{
	var eventInstance = FMODUnity.RuntimeManager.CreateInstance(yourEventReference);
	
	// FMOD.RESULT is a very useful debugging tool to ensure that FMOD functions have run properly 
	FMOD.RESULT result; 
	if (yourEventInstance.isValid() == false)
	{
		Debug.Log("Failed to create instance, instance invalid");
		return;
	}
	// Lock the file location in memory to be used in the CALLBACK function to find the audio source
	GCHandl stringLocation = GCHandle.Alloc(location);
	// Assigning this data to the created instance 
	result = eventInstnace.setUserData(GCHandle.ToIntPtr(stringLocation));
	
	// Using an if statement like this after most FMOD function calls will help debug errors in code 
	if (result != FMOD.RESULT.OK)
	{
		Debug.Log("Failed to create evenInstance with a result of " + result);
		return;
	}
	
	
	// Check the result after each function call 
	result = eventInstance.setCallback(yourPlayBackVaraible); 
	result = eventInstance.start();
	// The sound has successfully been created and played 
}

This is your FMOD.Studio.EVENT_CALLBACK function used to create the sound for FMOD to play using the audio source file location.

CALLBACK Function
[AOT.MonoPInvokeCallback(typeof(FMOD.Studio.EVENT_CALLBACK))]
    static FMOD.RESULT YourCallBackFunction(FMOD.Studio.EVENT_CALLBACK_TYPE type, IntPtr instancePtr, IntPtr parameterPtr)
    {
        FMOD.Studio.EventInstance instance = new FMOD.Studio.EventInstance(instancePtr);

        if (instance.isValid() == false)
        {
            UnityEngine.Debug.Log("Failed to create instance, instance invalid");
            return FMOD.RESULT.ERR_EVENT_NOTFOUND;
        }

        //Retrive the user data 
        IntPtr stringPtr;
        instance.getUserData(out stringPtr);

        // Retrieving the path of the audio source from the user data
        GCHandle stringHandle = GCHandle.FromIntPtr(stringPtr);
        String location = 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.Sound audioSound;
                    FMOD.RESULT result;

                    // Creating the sound using the location of the audio source 
                    result = FMODUnity.RuntimeManager.CoreSystem.createSound(location, soundMode, out audioSound);

                    if (result == FMOD.RESULT.OK)
                    {
                        parameter.sound = audioSound.handle;
                        parameter.subsoundIndex = -1;
                        Marshal.StructureToPtr(parameter, parameterPtr, false);
                    }
                    break;
                }
            case FMOD.Studio.EVENT_CALLBACK_TYPE.DESTROY_PROGRAMMER_SOUND:
                {
                    var paramerter = (FMOD.Studio.PROGRAMMER_SOUND_PROPERTIES)Marshal.PtrToStructure(parameterPtr, typeof(FMOD.Studio.PROGRAMMER_SOUND_PROPERTIES));
                    var sound = new FMOD.Sound(paramerter.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 garbaged collected
                    stringHandle.Free();
                    break;
                }
        }
        return FMOD.RESULT.OK;
    }

Once this is all set up users will be able to pass in the location of audio sources which you can then play using FMOD.

A full script example of Programmer Sounds being used can be found under Scripting Examples | Programmer Sounds. Keep in mind, in the example it is using an audio table and not the file location of an audio source, but it may be a useful reference.

Hope this helps!

3 Likes