Error executing result = instance->m_Sound->lock(offsetBytes, lengthBytes, &ptr1, &ptr2, &len1, &len2) (An invalid parameter was passed to this function. )

I’m getting this error when calling AudioClip.GetData. It seems to be caused when I pass an index that tries to access samples outside the 1st channel. Is this a bug and if it is, is there a workaround?

Edit to include code. This uses MathNet so won’t compile in Unity out of the box. I should also note that GetData seems to sometimes start returning false and I have to Stop/Play a bunch of times before it will start returning true again. I’m not sure what’s up with that either.

using UnityEngine;
using System.Collections;

public class FFTTest : MonoBehaviour {

	bool filtered;
	AudioClip clip;
	AudioSource audioSrc;

	int maxSamples;
	int sampleSize = 128;
	int sampleIdx = 0;
	MathNet.Numerics.Transformations.RealFourierTransformation rft;

	float playTimeStart;

	void Start()
	{
		filtered = false;
		clip = Resources.Load("Audio/<<SOUND FILE>>") as AudioClip;
		audioSrc = Camera.main.gameObject.GetComponent<AudioSource>();

		audioSrc.clip = clip;
		rft = new MathNet.Numerics.Transformations.RealFourierTransformation(MathNet.Numerics.Transformations.TransformationConvention.Default);
		maxSamples = clip.channels * clip.samples;
	}

	// Use this for initialization
	void Filter () {
		float [] filteredSamples = new float[maxSamples];
		bool res = false;
		float[] samples = new float[sampleSize];

		while(sampleIdx + sampleSize < maxSamples)
		{
			double [] real;
			double [] img;
			res = clip.GetData(samples, sampleIdx); //ERROR HERE WHEN sampleIdx >= maxSamples/2
			if(res)
			{
				filtered = true;
			}
				
			double [] dsamples = System.Array.ConvertAll(samples, x => (double)x);
			rft.TransformForward(dsamples, out real, out img);

			double f0 = 1.5;
			double DCGain = 100;
			double order = 2;
			double binWidth = clip.frequency / (double)(sampleSize); // Hz
			//do filter
			for(int i = 0; i < real.Length; i++)
			{
				double binFreq = binWidth * i;
				double gain = DCGain / ( System.Math.Sqrt( ( 1 + System.Math.Pow( binFreq / f0, 2.0 * order ) ) ) );

				if(i > (real.Length>>3))
				{
					real _*= gain;_
  •  		}*
    
  •  		if(i > (real.Length>>3))*
    
  •  		{*
    

img *= gain;
* }*
* }*

* double [] dsamples2;*
* rft.TransformBackward(real, img, out dsamples2);*

* float [] samples2 = System.Array.ConvertAll(dsamples2, x => (float)x);*

* int idx = 0;*
* for(int i = sampleIdx; i < sampleIdx + sampleSize; i++)*
* {*
_ filteredSamples = samples2[idx++];
* }
sampleIdx += sampleSize;
}*_

* res = audioSrc.clip.SetData(filteredSamples, 0);*
* audioSrc.Play();*
* playTimeStart = Time.time;*
* }*

* // Update is called once per frame*
* void Update () {*
* if(!filtered)*
* {*
* Filter();*
* }else*
* {*

* }*
* }*
}

I’m not sure what you mean by “outside the 1st channel”. The samples for the different channels are interleaved. So if you have a dual channel audio, the first float value is for channel 1 the second float value is for channel 2 the third for cnannel 1 the fourth for channel 2 and so on.

You probably passed an offset that’s outside of the buffer. You should include more information in your question. Specifically:

  • What audio clip do you use? That means how many samples and how many channels does it have?
  • Show the code that you’re using
  • Tell us the exact value that you pass as offset which does produce that error.

The error comes from the native C++ part of Unity and most likely isn’t a bug. The error clearly mentions bad parameters. The only parameters you pass to GetData is:

  • the float array
  • the offset

So make sure the offset is within the sample count of the clip and make sure your array length is divisible by your channel count. So if you have 2 channels, make sure the array is a multiple of 2.

edit

Well, i’m pretty sure that GetData is based on “clip samples”, not on “raw samples”. So it most likely does always advance two samples (only for stereo clips with two channels). The same way as the length of the clip is based on the logical sample count divided by the frequency. So don’t multiply by the channel count when choosing a position in the clip. Also keep in mind that since the channels are interleaved you can’t do a FFT over a buffer section. You should take every second sample from the buffer.

You can use an extension methods like that:

public static class GetChannelExtension
{
    public static IEnumerable<float> GetChannel(this IEnumerable<float> aData, int aMaxChannels, int aChannelIndex)
    {
        var e = aData.GetEnumerator();
        while(true)
        {
            for(int i = 0; i < aMaxChannels; i++)
            {
                if (!e.MoveNext())
                    yield break;
                if (i == aChannelIndex)
                    yield return e.Current;
            }
        }
    }
}

This allows you to take every “Nth” sample. So for a stereo track You could do this:

float[] samples;

float[] channel1 = samples.GetChannel(2,0).ToArray(); // Returns indices 0,2,4,6,8,10, ...
float[] channel2 = samples.GetChannel(2,1).ToArray(); // Returns indices 1,3,5,7,9,11, ...

So “2” is the channel count. For a mono track(when passing channel count 1) channel1 would contain all samples and channel2 would be an empty array.

And again to avoid passing an index out of bounds you should use

while(sampleIdx + sampleSize < clip.samples)

instead of

while(sampleIdx + sampleSize < maxSamples)

So just keep in mind that “samples” comes in pack of two for a stereo clip and the sample index indicates a pair of samples.