AudioClip.GetData Equivalent in FMOD?

Hi there :slightly_smiling_face:

I’m currently trying to convert a speech recognition solution work with FMOD audio, rather than the built-in Unity Audio. I’m stumped at a point in the script where the Unity method AudioClip.GetData is used to receive some data. I’m wondering if there is a way to extract the same data from FMOD sounds?
FMOD Help

I’m aware of a method called ReadData in FMOD, but I was, unfortunately, unable to apply it to get the desired values.
I’m a bit new to working this deeply with FMOD, so any help is appreciated :slightly_smiling_face:

Hi,

There is a way to get the sample data from an audio source but there is a bit of setup to do, we will need to create a Sound to read the data from. Here is an example of how:

GetSampleData(string filePath)
    /// <summary>
    /// Return sample data in a byte array from an audio source using its file path 
    /// </summary>
    /// <param name="filePath"></param>
    /// <returns></returns>
	private byte[] GetSampleData(string filePath)
    {
        // Very useful tool for debugging FMOD function calls
        FMOD.RESULT result;

        // Sound variable to retrieve the sample data from
        FMOD.Sound sound; 

        // Creating the sound using the file path of the audio source 
        // Make sure to create the sound using the MODE.CREATESAMEPLE | MDOE.OPENONLY so the sample data can be retrieved
		result = FMODUnity.RuntimeManager.CoreSystem.createSound(filePath, FMOD.MODE.CREATESAMPLE | FMOD.MODE.OPENONLY, out sound);

        // Debug the results of the FMOD function call to make sure it got called properly
        if (result != FMOD.RESULT.OK)
        {
            Debug.Log("Failed to create sound with the result of: " + result);
            return null; 
        }

        // Retrieving the length of the sound in milliseconds to size the arrays correctly
		result = sound.getLength(out uint length, FMOD.TIMEUNIT.MS);

        if (result != FMOD.RESULT.OK)
        {
            Debug.Log("Failed to retrieve the length of the sound with result: " + result);
            return null; 
        }

        // Buffer which the sample data will be copied too 
        System.IntPtr buffer; 

        // Creating a pointer to newly allocated memory
        // This pointer must be released at the end of the function! 
        buffer = Marshal.AllocHGlobal((int)length * sizeof(byte));
		
        // Creating the return array which will have the sample data is a readable variable type 
        // Using the length of the sound to create it to the right size 
		byte[] byteArray = new byte[(int)length];

        // Retrieving the sample data to the pointer using the full length of the sound 
		result = sound.readData(buffer, length, out uint read);

        if (result != FMOD.RESULT.OK)
        {
            Debug.Log("Failed to retrieve data from sound: " + result);
            return null; 
        }

        // Make sure the pointer has been populated 
		if (_buffer != System.IntPtr.Zero)
		{			
            // Coping the data from our pointer to our usable array 
			Marshal.Copy(buffer, byteArray, 0, (int)length);
		}

        //Releasing the pointer 
        Marshal.FreeHGlobal(buffer); 

        //Returning the array populated with the sample data to be used
		return byteArray;
	}

Hopefully, calling Sound::readData this way will get you the values you are looking for!

Hope this helps!

Hello,
I have the exact same issue as the operator. I want to make use of the audioclip data in Unity, but with FMOD.
I want to use the audioclip’s data for the correct mouth synchronization in a dialogue system.

I have tried using your approach, which seems like the right approach
First of all, from which location do I get the file path? I’ve tried several file paths based on my folder structure already, but with no luck. What’s the correct path structure? Can you give me an example?
Also, I don’t seem to understand why your example requires a file path. Why not just use the event path instead to retrieve the audioclip?

I’ve also had a look at callbacks, and it seems to give me what I’m looking for, but it somehow only uses the master channel group. In my case I have a voice channel I wanna use. https://www.fmod.com/docs/2.02/unity/examples-dsp-capture.html

I think your documentation about how to implement this logic is kinda vague. It’s not really helping me.

Well I got your points here. Thanks for sharing

1 Like

Hi,

The file path I am using is: "C:\Users\XXX\Music\Epic SciFi Music.wav", but this was purely for the example. There are different ways to create a sound which can be found under FMOD API | Core API Reference.

