Memory Management problem with DSP : mDSPLevelsPool not cleaned up properly

Hello !

I tried to do a cube reacting to the beat of a given sound.
This works quite well, however each time I close my game, I get a warning from FMOD saying :

[FMOD] SystemI::close : mDSPLevelsPool not cleaned up properly!. 64 bytes remaining.

(The bytes remaining are not always the same, depending on the moment I close my game I think.)

using System;
using System.Collections;
using UnityEngine;
using System.Runtime.InteropServices;

class SoundSpectrumBeat : MonoBehaviour
{
    public Material normalMaterial;
    public Material activeMaterial;
    private bool isActive = false;

    [Tooltip("Path to the file containing the beat reference.")]
    public string beatReferencePath = "/Audio/Beats/musique-Glockenspiel.mid";
    public float activationThreshold = -45.0f;
    public float disactivationThreshold = -50.0f;

    [Tooltip("The volume percentage (between 0 and 1).")]
    public float volume = 1.0f;

    [Tooltip("The delay to start the music (in seconds).")]
    public float delay = 0.0f;

    private bool started = false;

    public Action onBeatHit = null;

    FMOD.DSP fft;

    const int WindowSize = 1024;

    static private int availableId = 0;
    private int id = availableId++;

    private FMOD.ChannelGroup channelGroup;
    private FMOD.ChannelGroup volumeAdjustedChannelGroup;
    private FMOD.Sound sound;

    void Start()
    {   
        if(disactivationThreshold > activationThreshold) {
            Debug.LogError("Disactivation threshold should be lower than activation threshold.");
        }

        GetComponent<Renderer>().material = normalMaterial;

        FMODUnity.RuntimeManager.CoreSystem.createDSPByType(FMOD.DSP_TYPE.FFT, out fft);
        fft.setParameterInt((int)FMOD.DSP_FFT.WINDOWTYPE, (int)FMOD.DSP_FFT_WINDOW.HANNING);
        fft.setParameterInt((int)FMOD.DSP_FFT.WINDOWSIZE, WindowSize * 2);

        Debug.Log(id);
        // FMOD.ChannelGroup channelGroup;
        FMODUnity.RuntimeManager.CoreSystem.createChannelGroup("SoundSpectrumBeat"+id.ToString(), out channelGroup);
        channelGroup.addDSP(FMOD.CHANNELCONTROL_DSP_INDEX.TAIL, fft);
        
        FMODUnity.RuntimeManager.CoreSystem.createChannelGroup("SoundSpectrumBeatMuted"+id.ToString(), out volumeAdjustedChannelGroup);
        volumeAdjustedChannelGroup.addGroup(channelGroup);
        volumeAdjustedChannelGroup.setVolume(volume);

        FMOD.ChannelGroup masterGroup;
        FMODUnity.RuntimeManager.CoreSystem.getMasterChannelGroup(out masterGroup);
        masterGroup.addGroup(volumeAdjustedChannelGroup);

        FMOD.RESULT res;
        res = FMODUnity.RuntimeManager.CoreSystem.createStream(Application.dataPath+beatReferencePath, FMOD.MODE.DEFAULT, out sound);
        // res = FMODUnity.RuntimeManager.CoreSystem.createStream(Application.dataPath+"/Audio/FMod/project/Assets/musique-Glockenspiel.wav", FMOD.MODE.DEFAULT, out sound);
        if(res != FMOD.RESULT.OK) {
            Debug.LogWarning(Application.dataPath);
            Debug.LogError("Failed to open specified sound file (Reason: "+res+")");
        }

        StartCoroutine(StartDelayed(sound, channelGroup));
    }

    IEnumerator StartDelayed(FMOD.Sound sound, FMOD.ChannelGroup channelGroup) {
        yield return new WaitForSecondsRealtime(delay);

        FMOD.Channel channel;
        FMODUnity.RuntimeManager.CoreSystem.playSound(sound, channelGroup, false, out channel);
        channel.setPriority(0);
        started = true;
    }

    const float WIDTH = 10.0f;
    const float HEIGHT = 0.1f;

    void Update()
    {
        if(!started) {
            return;
        }

        IntPtr unmanagedData;
        uint length;
        fft.getParameterData((int)FMOD.DSP_FFT.SPECTRUMDATA, out unmanagedData, out length);
        // FMOD.DSP_PARAMETER_FFT fftData = (FMOD.DSP_PARAMETER_FFT)Marshal.PtrToStructure(unmanagedData, typeof(FMOD.DSP_PARAMETER_FFT));
        FMOD.DSP_PARAMETER_FFT fftData = Marshal.PtrToStructure<FMOD.DSP_PARAMETER_FFT>(unmanagedData);
        float[][] spectrum = fftData.spectrum;

        if (fftData.numchannels > 0)
        {
            bool shouldActivate = false;
            float maxLevel = -10000f;
            for (int i = 0; i < WindowSize; ++i)
            {
                float level = lin2dB(spectrum[0][i]);
                maxLevel = Mathf.Max(level, maxLevel);
            }

            if(isActive) {
                if(maxLevel < disactivationThreshold) {
                    isActive = false;
                    GetComponent<Renderer>().material = normalMaterial;
                }
            }
            else {
                if(maxLevel > activationThreshold) {
                    isActive = true;
                    GetComponent<Renderer>().material = activeMaterial;
                    if(onBeatHit != null) {
                        onBeatHit();
                    }
                }
            }
        }

        Marshal.FreeHGlobal(unmanagedData);
    }

    float lin2dB(float linear)
    {
        return Mathf.Clamp(Mathf.Log10(linear) * 20.0f, -80.0f, 0.0f);
    }

    private void OnDestroy() {
        Debug.Log("Destruction");
        channelGroup.removeDSP(fft);
        channelGroup.release();
        volumeAdjustedChannelGroup.release();
        fft.release();
        sound.release();
    }
}

Can you, please, help me spot the point where I could cause a memory lack or a memory management problem ?

I’m a newbie in using FMOD and C#, I search in the docs for those details but didn’t found anything.

Thanks !

PS: I based this script on the one I found on this thread.

Hi zetarov,

I created a basic unity project using the script you attached and wasn’t able to reproduce the issue. If you could attach the log, that might help narrow down what’s going on. Also, which version of fmod are you using?