getParameterInfo returns garbage in Unity

Running the following code on a playing event instance:

FMOD.ChannelGroup chGroup;
FMOD.DSP dsp;
string name;
int _ignore;
uint _uignore;
int paramCount = 0;


Audio.CheckError(evtInstance.getChannelGroup(out chGroup), this);
Audio.CheckError(chGroup.getDSP(0, out dsp), this);

dsp.getInfo(out name, out _uignore, out _ignore, out _ignore, out _ignore);
s += string.Format("\n - {0}", name);

Audio.CheckError(dsp.getNumParameters(out paramCount), this);
for (int j = 0; j < paramCount; ++j)
{
FMOD.DSP_PARAMETER_DESC paramDesc = new FMOD.DSP_PARAMETER_DESC();
Audio.CheckError(dsp.getParameterInfo(j, out paramDesc), this);
string paramName = new string(paramDesc.name);
s += string.Format("\n   - param {0} : type: {1} name: '{2}' label: '{3}'",
    j,
    paramDesc.type,
    new string(paramDesc.name),
    new string(paramDesc.label)
    );
}

I get garbage data back from getParameterInfo, for instance:

- ChanGroup Fader
 - param 0 : type: -404006640 name: '' label: ''
 - param 1 : type: -404006640 name: '' label: ''

Same goes for paramDesc.desc, all useless data.

I’m using Unity 2017.2.5f1 and
fmodstudio11014_v2.unitypackage / FMOD Studio 1.10.14 64-bit Build #102821

Thanks very much for the info.

We are aware of this issue and have a task to investigate it further but do not have an ETA at this point.

Both the P/Invoke and structure are setup wrong.

Firstly the struct needs to marshal bytes, as this is fixed size. char in c# is 2-bytes wide, so 16 of those would be 32 bytes, which would not match the DLL.

[StructLayout(LayoutKind.Sequential)]
public struct DSP_PARAMETER_DESC
{
    public DSP_PARAMETER_TYPE   type;            /* [w] Type of this parameter. */
    [MarshalAs(UnmanagedType.ByValArray, SizeConst = 16)]
    public byte[]               name;            /* [w] Name of the parameter to be displayed (ie "Cutoff frequency"). */
    [MarshalAs(UnmanagedType.ByValArray, SizeConst = 16)]
    public byte[]               label;           /* [w] Short string to be put next to value to denote the unit type (ie "hz"). */
    public string               description;     /* [w] Description of the parameter to be displayed as a help item / tooltip for this parameter. */

    public DSP_PARAMETER_DESC_UNION desc;
}

Then the P/Invoke needs to change, as the DLL’s GetParameterInfo allocates the result, and returns its pointer through a pointer to pointer.

[DllImport(VERSION.dll)]
private static extern RESULT FMOD5_DSP_GetParameterInfo          (IntPtr dsp, int index, out IntPtr pDesc);

Now as we only have the pointer, we need to marshal the actual struct before giving it to the managed layer.

public RESULT getParameterInfo(int index, out DSP_PARAMETER_DESC desc)
{
    IntPtr pDesc;
    RESULT rc = FMOD5_DSP_GetParameterInfo(this.handle, index, out pDesc);

    int szDesc = Marshal.SizeOf(typeof(DSP_PARAMETER_DESC));
    desc = Marshal.PtrToStructure<DSP_PARAMETER_DESC>(pDesc);

    return rc;
}

Finally, in case you want name / label as a managed string, you’ll need to use the ASCII encoding to convert from the bytes in your code.

        string name = Encoding.ASCII.GetString(desc.name).TrimEnd('\0');
        string label = Encoding.ASCII.GetString(desc.label).TrimEnd('\0');

Then it all works just fine.

Hope that helps - Andy

2 Likes

Thank you, Andy! This patch works for me.
I’m on the old C#, so I had to make a small change:

// desc = Marshal.PtrToStructure<DSP_PARAMETER_DESC>(pDesc);
desc = (DSP_PARAMETER_DESC) Marshal.PtrToStructure(pDesc,
       typeof(DSP_PARAMETER_DESC));
1 Like