C言語 のこぎり波をつくる

思い出したようにC言語のプログラムメモを再開。サイン波の合成で検索して来る人が多いということと、子供がプログラムで音を作り始めたというところが理由。とりあえずシンセサイザーの基本となるような波形をフーリエ変換の考えでプログラミングしてみるところから再スタート。

のこぎり波

波形がのこぎりのような形になっているため、そう呼ばれている特徴的な波形。


生成方法

音はサイン波に分解できるというフーリエの理論だが、ここでは逆のサイン波を合成することで、のこぎり波を生成している。 またフーリエ変換では数学的に無限大の数のサイン波を合成するのだが、実際には適当な数で打ち切って処理している。もしくはナイキスト周波数までやれば、デジタル処理としては完璧。 のこりぎ波にするには、整数倍のサイン波を合成していくのだが、振幅は倍音と同じ数で割って、小さくしていくところがポイント。これだけで、のこぎり波になっていく。 他にものこぎり波の生成方法はいくらでもあるが、まずはこのような理論的にベーシックなところを確認しておきたい。

理想的な、のこぎり波形は耳に痛いのだが、ここで作るような合成数が少ない波形は角が取れて聴きやすい。

サイン波の合成で、のこぎり波をつくる

/* Sawtooth wave
 * 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 a = 0.4; /* Aの値 初期振幅 */
  float note = 440;
  float step = 2 * M_PI / samplingfreq;/* 点間のステップ */
  int i;
  int j;

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

  /* SAW 整数倍sinの合成(30回) メモリ書き込み */
  for(i=1; i<=30; i++){
   for(j=0; j<fileSize; j++){
        *(pbuff+j) += a/i * sin(i * j * step * note);
   } 
  }
  /* ファイルへ書き込み */
  fwrite(pbuff, sizeof(float), fileSize, fpw);
  /* ファイル閉じる */
  fclose(fpw);
  /* メモリ解放 */
  free(pbuff);
  return 0;
}

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

30回重ねたのこぎり波の音

下は合成回数を1から5回までの、のこぎり波。はじめの1回目はサイン波だけなので合成になっていない。2回目以降からのこぎり波に変わっていくのが分かると思う。



C言語 ANSI C89 GCC 目次