0

I'm writing a small program that use SDL and KissFFT that should open a wave file, play the file and find the magnitude and dB for each channel of the current sample buffer so I would visually display Left and Right channels on screen.

So far I have opened and played the file and wrote a small function that will input current sample buffer and calculate the magnitude and dB of the provided buffer.

I'm very new at signal processing and FFT but the basic concept should be to get the buffer, allocate the arrays IN/OUT. Fill the IN array with samples and calculate the FFT and store the output in OUT.

But from what I understand the OUT is an array of frequencies ( a lot of them ). So I would now like to find the magnitude and dB for left and right channel based on those.

This is my code for now


void audio_callback(void *userdata, Uint8 *stream, int len) 
{
 if (audio_len ==0)
     return;

SDL_memset(stream, 0, len);


len = ( len > audio_len ? audio_len : len );   
SDL_memcpy (stream, ptr_audio_buffer, len);                 

calc_loudness(ptr_audio_buffer, len);  // 8192/2 = 4096 samples

ptr_audio_buffer += len;
audio_len -= len;   
}


void calc_loudness(uint8_t *buff, int len)
{
    int nfft = len;
    double magnitude = 0;
    kiss_fft_cfg cfg;
    kiss_fft_cpx *cx_in = new kiss_fft_cpx[len];
    kiss_fft_cpx *cx_out = new kiss_fft_cpx[len];
    int16_t val = NULL;

    cfg = kiss_fft_alloc(nfft, 0, 0, 0);

    for (int i = 0;i<len;i+=2) // 4096 samples
        {
         decode_signed16(&buff[i], &val);
         cx_in[i].r = (float)val / 32768.0;  // I have to do this because values get wild. Why?
         cx_in[i].i = 0.0;
        }

    kiss_fft(cfg, cx_in, cx_out);

    int position = len/2-1;  // last sample
    magnitude = sqrt(pow(cx_out[position].r, 2) + pow(cx_out[position].i, 2));
    double dB = 10 * log10(pow(cx_out[position].r, 2) + pow(cx_out[position].i, 2));

    printf("magnitude: %9.4f \t dB: %9.4f\n", magnitude,dB);

    // ...
    // free memory.
}

At this point I have this arbitrary values that kind of look correct when displayed with fill_rect. But this only gets me one value. And I'm pretty sure I messed up a lot of things here.

How can I separate these values to 2 channels? (should I calculate fft for each channel separately?).

genpfault
  • 51,148
  • 11
  • 85
  • 139
Milo
  • 51
  • 5
  • 1
    lookup nyquist limit ...and to calc magnitude you need to also divide by number_of_samples – Scott Stensland Jun 09 '20 at 11:07
  • So like this? `magnitude = sqrt(pow(cx_out[position].r, 2) + pow(cx_out[position].i, 2)) / len/2;` This gives me very small values in 0.00xx range. – Milo Jun 09 '20 at 11:26
  • yes or can be written `magnitude = 2 * (sqrt(pow(cx_out[position].r, 2) + pow(cx_out[position].i, 2))) / len` however when iterating across output of fft result set only loop `from 0 to < nyquist_limit` where `nyquist_limit = number_of_samples / 2` for a nice full detail yet digestible video see https://www.youtube.com/watch?v=mkGsMWi_j4Q I strongly suggest you run your code using that toy input time series – Scott Stensland Jun 09 '20 at 13:47
  • Thanks Scott. I will try these tomorrow. So in short I can get the amplitude by just using this formula on the last position on the FFT output (nyquist limit) and then calculate dB as I've been doing in my code. So final question would be to get the output of left and right channel I should just do them separately? – Milo Jun 09 '20 at 14:48
  • 1
    regarding `fft on two channel` take a look at https://stackoverflow.com/questions/14477454/apply-fft-to-a-both-channels-of-a-stereo-signal-separately – Scott Stensland Jun 09 '20 at 17:08
  • I think I'll just process each channel separately. BTW is there a way to determine which channel is which? And what about when I have 4 or more channels? – Milo Jun 10 '20 at 08:08

1 Answers1

0

It seems that although loudness can be calculated using the FFT, there is a simpler way to do it. FFT as I understand it now, will give us the range of separate frequencies. Like disambiguation of the signal.

See here:

How can I calculate audio dB level?

Milo
  • 51
  • 5