Get sound data after dsp processing

Since we are in the Unity forum, I’m assuming you ultimately want to do this these in C# / Unity. I’ll put some code here to get you started, ultimately you’ll need to extend this for your desired goal. Eventually this code will be put into our documentation to help others.

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

class ScriptUsageCaptureDSP : MonoBehaviour
{
    FMOD.DSP mCaptureDSP;
    FMOD.DSP_READCALLBACK mReadCallback;
    float[] mDataBuffer;
    GCHandle mObjHandle;

    [AOT.MonoPInvokeCallback(typeof(FMOD.DSP_READCALLBACK))]
    static FMOD.RESULT CaptureDSPReadCallback(ref FMOD.DSP_STATE dsp_state, IntPtr inbuffer, IntPtr outbuffer, uint length, int inchannels, ref int outchannels)
    {
        FMOD.DSP_STATE_FUNCTIONS functions = Marshal.PtrToStructure<FMOD.DSP_STATE_FUNCTIONS>(dsp_state.functions);

        IntPtr userData;
        functions.getuserdata(ref dsp_state, out userData);

        GCHandle objHandle = GCHandle.FromIntPtr(userData);
        ScriptUsageCaptureDSP obj = objHandle.Target as ScriptUsageCaptureDSP;

        // Copy the incoming buffer to process later
        int lengthElements = (int)length * inchannels;
        Marshal.Copy(inbuffer, obj.mDataBuffer, 0, lengthElements);

        // Copy the inbuffer to the outbuffer so we can still hear it
        Marshal.Copy(obj.mDataBuffer, 0, outbuffer, lengthElements);

        return FMOD.RESULT.OK;
    }

    void Start()
    {
        // Assign the callback to a member variable to avoid garbage collection
        mReadCallback = CaptureDSPReadCallback;

        // Allocate a data buffer large enough for 8 channels with default mix buffer of 1024 samples, pin the memory to avoid garbage collection
        mDataBuffer = new float[1024 * 8];

        // Get a handle to this object to pass into the callback
        mObjHandle = GCHandle.Alloc(this);

        // Define a basic DSP that receives a callback each mix to capture audio
        FMOD.DSP_DESCRIPTION desc = new FMOD.DSP_DESCRIPTION();
        desc.numinputbuffers = 1;
        desc.numoutputbuffers = 1;
        desc.read = mReadCallback;
        desc.userdata = GCHandle.ToIntPtr(mObjHandle);

        // Create an instance of the capture DSP and attach it to the master channel group to capture all audio
        FMOD.ChannelGroup masterCG;
        FMODUnity.RuntimeManager.CoreSystem.getMasterChannelGroup(out masterCG);
        FMODUnity.RuntimeManager.CoreSystem.createDSP(ref desc, out mCaptureDSP);
        masterCG.addDSP(0, mCaptureDSP);
    }

    void OnDestroy()
    {
        // Remove the capture DSP from the master channel group
        FMOD.ChannelGroup masterCG;
        FMODUnity.RuntimeManager.CoreSystem.getMasterChannelGroup(out masterCG);
        masterCG.removeDSP(mCaptureDSP);

        // Release the DSP and free the object handle
        mCaptureDSP.release();
        mObjHandle.Free();
    }

    void Update()
    {
        // Do something with mDataBuffer here
    }
}

To answer your above questions, indeed Sound::lock is for accessing the audio of the audio asset, it doesn’t include DSP processing, this code does, it just depends on where you attach it. In the example I attach it to the master channel group.

As in your code snippet and mine, the incoming audio is in inbuffer, the outgoing audio is in outbuffer. It’s the job of the DSP to transfer audio from inbuffer to outbuffer, hence why I copy the data, otherwise it would be silent. The format of the data is PCM float, usually within the range of -1.0f to 1.0f, remember to multiply 1<<15 before converting to int32 and clamp before truncating to int16.