Comments and answers for "How to do a FFT in Unity?"
http://answers.unity.com/questions/974565/how-to-do-a-fft-in-unity.html
The latest comments and answers for the question "How to do a FFT in Unity?"Comment by Deutschland1000 on Deutschland1000's answer
http://answers.unity.com/comments/1758338/view.html
Thanks so much for sharing your code, it helped me a lot!
The only thing that was a bit inconvenient is that it had a big GC impact. For that reason I edited the two FFT functions I needed. This resulted in 0 Byte Garbage.
public static void CalculateFFT(Complex[] samples, float[] result, bool reverse)
{
int power = (int)$$anonymous$$ath.Log(samples.Length, 2);
int count = 1;
for (int i = 0; i < power; i++)
count <<= 1;
int mid = count >> 1; // mid = count / 2;
int j = 0;
for (int i = 0; i < count - 1; i++)
{
if (i < j)
{
var tmp = samples[i];
samples[i] = samples[j];
samples[j] = tmp;
}
int k = mid;
while (k <= j)
{
j -= k;
k >>= 1;
}
j += k;
}
Complex r = new Complex(-1, 0);
int l2 = 1;
for (int l = 0; l < power; l++)
{
int l1 = l2;
l2 <<= 1;
Complex r2 = new Complex(1, 0);
for (int n = 0; n < l1; n++)
{
for (int i = n; i < count; i += l2)
{
int i1 = i + l1;
Complex tmp = r2 * samples[i1];
samples[i1] = samples[i] - tmp;
samples[i] += tmp;
}
r2 = r2 * r;
}
r.img = $$anonymous$$ath.Sqrt((1d - r.real) / 2d);
if (!reverse)
r.img = -r.img;
r.real = $$anonymous$$ath.Sqrt((1d + r.real) / 2d);
}
if (!reverse)
{
double scale = 1d / count;
for (int i = 0; i < count; i++)
samples[i] *= scale;
for (int i = 0; i < samples.Length / 2; i++)
{
result[i] = (float)samples[i].magnitude;
}
}
else
{
for (int i = 0; i < samples.Length / 2; i++)
{
result[i] = (float)($$anonymous$$ath.Sign(samples[i].real) * samples[i].magnitude);
}
}
}
public static void Float2Complex(float[] input, Complex[] result)
{
for (int i = 0; i < input.Length; i++)
{
result[i] = new Complex(input[i], 0);
}
}
It also resulted in better performance, so I hope this helps someone too :)Tue, 04 Aug 2020 21:32:09 GMTDeutschland1000Answer by drudiverse
http://answers.unity.com/answers/1668955/view.html
Adding to Bunny's awesome code, here's my findings... It may be lacking windows, i.e. rectangular/blackman-harris etc etc. The default window seems to be giving major sound-blurring on the frequency axis, translated by long lines where there is some chirp noise and the algo is not totally sure where the noise is. I know there shouldn't be so many lines as this, will have to work to figure out what it is:
![alt text][1]
higher res:
![alt text][2]
Okay... I have researched the same birdsong from other FFT's, it has frequency axis lines also. these are noise chirps, although I am working with filter banks at the moment which gives me 100 times higher resolution than FFT, so i will use the FFT to optimize the high res scan as a 2nd sweep. nice...
https://www.researchgate.net/profile/Valentin_Amrhein/publication/233800034/figure/fig2/AS:300161474547725@1448575480959/Examples-of-nightingale-song-types-containing-elaborate-trills-of-different-repetition.png
[1]: /storage/temp/146887-bunny-83-fft.jpg
[2]: /storage/temp/146888-bunny-fft-birdsong.jpgTue, 01 Oct 2019 08:13:49 GMTdrudiverseAnswer by Bunny83
http://answers.unity.com/answers/1317336/view.html
I just implemented the FFT algorithm myself in C#. In addition i first created a Complex number struct which is used by the FFT function. You can find it **[here on my pastebin][1]**. As i mentioned in the info header i basically implemented [Paul Bourke's version][2] but instead of using two arrays i used one array of my Complex type. This method calculates the FFT in-place. So it transforms the given sample array (which need to have a length that is a power of two) from the time domain into the frequency domain or the other way round.
A few important notes:
- As already mentiond the array always need to have a size that is a power of two (i.e. 2, 4, 8, 16, 32, 64, 128, 256, 512, 1024, 2048, 4096, 8192, 16384, 32768, 65536, ...)
- If you have your samples as a float array you need to copy them into a Complex array first. Keep in mind that you can reuse the array.
- The transformed frequencies reach from 0 up to the sample frequency. However it makes no sense to look at frequencies that are higher than the [Nyquist-frequency][3] which is half the sampling frequency. So the second half of the FFT can be ignored. The usual way is to only take the first half and multiply the results by two to compensate the power levels.
- Based on the last point it should be clear that if you want for example 1024 frequency bins / bands you need 2048 samples.
- If you want to use the FFT class as a filter you should use the whole FFT so when calculating the inverse FFT you get the exact same samples back that you originally feed in. Here are three examples [Ex1][4], [Ex2][5], [Ex3][6]. Green is the input signal, red the FFT and yellow the inverse FFT. Those examples have been made from 65k samples. The FFT of 65k (1<<16) samples took around 60ms on my PC. 4k(1<<12) samples took about 3ms
- I haven't implemented any windowing functions. So the results are like you used a "rectangle window". If you want / need one you just need to preprocess your data by your desired windowing function.
I've made a quick test to compare Unity's "GetSpectrumData" with my own implementation. The result is pretty much the same:
using B83.MathHelpers;
// [ ... ]
float[] spec = new float[1024];
float[] tmp = new float[2048];
Complex[] spec2 = new Complex[2048];
void Update()
{
// Unity's FFT function
AudioListener.GetSpectrumData(spec, 0, FFTWindow.Rectangular);
for (int i = 0; i < spec.Length; i++)
{
Debug.DrawLine(new Vector3(i, 0), new Vector3(i, spec[i]), Color.cyan);
}
// My FFT based on the output samples.
AudioListener.GetOutputData(tmp, 0);
// copy the output data into the complex array
for(int i = 0; i < tmp.Length; i++)
{
spec2[i] = new Complex(tmp[i],0);
}
// calculate the FFT
FFT.CalculateFFT(spec2, false);
for (int i = 0; i < spec2.Length/2; i++) // plot only the first half
{
// multiply the magnitude of each value by 2
Debug.DrawLine(new Vector3(i, 4), new Vector3(i, 4+(float)spec2[i].magnitude*2), Color.white);
}
}
Of course instead of feeding the FFT function the samples from "AudioListener.GetOutputData" you can also feed it chunks of samples from an audio file. Since the FFT function is static and don't use any global variables / state it can be easily multithreaded if needed. Just ensure that each FFT method / thread has it's own sample array it's working on.
If you're interested in how the FFT (or DFT in general) works i recommend [this video][7]. Even though the guy messes up a lot of his math and equations, most are fixed by annotations. What's great about that presentation is the visual representation of what's happening. If you want to make sense of the code i recommend to first look at the [DFT implementation][8] (Appendix A.). To make sense of the FFT code you should be familiar with complex numbers. Though you don't have to understand it to use it.
[1]: http://pastebin.com/LiTws7ND
[2]: http://paulbourke.net/miscellaneous/dft/
[3]: https://en.wikipedia.org/wiki/Nyquist_frequency
[4]: https://www.dropbox.com/s/19iaxgz3rw8oaji/FFT01.png?raw=1
[5]: https://www.dropbox.com/s/zuvjztfimojg3jd/FFT02.png?raw=1
[6]: https://www.dropbox.com/s/q1wizo1wymd52rz/FFT03.png?raw=1
[7]: https://www.youtube.com/watch?v=FjmwwDHT98c
[8]: http://paulbourke.net/miscellaneous/dft/Thu, 23 Feb 2017 02:49:34 GMTBunny83Comment by AkamiT on AkamiT's comment
http://answers.unity.com/comments/1308516/view.html
Hello, now I'm searching for the same solution, Could you please send us the code?Sat, 04 Feb 2017 00:55:21 GMTAkamiTAnswer by Ryan-Lintott
http://answers.unity.com/answers/1218667/view.html
I don't know how to make your own FFT but if you want a hack for using **GetSpectrumData** without hearing the audio you can do this:
1) Go to the **Audio Mixer** and add a new group (I called mine "input")
2) Click on the Input group and add the effect **Duck Volume**
3) In **Duck Volume** set **Make-up Gain** all the way to the left and **Ratio** all the way to the right. Make sure **Duck Volume** is at the bottom of the stack. This effectively mutes the channel after you've read the spectrum data.
4) On your **Audio Source**, set the **Output** to your new group in the **Audio Mixer** (in my case, "input")Wed, 20 Jul 2016 14:23:00 GMTRyan-LintottComment by Croug on Croug's comment
http://answers.unity.com/comments/1108079/view.html
think you could send me the code? drop it in pastebin or somethingSat, 05 Dec 2015 22:10:20 GMTCrougComment by Kokujou
http://answers.unity.com/comments/1107880/view.html
well guess... i finally looked for some ready fft source code and put it into my code without understanding it.
well... it worked ^_^Sat, 05 Dec 2015 07:25:22 GMTKokujouComment by Croug
http://answers.unity.com/comments/1107838/view.html
This is exactly the thing I'm looking for did you ever get an answer?Sat, 05 Dec 2015 02:11:55 GMTCrougComment by Kokujou
http://answers.unity.com/comments/974874/view.html
lets quote my own question
"in short i want to have a GetSpectrumData Function without the "must play" limitation"
getspectrumdata requires the song to play and just gives exactly THIS moment of the song which is playing.
to analyze the whole audio i'd have to play the whole audio track before my game begins what'd make a 5 minute waiting time. this is inefficient.
i mean if i'd at least have the source code of this function.
what i'm looking for is some kind of function where i can input a float array for the actual samples and another float array that gives the output of the FFT. i tried the NAudio Library but i don't even know what unit they are using for their FFT.
FFTW also uses NAudio. well at least the C# .Net Layer.
i found another one on the net but the output wasn't correct too.
so what to do now?
PS: the other one i found is this: http://www.lomont.org/Software/$$anonymous$$isc/FFT/LomontFFT.html but the output wasn't correct. i don't think the -1f to 1f values are correct for this one...Tue, 26 May 2015 22:47:46 GMTKokujouComment by AlucardJay
http://answers.unity.com/comments/974857/view.html
http://docs.unity3d.com/ScriptReference/AudioSource.GetSpectrumData.html
http://docs.unity3d.com/ScriptReference/FFTWindow.html
float[] data = new float[ 8192 ];
audioSource.GetSpectrumData( data, 0, FFTWindow.BlackmanHarris );Tue, 26 May 2015 22:18:45 GMTAlucardJayComment by Kokujou
http://answers.unity.com/comments/974852/view.html
i never asked how to DO a FFT. i asked how to use it or what for but never how to do it.
its not my fault if nobody answers i'm desperated and not even my prof can really help me so tell me what i should to this projects is being evaluated!Tue, 26 May 2015 22:10:38 GMTKokujou