2012-03-10 3 views
2

В настоящее время я пытаюсь воспроизвести функцию getSpectrum функции звуковой библиотеки FMOD. Эта функция считывает данные PCM текущего воспроизводящего буфера, применяет окно к этим данным и применяет FFT для получения спектра.FFT - Применение окна на данных PCM

Он возвращает массив с плавающей точкой, где каждый поплавок находится между 0 и 1 дБ (10.0f * (float)log10(val) * 2.0f).

Я не уверен, что я делаю то, что я должен сделать, так что я объясню:

Во-первых, я получаю данные PCM в байтах буфера 4096, в соответствии с документацией, данные ИКМ состоящий из выборок, которые представляют собой левую-правую пару данных.

data

В моем случае я работаю с образцами 16bit, как на картинке выше. Так что, если я хочу работать только с левым каналом, я сохраняю левые данные PCM в коротком массиве делает:

short *data = malloc(4096); 
FMOD_Sound_ReadData(sound, (void *)data, 4096, &read); 

Таким образом, если образец = 4 байта, у меня есть 1024 выборки, т.е. 1024 шорт, представляющих левые канал и 1024 шортов, представляющих правый канал.

Для выполнения БПФА, мне нужно иметь буи и применить окно (Ханнинг) на моих данных:

float hanningWindow(short in, size_t i, size_t s) 
{ 
    return in*0.5f*(1.0f-cos(2.0f*M_PI*(float)(i)/(float)(s-1.0f))); 
} 

Уф in является входом, i позиции в массиве и s размер массива (1024).

Чтобы получить только левый канал:

float *input = malloc(1024*sizeof(float)); 
for (i = 0; i < 1024; i++) 
    input[i] = hanningWindow(data[i*2], i, 1024); 

Затем я выполняю FFT благодаря kiss_fft (от реального к сложному). Я получаю kiss_fft_cpx *ouput (массив) комплекса размером 1024/2 + 1 = 513.

рассчитать амплитуду каждой частоты с:

kiss_fft_cpx c = output[i]; 
float   amp = sqrt(c.r*c.r + c.i*c.i); 

стоимость в дБ:

amp = 10.0f * (float)log10(amp) * 2.0f; 

amp не находится между 0 и 1. Я не знаю, где я должен нормализовать свои данные (по данным PCM или в конце). Также я не уверен, как я применяю свое окно к данным PCM.

Вот результат, который я получаю от песни 0 до 20 кГц по сравнению с результатом функции getSpectrum. (Для прямоугольного окна)

results

   My Result       getSpectrum Result 

Как я могу достичь того же результата?

+0

На скорости ноты, вы должны действительно хранить коэффициенты Hann окна, а не вычисляя их аккуратные каждый время. –

+0

Не нужно брать sqrt. Примечание: 20 * log10 (sqrt (x)) == 10 * log10 (x) –

ответ

2

Вы немного запутались в масштабах журнала (дБ) - вы не получаете диапазон 0 - 1 дБ, вы получаете диапазон обычно 96 дБ для 16-битного звука, где верхний и нижний концы несколько произвольных, например От 0 до -96 дБ или от 96 дБ до 0 дБ или любого другого диапазона, который вам нравится, в зависимости от различных факторов. Вам, вероятно, просто нужно сдвинуть и масштабировать график ваших спектрограмм с помощью подходящего смещения и коэффициента для учета этого.

(Примечание: диапазон 96 дБ происходит от формулы 20 * log10(2^16), где 16 является числом бит.)

+0

Спасибо за ваш ответ, но как ни странно, при применении '20 * log10 (amp)' Я получаю значения до 120. Это может быть из-за (плавающее) литье, которое я делаю, но не уверен в этом. – Lowip

+0

Это действительно только * диапазон *, который имеет значение - дБ является отношением относительно некоторой условной ссылки 0 дБ - вам просто нужно посмотреть на значения min/max, которые вы получаете, и сдвиг/масштаб соответственно, чтобы получить разумный диапазон интенсивности на вашей спектрограмме. –

+0

Окно Hann выше умножается на среднее значение .5. Также максимальное значение подписанных 16-битных данных составляет 2^15-1, а не 2^16. Отпирание -6 дБ для каждого из этих половин шкалы устанавливает пик дБ при 84 дБ –