• Products
  • Solutions
  • Made with Unity
  • Learning
  • Support & Services
  • Community
  • Asset Store
  • Get Unity

UNITY ACCOUNT

You need a Unity Account to shop in the Online and Asset Stores, participate in the Unity Community and manage your license portfolio. Login Create account
  • Blog
  • Forums
  • Answers
  • Evangelists
  • User Groups
  • Beta Program
  • Advisory Panel

Navigation

  • Home
  • Products
  • Solutions
  • Made with Unity
  • Learning
  • Support & Services
  • Community
    • Blog
    • Forums
    • Answers
    • Evangelists
    • User Groups
    • Beta Program
    • Advisory Panel

Unity account

You need a Unity Account to shop in the Online and Asset Stores, participate in the Unity Community and manage your license portfolio. Login Create account

Language

  • Chinese
  • Spanish
  • Japanese
  • Korean
  • Portuguese
  • Ask a question
  • Spaces
    • Default
    • Help Room
    • META
    • Moderators
    • Topics
    • Questions
    • Users
    • Badges
  • Home /
avatar image
5
Question by Kokujou · May 26, 2015 at 01:09 PM · c#unity 5audiodsp

How to do a FFT in Unity?

it's a very simple thing i want: i want to get the spectrum of my audio file without playing it. i want to give an interval of lets say 100ms and get the spectrum of this 100ms for every part of the song without playing it! in short i want to have a GetSpectrumData Function without the "must play" limitation. i want to analyze the whole audio in a short time before i play it!

can't be too difficult right? well i searched hours for a solution - nothing. maybe you guys can help me because i'm completely desperated!

Comment
Add comment · Show 7
10 |3000 characters needed characters left characters exceeded
▼
  • Viewable by all users
  • Viewable by moderators
  • Viewable by moderators and the original poster
  • Advanced visibility
Viewable by all users
avatar image Kokujou · May 26, 2015 at 10:10 PM 0
Share

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!

avatar image AlucardJay · May 26, 2015 at 10:18 PM 0
Share

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 );
avatar image Kokujou · May 26, 2015 at 10:47 PM 0
Share

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 $$anonymous$$ute 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...

avatar image Croug · Dec 05, 2015 at 02:11 AM 0
Share

This is exactly the thing I'm looking for did you ever get an answer?

avatar image Kokujou · Dec 05, 2015 at 07:25 AM 0
Share

well guess... i finally looked for some ready fft source code and put it into my code without understanding it. well... it worked ^_^

avatar image Croug Kokujou · Dec 05, 2015 at 10:10 PM 0
Share

think you could send me the code? drop it in pastebin or something

avatar image AkamiT Kokujou · Feb 04, 2017 at 12:55 AM 0
Share

Hello, now I'm searching for the same solution, Could you please send us the code?

3 Replies

· Add your reply
  • Sort: 
avatar image
8

Answer by Bunny83 · Feb 23, 2017 at 02:49 AM

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. As i mentioned in the info header i basically implemented Paul Bourke's version 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 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, Ex2, Ex3. 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. 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 (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.

Comment
Add comment · Show 2 · Share
10 |3000 characters needed characters left characters exceeded
▼
  • Viewable by all users
  • Viewable by moderators
  • Viewable by moderators and the original poster
  • Advanced visibility
Viewable by all users
avatar image Deutschland1000 · Aug 04, 2020 at 09:32 PM 0
Share

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 :)

avatar image moonlock · 3 days ago 0
Share

Thank you very much for taking the time to reply in such depth and sharing code. Immensely helpful.

avatar image
3

Answer by Ryan-Lintott · Jul 20, 2016 at 02:23 PM

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")

Comment
Add comment · Share
10 |3000 characters needed characters left characters exceeded
▼
  • Viewable by all users
  • Viewable by moderators
  • Viewable by moderators and the original poster
  • Advanced visibility
Viewable by all users
avatar image
0

Answer by drudiverse · Oct 01, 2019 at 08:13 AM

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 higher res: alt text 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


bunny-83-fft.jpg (233.8 kB)
bunny-fft-birdsong.jpg (136.6 kB)
Comment
Add comment · Share
10 |3000 characters needed characters left characters exceeded
▼
  • Viewable by all users
  • Viewable by moderators
  • Viewable by moderators and the original poster
  • Advanced visibility
Viewable by all users

Your answer

Hint: You can notify a user about this post by typing @username

Up to 2 attachments (including images) can be used with a maximum of 524.3 kB each and 1.0 MB total.

Follow this Question

Answers Answers and Comments

29 People are following this question.

avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image

Related Questions

Unity3d game to send two different audio to two output devices separately 0 Answers

Passing audio information from unity to third-party 0 Answers

Multiple Cars not working 1 Answer

Distribute terrain in zones 3 Answers

Is it possible to access the speaker in the DualShock 4 controller without the PS4 kit? 1 Answer


Enterprise
Social Q&A

Social
Subscribe on YouTube social-youtube Follow on LinkedIn social-linkedin Follow on Twitter social-twitter Follow on Facebook social-facebook Follow on Instagram social-instagram

Footer

  • Purchase
    • Products
    • Subscription
    • Asset Store
    • Unity Gear
    • Resellers
  • Education
    • Students
    • Educators
    • Certification
    • Learn
    • Center of Excellence
  • Download
    • Unity
    • Beta Program
  • Unity Labs
    • Labs
    • Publications
  • Resources
    • Learn platform
    • Community
    • Documentation
    • Unity QA
    • FAQ
    • Services Status
    • Connect
  • About Unity
    • About Us
    • Blog
    • Events
    • Careers
    • Contact
    • Press
    • Partners
    • Affiliates
    • Security
Copyright © 2020 Unity Technologies
  • Legal
  • Privacy Policy
  • Cookies
  • Do Not Sell My Personal Information
  • Cookies Settings
"Unity", Unity logos, and other Unity trademarks are trademarks or registered trademarks of Unity Technologies or its affiliates in the U.S. and elsewhere (more info here). Other names or brands are trademarks of their respective owners.
  • Anonymous
  • Sign in
  • Create
  • Ask a question
  • Spaces
  • Default
  • Help Room
  • META
  • Moderators
  • Explore
  • Topics
  • Questions
  • Users
  • Badges