#define _USE_MATH_DEFINES #include #include #include #define LENGTH 512 /* 信号長 ただし,2の整数乗 */ typedef struct { double r; /* 実部 */ double i; /* 虚部 */ } Complex; /* 複素数 */ /* プロトタイプ宣言 */ Complex getComplex(double r, double i); void bit_reversal(Complex *x, int N); void fft(Complex *x, int N, int inverse); void applyWindow(Complex *x, int N); Complex cexptheta(double theta); Complex addComplex(Complex a, Complex b); Complex subComplex(Complex a, Complex b); Complex timeComplex(Complex a, Complex b); Complex divComplexByReal(Complex z, double div); int main() { int N = LENGTH; /* 信号長 */ double amp; /* 振幅 */ int i; int j; double start_sec = 2.454; /* 読み込む音声の開始位置 [秒] */ long fs = 16000; /* 標本化周波数 */ long bytes_per_sample = 2; /* 16bitなので2バイト */ long start_byte = (long)(start_sec * fs * bytes_per_sample); /* 指定時刻の開始位置バイト */ long frame_length = 32; /* フレーム長[msec] */ long frame_period = 10; /* フレーム周期[msec] */ long frame_length_samples = (long)(frame_length * fs / 1000); /* フレーム長[サンプル] */ long frame_period_samples = (long)(frame_period * fs / 1000); /* フレーム周期[サンプル] */ long frame_period_bytes = frame_period_samples * bytes_per_sample; /* フレーム周期[バイト] */ /* 入力信号配列 */ short input[LENGTH]; Complex x[LENGTH]; FILE *fp = fopen ( "j22330.sw", "rb" ); if ( fp == NULL ) { fprintf ( stderr, "File open error (j22330.sw)\n" ); exit ( 1 ); } /* 読み込む位置にファイルポインタを移動 */ fseek(fp, start_byte, SEEK_SET); for() { /* 音声データを読み込み */ if (fread(input, sizeof(short), N, fp) != (size_t)N) { fprintf(stderr, "File read error (j22330.sw)\n"); fclose(fp); exit(1); } /* 音声データを複素数型に変換 */ for(i = 0; i < N; i++) { x[i] = getComplex(input[i], 0); } /* 窓関数の適用 */ applyWindow(x, N); /* FFTの実行 */ fft(x, N, 0); /* 振幅スペクトルの出力 */ for(i = 0; i < N; i++) { amp = sqrt(x[i].r * x[i].r + x[i].i * x[i].i); printf("%f\n", amp); } } fclose(fp); return 0; } /** * @brief 配列の要素をビット逆順に並べ替える * * @param x 信号配列 * @param N 信号長 ただし,2の整数乗 */ void bit_reversal(Complex *x, int N) { int i, j, k; Complex temp; j = 0; for(i = 0; i < N; i++) { if (i < j) { temp = x[i]; x[i] = x[j]; x[j] = temp; } /* 逆方向カウントアップ */ k = N >> 1; while (k <= j && k > 0) { /* もしjのk番目のビットが 1 だったら */ j -= k; /* そのビットを 0 にする */ k >>= 1; /* 次のビットに移る */ } j += k; /* 0 を見つけたら 1 にする */ } } /** * @brief 高速フーリエ変換 * * @param x 入力信号配列 * @param N 信号長 ただし,2の整数乗 * @param inverse 0ならDFT,1ならIDFT */ void fft(Complex *x, int N, int inverse) { bit_reversal(x, N); for (int stage = 1; (1 << stage) <= N; stage++) { int block = 1 << stage; /* 現在のブロックのサイズ */ int block2 = block >> 1; /* ブロックサイズの半分 */ double theta = (inverse ? 2.0 : -2.0) * M_PI / block; Complex wm = cexptheta(theta); /* 基本となる回転子 */ /* 各ブロックの計算 */ for (int k = 0; k < N; k += block) { Complex w = getComplex(1.0, 0); for (int j = 0; j < block2; j++) { /* バタフライ演算の本体 */ Complex u = x[k + j]; /* X_0[k] */ Complex v = timeComplex(w, x[k + j + block2]); /* W^k * X_1[k] */ x[k + j] = addComplex(u, v); x[k + j + block2] = subComplex(u, v); w = timeComplex(w, wm); } } } /* 逆変換の場合、最後に N で割る */ if (inverse) { for (int i = 0; i < N; i++) { x[i] = divComplexByReal(x[i], N); } } } /* 配列にハニング窓を適用 */ void applyWindow(Complex *x, int N) { for (int i = 0; i < N; i++) { double w = 0.5 - 0.5 * cos(2 * M_PI * i / (N - 1)); x[i].r *= w; x[i].i *= w; } } Complex getComplex(double r, double i) { Complex c; c.r = r; c.i = i; return c; } Complex cexptheta(double theta) { return getComplex(cos(theta), sin(theta)); } Complex addComplex(Complex a, Complex b) { return getComplex(a.r + b.r, a.i + b.i); } Complex subComplex(Complex a, Complex b) { return getComplex(a.r - b.r, a.i - b.i); } Complex timeComplex(Complex a, Complex b) { return getComplex(a.r*b.r - a.i*b.i, a.r*b.i+a.i*b.r); } Complex divComplexByReal(Complex z, double div) { return getComplex(z.r / div, z.i / div); }