Getting Parameter IDs is not straightforward

I have some local parameters that are used on a number of different events (like normalised speed, for example), and I want to create functions that the designers can use to get and set parameter values on event instances without using strings.

Get/SetParameterByName() works fine, but if I’m updating a parameter at a high frequency I don’t want FMOD doing a string lookup multiple times per frame, so I figured I would use Get/SetParameterbyID() instead. However, using eventRef.Name always returns 0,0 as the parameter ID, so I looked through the forums and found an FMOD team member suggesting someone else use getParameterDescriptionByName(), then pulling the ID from the description, but this too only gave me 0,0 as the ID.

After scouring the documentation and forums and finding nothing on this, I finally discovered that if I pass in the EventInstance that I’m trying to get/set the parameter on, I can use eventInstance.getDescription() to access the EventInstance’s description, then [eventInstanceDescription].getParameterDescriptionByName() to access the Parameter’s description, then [parameterDescription].id to grab the ID and store it for using in the Get/SetParameterbyID() function.

Here’s some example code, since that explanation is kinda twisty:

private static PARAMETER_ID GetParamID(EventInstance instance, ParamRef parameter)
		{
			instance.getDescription(out EventDescription eventDesc);
			eventDesc.getParameterDescriptionByName(parameter.Name, out PARAMETER_DESCRIPTION paramDesc);
			return paramDesc.id;
		}

Sorry if I have made any mistakes above, I am paraphrasing from my actual code which is split into a couple of functions across a couple of classes for reasons I won’t go into.

Anyway, that’s how I’ve solved it for now, hopefully this is useful to others. It does leave me with some questions though:

  1. If you’re not supposed to use Get/SetParameterByID() on local parameters, why is it a function in the EventInstance class?
  2. If you’re supposed to use Get/SetParameterByName() all the time, is it actually more efficient than it appears? And if so, why is that not in the documentation?
  3. I know there is an EditorParamRef in the Cache for each event that uses each parameter, but their IDs appear to be identical, so why can’t I access them from ParamRef.ID? Why return the default value instead?

I know multiple people who have had to solve this problem in various convoluted ways, so I think there should either be a more straightforward way to do it, documentation on how to do it as it is, or documentation explaining why to use Get/SetParameterByName() instead.

Hi, apologies for the delayed response,

To clarify, there’s two kinds of methods to get/set parameters by name/ID - the Studio::EventInstance methods, and the Studio::System methods. The former can be used to get/set the value of any parameter being used by the event, including global parameters, and the latter can only be used to get/set the value of global parameter.

To address your questions, in order:

  1. You are supposed to call EventInstance::get/setParameterByID() on local parameters, but the function requires a parameter ID, in the same way attempting to get an event by GUID requires an event GUID - this is why eventRef.Name returned 0,0 as the parameter ID. If I may ask, how did you come to conclusion that you’re not supposed to use get/setParameterByID() on local parameters?

  2. You’re not necessarily supposed to get/set a parameter by name instead of by ID all the time - they’re just tools to accomplish getting/setting a parameter. As for efficiency, if you are getting/setting parameters a lot, then it would be more efficient to manually get and store the parameter ID, as the “by name” methods do perform a name-to-ID lookup internally

  3. I’m not entirely sure what you mean regarding ParamRef.ID and returning the default value - would you mind elaborating?

That said, thanks for detailing your thoughts and process - I’ve flagged some documentation changes around getting/setting parameters.

Hi Louis,

  1. I only got that impression because I could find no documentation that outlined how to get a local parameter’s ID. I thought maybe it was difficult on purpose to prevent people doing an inefficient thing.

  2. I’m glad to hear that I was right about name-to-ID lookup adding an extra step — this is why I wanted to store the ID.

  3. When looking in the Unity Inspector, an EventRef has a bunch of data attached to it, including the GUID. But a ParamRef is just a name and a value. Here’s an example of one of each on a scriptable object:
    image

A ParamRef also appears to have an ID on it, despite it not showing in the Unity Inspector window:
image
But if I try to access this directly, it always returns the value (0,0)