In the example, as the DSP is being added to the MasterChannelGroup it is the only one that is needed but there are a number of ways to retrieve a channel. When referencing your voice channel could you elaborate on what it is? Could you screen shot it in your FMOD Studio Project?

Hi,
Thanks for your quick apply. Much appreciated.
Oh, I had no idea that I needed the full path including the filename. Just wondering. Doesn’t this mess up the code if the game is being built?
And also, I can’t really see the benefits in this logic, because then I would have to somewhere store hundreds of paths of dialogue, which is basically already are stored in the FMOD project.

About DSP. Maybe I did it wrong. Still trying to get my head around it. I want to rule out all audio but keep the Voice for the facial animations, because I don’t want other background noise to interfere.
Maybe I need a different approach?

Hi,

Again, this was just an example. Depending on where you are getting the audio source this will be different. E.g. Using an event.

Here is a reliable way to get the Voice Group from an Event Emitter. Make sure this is called after the event has started:

emitter = GetComponent<FMODUnity.StudioEventEmitter>();
if (emitter == null)
	return;
emitter.EventInstance.getChannelGroup(out FMOD.ChannelGroup masterChannelGroup);
masterChannelGroup.getGroup(0, out voiceGroup);

I am then attaching the DSP from the example to the voiceGroup.

Hope this helps!

Thanks for your reply, but it didn’t really help me.
Everything works perfectly on the masterchannel group, but I only want the “Voice” channel.

I’ve tried to get the channelgroup via the bus, based on the path to the voice channel. The Voice bus exists. I know that for a fact because I debugged it.
However, it wont allow me to add a DSP onto that channelgroup for some reason. The addDSP requires an index, but I’m kinda confused about which index it requires and what it’s for. I’ve tried several indexes like these [-3,-2,-1,0,1,2,30], but with the same outcome.
Apart from the Start function, I’ve also tried to add the DSP in runtime and while the NPC is talking, but it prints the same error.


So the issue with this method is that the channelGroup may not be ready when you are trying to assign the DSP to it. To resolve this we need to use a couple of commands:
bus.lockChannelGroup() will ensure that the channelGroup is created and will stay in memory, it will have to be unlocked in the future. (FMOD API | Studio API Reference)
FMODUnity.RuntimeManager.StudioSystem.flushCommands(); forces all commands to be called before continuing to ensure that the commands we are calling are being processed by the Studio System. (FMOD API | Studio API Reference).
FMODUnity.RuntimeManager.StudioSystem.flushSampleLoading() forces all sample loading and unloading to be completed so our calls can be run. (FMOD API | Studio API Reference)

if (FMODUnity.RuntimeManager.CoreSystem.getMasterChannelGroup(out currentMAster) == FMOD.RESULT.OK)
{
	FMODUnity.RuntimeManager.StudioSystem.getBus("bus:/In-World/Voice", out bus);

	bus.lockChannelGroup();
	FMODUnity.RuntimeManager.StudioSystem.flushCommands();
	FMODUnity.RuntimeManager.StudioSystem.flushSampleLoading();
	bus.getChannelGroup(out ChannelGroup group);

	if (FMODUnity.RuntimeManager.CoreSystem.createDSP(ref desc, out mCaptureDSP) == FMOD.RESULT.OK)
	{
		if (!currentMAster.hasHandle())
		{
			Debug.Log("No master");
			return;
		}
		FMOD.RESULT result = currentMAster.addDSP(0, mCaptureDSP);
		Debug.Log(result.ToString());
		if (result != FMOD.RESULT.OK)
		{
			Debug.LogWarningFormat("FMOD: Unable to add mCaptureDSP to the master channel group");
		}
		else
			success = true;
	}
	else
	{
		Debug.LogWarningFormat("FMOD: Unable to create a DSP: mCaptureDSP");
	}
}
else
{
	Debug.LogWarningFormat("FMOD: Unable to create a GCHandle: mObjHandle");
}

Try updating your code with this, hope it helps!

Thanks for your reply! Unfortunately It’s still not working. I’m still always getting the master channel’s audio just like before and with no errors.
I’m wondering why you are assigning “group”, if it isn’t going to be used. I did try to replace “currentMaster” with “group” but then the debug warning error shows up again. (Recent screenshot)

Apologies for that, I have included the whole script without reference issues.
EventDataAndBus.txt (5.1 KB)

That works perfectly!
Thank you so much for your help!

1 Like