2012/07/08

C言語 サイン波をつくる

任意のサイン波を作って、それをwavファイルとして保存するプログラム。子ども向けの学習サンプルとして作ってみた。下の例ではサイン波の足し算をしているが、掛け算などすることで、フーリエ変換の学習にもなる。下記のプログラムで作ったwavファイルはヘッダを含まないので、Audacityなどの波形編集ソフトでRawデータとして読み込む必要がある。サンプルフォーマット(音量の分解能)は32bit float。

サイン波の合成

#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 step = 2 * M_PI / samplingfreq;/* 点間のステップ */
  int i;

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

  /* データ作成 & メモリに書き込み */
  for(i=0; i<fileSize; i++){
    *(pbuff+i) = 
      /* 例 0.3は振幅 440は周波数Hz */
      (0.3 * sin(i * step * 440))+ 
      (0.2 * sin(i * step * 880))+
      (0.2 * sin(i * step * 1760));
  } 

  /* ファイルへ書き込み */
  fwrite(pbuff, sizeof(float), fileSize, fpw);
  /* ファイル閉じる */
  fclose(fpw);
  /* メモリ解放 */
  free(pbuff);
  return 0;
}
プログラムは、新規ファイルを用意して、サンプル数と波形の長さからメモリを確保。for文を使ってサイン波を作り、1点、1点メモリに書き込んでいく。その後ファイルにメモリの内容をコピーして終了。
上記を実行すると、32bitF_raw.wavというファイルが同じディレクトリに作られる。これをAudacityで読み込んで表示させてみた。サイン波の合成波形になっているのが確認できる。

サイン波の掛け算

上記プログラムのfor文のところだけを変更。
  for(i=0; i<fileSize; i++){
      *(pbuff+i) = (0.5 * sin(i * step * 440)) * (1.0 * sin(i * step * 440));
  }
下は同じ周波数のサイン波を掛けた場合の例。積分して0にならない波形はフーリエ変換の基本となる部分。

C言語 ANSI C89 GCC 目次