0

I'm currently working on an audio visualizer running on a 64x64 LED matrix, and some tests showed that the Pi1 is totally capable of doing that. I'm receiving raw PCM audio data using PortAudio, and I now want to show a visualizer having 64 bands out of these raw samples. Following a few suggestions from peterO here in the forums I went ahead with GPU_FFT, but I am not too sure how I can translate the fft calculations to actual renderable frequency bands.

Here's what I have right now:

void CAudio::AudioWorker(CAudio* Instance)
{
     PaError err;

     int fftSize = 8;
     int N = 1 << fftSize;
     int i,j;
     float s;
     float mean, std_deviation;

     while (!Instance->ShouldExitThread)
     {
         // The buffer is filled with the raw PCM input samples
         float* buffer = (float*)malloc(sizeof(float)*FRAMES_PER_BUFFER);
         err = Pa_ReadStream(Instance->AudioStream, buffer, FRAMES_PER_BUFFER);

         if (err == paNoError)
         {
              CDisplay::Get()->Clear();

              // Allocate a raw buffer for the FFT data
              float* fftOut = (float*)malloc(sizeof(float)*64*3);

              Instance->base = Instance->fft->in;

              for (i = 0; i < N; i++)
              {
                  Instance->base[i].re = buffer[i];
                  Instance->base[i].im = 0;
              }

              gpu_fft_execute(Instance->fft);

              Instance->base = Instance->fft->out;

              for (i = 0; i < 64; i++)
              {
                   s = 0.0;

                   int j = (i * SAMPLE_RATE) / N;
                   s += Instance->base[j].re * Instance->base[j].re + Instance->base[j].im * Instance->base[j].im;

                   CDisplay::Get()->SetPixel(i, (int)round(10*log10(s)), Color::RandomColor());
              }

              free(fftOut);
          }

          free(buffer);
     }
 }

I found this implementation for FFT somewhere on the net (and yea, I initialize fft and everything correctly, I was just too lazy to put it here too, I think it's clear :D)

How can I turn the FFT data into frequency bands? And which parameters (log2_N e.g.) do I use for the FFT calculation?

Thanks in advance!

0

IIRC, fft_out is the returned power in frequency bands.
The data is mirrored above n/2 (fft_out[63] == fft_out[0]);

fft_out[0] is the power in n/sample rate (where n is buffer size - 64) 
fft_out[1] is 2n/sample rate 
fft_out[2] 4n/sample rate, etc.  
  • Hey, thanks for the comment. Unfortunately that didn't really help me with how I can render the bars :( – Johnny Verbeek Aug 11 '18 at 9:34
  • For each bin, you draw a rectangle. Width of the rectangle is the width of the drawing surface divided by the number of bins you want to draw. Height of the rectangle is the power of the bin times the height of the drawing surface. What graphics package are you drawing with? – rmustakos Aug 12 '18 at 21:16
  • I'm using it for a LED matrix display running rpi-rgb-led-matrix as it's underlying system. So speaking of "bins", I think I'm having a major understanding problem of what "bins" are. I have 64 columns, so would that mean 64 bins? And in each column I draw rectangle with width=1 (because I have 64 columns) and height = fft_out[i] * 64? – Johnny Verbeek Aug 13 '18 at 21:52
  • So, when you do your FFT, you have to figure out the bins associated with the frequencies that you are interested in. If you have more bins than columns, you want to combine them. If you are sampling at 22kHz, you can FFT bins of 512, 44 times a second. Sum bins 0..3 together, then 4..7, so you are down to 64 bins. Then, yeah, you have 64 columns, or bars. If the output is 0..1, scale it by 64, as you said and turn those LEDs on. With more bins, power per bin will be smaller, so scale and take the log, it matches perception better. You got this! – rmustakos Aug 15 '18 at 7:07

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.