2014/03/18

C言語 ホワイトノイズをつくる

ホワイトノイズ

すべての周波数を含み、そのすべてが一定の強度を持つ波。これをまじめに計算するとなると、結構厄介な話になる。ここでは1Hzからナイキスト周波数(サンプリング周波数44100Hzであれば、22050Hz)を扱う。また1Hz単位のサイン波を同じ音量にして足していくことで実現してみた。計算が膨大になるため、処理に時間がかかる。ちなみに1秒のホワイトノイズを作るのに4分ぐらいかかっている。速いマシンなら1分以内で処理できるとは思う。またサイン波の初期角度は、ランダム関数を使って2pi以内でばらつかせることでお互いの干渉を防いでいる。

ホワイトノイズ生成プログラム

/* White noise
 * sin波の合成による生成 
 * 32bit float RAW ヘッダなしwaveファイル出力
 */
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
int main(void){
  FILE *fpw;/* 書き込み用ファイルポインタ */
  float *pbuff; /* メモリのデータを指す */
  int samplingfreq = 44100;/* サンプリング周波数 */
  int sec = 10; /* 作成する波形の長さ(秒) */
  int fileSize = samplingfreq * sec; /* ファイルの大きさ */
  float gain = 0.001; /* ひとつの波形の振幅 */
  float step = 2 * M_PI / samplingfreq;/* 点間のステップ */
  float phase;
  int i, j;

  /* 新規ファイル作成 */
  fpw = fopen("white_noise_32bitF_raw.wav", "wb");
  /* 失敗時終了 */
  if (fpw == NULL) exit(EXIT_FAILURE);
  /* メモリを確保して先頭アドレスをpbuffに入れる */
  pbuff = (float*)malloc(sizeof(float) * fileSize);
  /* 失敗時終了 */
  if (pbuff == NULL) exit(EXIT_FAILURE);

  printf("ホワイトノイズ生成中\n");
  /* ホワイトノイズ生成 1Hzからナイキスト周波数まで合成 */
  for(i=1; i<=(samplingfreq/2); i++){
  /* ランダム関数で初期角度をばらつかせる 0~1 * 2pi */
   phase = (double)rand() / RAND_MAX * 2.0 * M_PI;
   for(j=0; j<fileSize; j++){
     *(pbuff+j) += gain * sin(i * j * step + phase);
   } 
  }
  /* ファイルへ書き込み */
  fwrite(pbuff, sizeof(float), fileSize, fpw);
  /* ファイル閉じる */
  fclose(fpw);
  /* メモリ解放 */
  free(pbuff);
  return 0;
}

上記をコンパイルしてから実行すると、white_noise_32bitF_raw.wavというファイルが同じディレクトリに作られる。注意点としてはヘッダのないwaveファイルなので、普通のミュージックプレーヤーでは再生できない。ここではRAWデータ(32bit float, Mono, Little-endian)としてAudacityで読み込んで表示させている。

周波数スペクトルで見ても、まぁまぁ許せる範囲にはなっていると思う。

ホワイトノイズの音。

ちなみに各サイン波の初期角度を常に0にして重ねて行くと以下のようになってしまう。1段目は1~10Hzの10個の合成で、2段目は100個、3段目は22050Hzまでの結果。このようにならないために、初期角度のばらつきは重要。



C言語 ANSI C89 GCC 目次