音楽をプログラム上で作成して、WAVファイルにして聞く方法を考えたいと思います。
前回は、概要を書きました。
そして、最後にプログラムを書きました。
今回は、そのプログラムの説明を書きたいと思います。
■プログラム
プログラムは、こうでした(書き忘れました。言語は、Cです)。
#include <math.h>
#include <stdio.h>
/* サンプリング周波数 */
#define SEC 44000
/* 音階 */
#define D 1.05946309
/* 音量基準値 */
#define VOL_VAL 15000
void wave(int i, double hz, double vol, double pos,unsigned short a[2])
{
double x = sin(i*2*3.1415926*hz/SEC);
a[0] += (int)(vol*pos*x); a[1] += (int)(vol*(1-pos)*x);
}
void main()
{
int i;
double hz;
unsigned short a[2];
for(i = 0; i < 10*SEC; ++i)
{ /* 10秒間 */
a[0] = a[1] = VOL_VAL; /* 出力配列の初期化 */
hz = 440;
wave(i, hz, 2000, 0.5,a);
fwrite(a, sizeof(a), 1, stdout); /* 出力 */
}
}
(< > #は、本当は半角)
■説明
音波は、こんなかんじです。
プログラムのVOL_VALっていうのが、図の15000のこと。
つまり、真ん中の基準の線です。
ここに対して、数値が上下して、波を作ります。
上下の幅が振幅となります。図で2000となっていますが、これが
wave(i, hz, 2000, 0.5,a);
の2000です。振幅は音の大きさを示します。
横軸は、時間の進行具合です。
1秒間に440回、この振幅を行うと440Hzとなります。
wave(i, hz, 2000, 0.5,a);
のhzがこれにあたります。0.5というのは、左右のバランスです。
そして、今回1秒間に44000回サンプリングを行います。
それがSECです。
サンプリング値を、aに設定して(左右)それを、書き出すことで、
PCMファイルになります。
■waveの中
問題は、Waveの中です。
double x = sin(i*2*3.1415926*hz/SEC);
で、sinは、上記の振幅をもとめているのだなということで、判ると思います。
問題は、i*2*3.1415926*hz/SECです。xの横軸をもとめているのですが・・
ということなんです。
つまり、440Hz=440個なんですけど、1個が2π分なので、
1秒間に440*2π分進みます(周波数*2π分すすみます)
一方、サンプリングは1秒間に44000回行います。
iは、サンプリング回数をしめします。このときのx軸の値は
44000:i=周波数*2π:x
よってx=i*周波数*2π/44000
(44000=SEC)
ということになります。
なぜ、aが=でなく+=なのかというと、これ、音を重ね合わせることが
できるようにするためです(つまり、和音も出せる)
実は、このプログラム、問題があって、440だときれいな音なのですが、
割り切れない音にすると、雑音が乗ります。変換しないこともあります。
次回は、eac3toについての説明です。