Trying to calculate the magnitude of each channel using KissFFT

285 Views Asked by At

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?).

1

There are 1 best solutions below

0
Milo On

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?