芸軌社株式会社
RSS 2.0

芸軌社公式ブログ

2012年6月07日(木)15:48(+0900)

鉄道唱歌をC言語+OpenALで演奏してみた

このエントリーをはてなブックマークに追加

前回の日記「C言語で音を出してみた」に続き、今回はC言語+OpenALで鉄道唱歌を演奏してみました。

実はプログラム自体はけっこう前(前回の日記と同じ日か翌日くらい)にほぼ出来上がっていてupしようと思っていました。しかし、「どうせなら動画も作りたい、ついでにGUIも、ついでに、、、」とかいろいろ思ってしまい、最終的に完成する目処が立たなくなってしまったので、とりあえず最低限のプログラムのみでupします。

ということで、とりあえずWindows用のコンパイル済みプログラムを以下に載せます。使い方はREADME.txtをお読みください。

プログラムのソースは以下のとおりです。

#include <stdio.h>
#include <AL/alut.h>
#include <math.h>

#ifdef WIN
#include <windows.h>
#else
#include <time.h>
#endif

#define DMAX 44100
short dat[DMAX][2];

float music[][2] = {
	{1.0, 99},

	{1.5/4,10},{0.5/4,10},{1.5/4,10},{0.5/4,12},
	{1.5/4,14},{0.5/4,14},{1.5/4,14},{0.5/4,12},
	{1.5/4,10},{0.5/4,10},{1.5/4,10},{0.5/4, 7},
	{1.5/2, 5},
	{0.5/2,99},

	{1.5/4, 7},{0.5/4, 7},{1.5/4, 5},{0.5/4, 7},
	{1.5/4,10},{0.5/4,10},{1.5/4,14},{0.5/4,14},
	{1.5/4,12},{0.5/4,12},{1.5/4,10},{0.5/4,12},
	{1.5/2,14},
	{0.5/2,99},

	{1.5/4,17},{0.5/4,17},{1.5/4,17},{0.5/4,17},
	{1.5/4,17},{0.5/4,17},{1.5/4,19},{0.5/4,17},
	{1.5/4,14},{0.5/4,10},{1.5/4,12},{0.5/4,14},
	{1.5/2,12},
	{0.5/2,99},

	{1.5/4,10},{0.5/4,12},{1.5/4,14},{0.5/4,14},
	{1.5/4,12},{0.5/4,12},{1.5/4,17},{0.5/4,17},
	{1.5/4,14},{0.5/4,14},{1.5/4,12},{0.5/4,12},
	{1.5/2,10},
	{0.5/2,99},

	{-1,0},
};

int main(int argc, char *argv[])
{
	int i, j, v, jmax;
	double hz, taw, ttime = 0.0;
	double ntime, otime = -1;
#ifdef WIN
	FILETIME ts;
#else
	struct timespec tp;
#endif
	double w = 2*3.141592/44100;
	ALuint buffer, source;

	/* OpenAL初期化 */
	alutInit(&argc, argv);

	/* 引数から時定数(の逆数)を設定 */
	taw = 1;
#ifdef WIN
	printf("taw=");
	scanf("%lf", &taw);
#else
	if(argv[1] != NULL)
		sscanf(argv[1], "%lf", &taw);
#endif

	for(i=0;music[i][0]>0;i++) {

	/* 音のデータを作る */
	hz = 440*pow(2,(double)music[i][1]/12);
	jmax = 44100*music[i][0]*1.1;
	if(jmax > DMAX) jmax = DMAX;
	for(j=0;j<jmax;j++) {
		v = 0;
		if(music[i][1]<90) v = 100*256
			*(440/(hz-taw/(2*3.141592)))
			*(440/(hz-taw/(2*3.141592)))
			*sin(w*hz*j)
			*pow(2.8182,-taw*j/44100);
		if(v>256*256-1) v = 256*256-1;
		dat[j][0] = v;
		dat[j][1] = v;
	}

	/* 次の音を鳴らすまでの間スリープする */
#ifdef WIN
	GetSystemTimeAsFileTime(&ts);
	ntime = (double)ts.dwHighDateTime*429.4967296
		+ (double)ts.dwLowDateTime*1.0e-7;
#else
	clock_gettime(CLOCK_MONOTONIC, &tp);
	ntime = (double)tp.tv_sec
		+ (double)tp.tv_nsec*1.0e-9;
#endif
	if(otime < 0) {
		otime = ntime;
	}
	ntime -= otime;
	ttime += music[i-1][0];
	ntime = ttime - ntime;
	if(ntime > 0)
	alutSleep(ntime);

	/* 前の音を削除 */
	if(i > 0) {
		alDeleteBuffers(1, &buffer);
		alDeleteSources(1, &source);
	}

	/* 音を鳴らす */
	alGenSources(1, &source);
	alGenBuffers(1, &buffer);
	alBufferData(buffer, AL_FORMAT_STEREO16, dat,
		DMAX*4, 44100);
	alSourcei(source, AL_BUFFER, buffer);
	alSourcePlay(source);

	}

	/* 終了 */
	alDeleteBuffers(1, &buffer);
	alDeleteSources(1, &source);
	alutSleep(2);

}

コンパイルは、OpenALを適切にインストールした後、例えばLinuxでは

cc tshoka.c -lalut

Windowsでは

cc tshoka.c -lalut -lOpenAL32 -DWIN

みたいな感じでできます。WindowsへのOpenALの導入は、MinGWをインストールした上で

のサイト様が参考になります。