Now my understanding is (and please correct me if I’m wrong) that each local parameter has only one ID, so why can’t I do a name-to-ID lookup through some global FMODUnity function? Why do I have to get a specific event description from an event that references that parameter, and then call [eventDescription].getParameterDescriptionByName(parameter.Name, out PARAMETER_DESCRIPTION paramDescription) on that event description to access a parameter description which I can then get the ID out of?

The parameter ID’s are stored in the FMOD Cache in Unity, so why aren’t they stored in ParamRef.ID at editor time, rather than requiring me to cache the value myself at runtime?

In case my writing isn’t very clear, here’s another way to show what I mean with pseudo-code:

Expectation:

ParamID = ParamRef.ID;

Reality:

ParamID = ParamRef.ID? // No, that's always (0,0). Get an Event Instance instead.
OK, ParamID = EventInstance.Param.ID? // No, get the Event Description.
OK, ParamID = EventInstance.EventDescription.Param.ID? // No, get the Parameter Description.
OK, ParamID = EventInstance.EventDescription.ParameterDescription.ID? // Yes, now write that down so you can use it later.

There may well be a simpler way, but this was the best I could manage in a few hours, and it felt like looking for the car keys and finally discovering that they were in the kettle all along.

This is due to the design pattern FMOD uses to make EventInstance more lightweight by storing entity metadata in corresponding “Description” objects - it is unfortunately a bit cumbersome to traverse through descriptions to get to the ID.

On the explicitly user-facing side, ParamRef is used to store Global parameter paths/values, and doesn’t assign anything to the ID field, which is why you’re getting (0,0) from it. On the less user-facing side, they are used by StudioEventEmitter to store parameter references - StudioEventEmitter performs a name-to-ID lookup for thea given parameter of the selected event, and stores the corresponding parameter ID in the ParamRef.ID field. Editor-only functionality such as EditorParamRef won’t work in-game, which is why we don’t want people to use it.

A means of simplifying access to parameter IDs based on the cached data would be useful (similar to how EventReference works), as would a name-to-ID lookup function, so I’ve added both to our internal feature/improvement tracker.

Ah, that all makes sense. Thanks for explaining and adding it to the feature tracker! Having easier access to Param-IDs through ParamRef would be great though, I hope it finds its way into an update!

1 Like

I have come across this in a bit of a specific case. I am working with Unity DOTS and so far have found a surprisingly pleasant way to integrate fmod into DOTS.

However, I would like to give designers a way to assign parameters in the editor but then only track them through their IDs. This means that at baking time (DOTS specific terminology) I’d like to look up the parameter ID from the parameter name. At this point the EventInstance does not exist yet (there might be some convoluted way to create it earlier and attempt to reuse it but that would be way more complex).

One way to go about it would be to create a new EventInstance during baking, just to read the parameter ID as described in the code snippet of the original post and then immediately dispose of the EventInstance. This seems extremely stupid and wasteful.

I would assume that IDs of local parameters are unique per event but not per event instance. Is that correct?
If so, couldn’t there be a static function like
static int RuntimeManager.GetParameterIdByName(EventReference|GUID|string event, string parameterName)
Is that what you were referring to with the feature request @Louis_FMOD?

All parameter IDs, local or global, are functionally the same as GUIDs and should be globally unique. Two events can make use of the same parametert, but the parameter itself will use the same ID.

That is essentially the feature request I noted internally, yes.

Instead of creating an EventInstance, you can load your Bank(s), retrieve the EventDescription from the System or Bank, then call one of EventDescription’s getParameterDescription functions and retrieve the ID from that. This should be far less wasteful than creating an EventInstance, as you’ll never load any sample data, just event metadata.

+1 for an easier way to reference parameters in a Monobehavior. I have an AudioManager class that I use to trigger FMOD events; and using FMODUnity.EventReference for those works nicely, as I can select from the available events and there is no room for error. For parameters I guess I will have to rely on simple strings instead.

1 Like

I’ve noted your interest internally.