2

getSpectrum現在、FMODオーディオライブラリの機能を再現しようとしています。この関数は、現在再生中のバッファの PCM データを読み取り、このデータにウィンドウを適用し、FFT を適用してスペクトルを取得します。

各 float が 0 ~ 1 dB の float の配列を返します ( 10.0f * ( float)log10(val) * 2.0f)。

自分が何をすべきかよくわからないので、説明します。

最初に、4096 バイトのバッファーで PCM データを取得します。ドキュメントによると、PCM データは左右のデータのペアであるサンプルで構成されています。

データ

私の場合、上の画像のように 16 ビットのサンプルを使用しています。したがって、左チャンネルのみで作業したい場合は、左の PCM データを次のようにして短い配列に保存します。

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

したがって、サンプル = 4 バイトの場合、1024 個のサンプルがあります。つまり、左チャネルを表す 1024 ショートと右チャネルを表す 1024 ショートです。

FFT を実行するには、float 配列を用意し、データにウィンドウ (ハニング) を適用する必要があります。

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)));
}

wewinは入力、iは配列内の位置、および配列sのサイズ (1024) です。

左チャンネルのみを取得するには:

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

次に、kiss_fft のおかげで 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);

dB で計算します。

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

ampは 0 と 1 の間ではありません。どこでデータを正規化する必要があるかわかりません (PCM データ上または最後)。また、PCM データにウィンドウを適用する方法もわかりません。

これは、getSpectrum 関数の結果と比較して、0 ~ 20kHz の曲から取得した結果です。(長方形の窓の場合)

結果

             My Result                         getSpectrum Result

どうすれば同じ結果を得ることができますか?

4

1 に答える 1

2

ログ (dB) スケールについて少し混乱しています - 0 から 1 dB の範囲は得られません。通常、16 ビット オーディオでは 96 dB の範囲が得られます。上限と下限は多少任意です。たとえば、さまざまな要因に応じて、0 ~ -96 dB、96 dB ~ 0 dB、またはその他の任意の範囲。これを考慮して、スペクトログラムのプロットを適切なオフセットと係数でシフトおよびスケーリングする必要があるだけです。

(注: 96 dB の範囲は20 * log10(2^16)、16 がビット数である公式から得られます。)

于 2012-03-10T11:25:22.863 に答える