prog_sin.c 解説

#include <stdio.h>
#include <math.h>

int
main()
{
	int smp_freq = 8000;
	int smp_cnt, iv;
	double freq = 880;
	double len = 1.0;
	double sec, v;

	smp_cnt = 0;
	do{
		sec = (double)smp_cnt / smp_freq;
		v = sin(2* M_PI * freq * sec);
		iv = 128 + (int)(v * 127);
		putchar(iv);
		smp_cnt++;
	}while(sec < len);
	return 0;
}

/* EOF */


#include <stdio.h>
#include <math.h>

int
main()
{
	int smp_freq = 8000;
	// サンプリング周波数
	// 8000 Hz
	// 1秒間に8000回
	

	int smp_cnt, iv;

	double freq = 880;
	// 鳴らす音の周波数
	// 880 Hz
	// 1秒間に880回(880サイクル)
	

	double len = 1.0;
	// 鳴らす音の長さ
	// 1.0 秒
	

	double sec, v;

	smp_cnt = 0;
	// サンプリング回数
	// 0から順に増加
	// サンプリング・データを1つ出力する毎に +1 していく
	// サンプリング周波数 smp_freq の値まで達すると、1秒分のデータが出力されている
	

	do{
		sec = (double)smp_cnt / smp_freq;
		// サンプリング回数をサンプリング周波数で割って、現在の時刻(秒)を算出
		// 1/周波数 = 周期(秒)
		// 周期は、1回(サイクル)にかかる時間
		// 1 / smp_freq は、サンプリング周期で、サンプリング間隔(秒)
		// smp_cnt * (1 / smp_freq) ととらえると
		// 1回のサンプリングの時間(秒) × サンプリング回数 = サンプリング回数分の時間(秒)
		

		v = sin(2* M_PI * freq * sec);
		// freq = 鳴らす音の周波数
		// SINパターンを1秒間に freq回 繰り返す
		// sec = 現在時刻 (音が鳴り初めてからの経過時間)
		// freq * sec で、音がなり初めてから、SINパターンを何回分繰り返したか
		// パターンの繰り返し回数は、小数で考えて
		// 例えば、880 Hz × 0.01 秒 ならば SINパターン 8.8 回分
		// ここでは、この小数の回数の値を「サイクル」と呼称する
		// sin()関数は入力 0 から 2π でSINパターン1つ分
		// 2 * M_PI * freq * sec は、2π × サイクル
		// sin(2 * M_PI * freq * sec) で 現在の波形の値となる
		

		iv = 128 + (int)(v * 127);
		// v は sin()関数の値 -1.0 〜 +1.0 の範囲をとる
		// 出力するデータ形式は、ビット長 8 bit、符号なし
		// v * 127 で -127.0 〜 +127.0 をとり
		// 128 + (int)(v * 127) で 1 〜 255 の値をとる
		

		putchar(iv);
		// 標準出力に 1つのサンプリング・データを出力
		

		smp_cnt++;
		// データを1つ出力したので、サンプリング回数を +1 して更新
		

	}while(sec < len);
	// 音を鳴らしてからの経過時間 sec(秒)が
	// len(1.0秒) に至るまで、処理を繰り返す
	
	return 0;
}

/* EOF */


prog_chord.c 解説

#include <stdio.h>
#include <math.h>

int
main()
{
	int smp_freq = 8000;
	int smp_cnt, iv, i;
	double freqs[3];
	double len = 1.0;
	double sec, v;

	freqs[0] = 880;
	freqs[1] = freqs[0] * pow(2, 4.0 / 12);
	freqs[2] = freqs[0] * pow(2, 7.0 / 12);

	for(i=0; i<3; i++){
		smp_cnt = 0;
		do{
			sec = (double)smp_cnt / smp_freq;
			v = sin(2 * M_PI * freqs[i] * sec);
			iv = 128 + (int)(v * 127);
			putchar(iv);
			smp_cnt++;
		}while(sec < len);
	}
	
	smp_cnt = 0;
	len = 2;
	do{
		sec = (double)smp_cnt / smp_freq;
		v = 0;
		for(i=0; i<3; i++){
			v += sin(2 * M_PI * freqs[i] * sec);
		}
		v /= 3;
		iv = 128 + (int)(v * 127);
		putchar(iv);
		smp_cnt++;
	}while(sec < len);
	return 0;
}

/* EOF */


#include <stdio.h>
#include <math.h>

int
main()
{
	int smp_freq = 8000;
	int smp_cnt, iv, i;
	double freqs[3];
	double len = 1.0;
	double sec, v;

	
	freqs[0] = 880;
	freqs[1] = freqs[0] * pow(2, 4.0 / 12);
	freqs[2] = freqs[0] * pow(2, 7.0 / 12);
	// A メジャー・コードの3つの周波数
	//   A  880 Hz
	//   C# 880 * pow(2, 4/12) Hz
	//   E  880 * pow(2, 7/12) Hz
	

	
	for(i=0; i<3; i++){
	// まずは、freqs[0], freqs[1], freqs[2] の周波数の音を、
	// 順に1つずつ鳴らしていく
	// for文の中は、 prog_sin.c  と同様で
	// freq の箇所を freqs[i] に置き換えている
	
		smp_cnt = 0;
		do{
			sec = (double)smp_cnt / smp_freq;
			v = sin(2 * M_PI * freqs[i] * sec);
			iv = 128 + (int)(v * 127);
			putchar(iv);
			smp_cnt++;
		}while(sec < len);
	}
	
	smp_cnt = 0;
	
	len = 2;
	// 次に和音として、3つの周波数の音を同時に鳴らす
	// 鳴らす時間は2秒間
	
	do{
		sec = (double)smp_cnt / smp_freq;
		
		v = 0;
		for(i=0; i<3; i++){
			v += sin(2 * M_PI * freqs[i] * sec);
		}
		v /= 3;
		// 前半で個別に鳴らした場合と同様の式だが、
		// 3つの音のそれぞれの波形を足し算し、3で割っている
		// v の値は -1.0 〜 +1.0 の範囲におさまる
		
		iv = 128 + (int)(v * 127);
		putchar(iv);
		smp_cnt++;
	}while(sec < len);
	return 0;
}

/* EOF */


prog_onoff.c 解説

#include <stdio.h>

int
main()
{
	int i, v, c, c1, c2, low, hi;
	char id[5];

	printf("header\n");

	for(i=0; i<4; i++) id[i] = getchar();
	id[i] = '\0';
	printf("id='%s'\n", id);

	v = 0;
	for(i=0; i<4; i++) v = (v << 8) | getchar();
	printf("size=%d\n", v);

	v = 0;
	for(i=0; i<2; i++) v = (v << 8) | getchar();
	printf("format type=%d\n", v);

	v = 0;
	for(i=0; i<2; i++) v = (v << 8) | getchar();
	printf("track num=%d\n", v);

	v = 0;
	for(i=0; i<2; i++) v = (v << 8) | getchar();
	printf("time division=%d (0x%x)\n\n", v, v);


	printf("track\n");

	for(i=0; i<4; i++) id[i] = getchar();
	id[i] = '\0';
	printf("id='%s'\n", id);

	v = 0;
	for(i=0; i<4; i++) v = (v << 8) | getchar();
	printf("size=%d\n", v);

	while(1){
		v = 0;
		do{
			if((c = getchar()) == EOF) break;
			v = (v << 7) | (c & 0x7f);
		}while(c & 0x80);
		if(c == EOF) break;
		printf("delta time=%d\n", v);
		
		c = getchar();
		if(c & 0x80){
			c1 = c;
			hi = (c1 >> 4) & 0xf;
			low = c1 & 0xf;
			c2 = getchar();
		}else{
			c2 = c;
		}

		if(hi == 9 || hi == 8){
			printf("%s ch=%d ", hi == 9 ? "on" : "off", low);
			printf("note=%d ", c2);
			printf("velo=%d\n", getchar());
			continue;
		}

		printf("c1=0x%02x, c2=0x%02x\n", c1, c2);
		break;
	}
	return 0;
}

/* EOF */


#include <stdio.h>

int
main()
{
	int i, v, c, c1, c2, low, hi;
	char id[5];

	printf("header\n");

	for(i=0; i<4; i++) id[i] = getchar();
	id[i] = '\0';
	printf("id='%s'\n", id);
	
	// ヘッダのID 4バイトを読み込み、文字列として表示
	// "MThd" を期待
	

	v = 0;
	for(i=0; i<4; i++) v = (v << 8) | getchar();
	printf("size=%d\n", v);
	
	// ヘッダのサイズ
	// ビッグエンディアンの4バイト整数を読み込み表示
	// 6 を期待
	

	v = 0;
	for(i=0; i<2; i++) v = (v << 8) | getchar();
	printf("format type=%d\n", v);
	
	// ヘッダのフォーマット・タイプ
	// ビッグエンディアンの2バイト整数を読み込み表示
	// 0 を期待
	

	v = 0;
	for(i=0; i<2; i++) v = (v << 8) | getchar();
	printf("track num=%d\n", v);
	
	// ヘッダのトラック数
	// ビッグエンディアンの2バイト整数を読み込み表示
	// 1 を期待
	

	v = 0;
	for(i=0; i<2; i++) v = (v << 8) | getchar();
	printf("time division=%d (0x%x)\n\n", v, v);
	
	// ヘッダの時間分解能
	// ビッグエンディアンの2バイト整数を読み込み表示
	// 再上位ビットが'0'であることを期待
	

	printf("track\n");

	for(i=0; i<4; i++) id[i] = getchar();
	id[i] = '\0';
	printf("id='%s'\n", id);
	
	// トラックのID 4バイトを読み込み、文字列として表示
	// "MTrk" を期待
	

	v = 0;
	for(i=0; i<4; i++) v = (v << 8) | getchar();
	printf("size=%d\n", v);
	
	// トラックのサイズ
	// ビッグエンディアンの4バイト整数を読み込み表示
	// ここでは、表示するだけで、トラックの末尾判定には使用してない
	

	while(1){
		v = 0;
		do{
			if((c = getchar()) == EOF) break;
			v = (v << 7) | (c & 0x7f);
		}while(c & 0x80);
		if(c == EOF) break;
		printf("delta time=%d\n", v);			
		
		// デルタタイムを読み込み表示
		// 1バイトデータ読み込み時にファイル終端判定をし、終端ならループをぬける
		// データは基本的にビッグエンディアンの整数
		// 各バイトの最上位ビットが、後続データの有無を表す
		// データ自体は、下位7ビット分
		
		
		c = getchar();
		
		// イベントの先頭バイトを読み込み
		

		if(c & 0x80){
		
		// 先頭バイトの最上位ビットが'1'ならば
		
			c1 = c;
			
			// イベント先頭の1バイト目を c1 へ
			

			hi = (c1 >> 4) & 0xf;
			low = c1 & 0xf;
			
			// イベント先頭の1バイト目の上位4ビットを hi へ
			// イベント先頭の1バイト目の下位4ビットを low へ
			

			c2 = getchar();
			
			// イベントの2バイト目を c2 へ
			
		}else{
		
		// 先頭バイトの最上位ビットが'0'ならば
		// 前回のイベント同じ1バイト目の値が省略されている
		// (ランニング・ステータス・ルール)
		// 前回の 1バイト目は c1 に保持されてるはずなので、
		// c1 は、そのままさわらない
		

			c2 = c;
			
			// 先ほど読み込んだ c は、
			// イベントの2バイト目となるはずなので c2 へ
			
		}

		if(hi == 9 || hi == 8){
		
		// イベントの1バイト目の上位4ビットが 9 ならば鍵盤オフ・イベント
		// イベントの1バイト目の上位4ビットが 8 ならば鍵盤オン・イベント
		

			printf("%s ch=%d ", hi == 9 ? "on" : "off", low);
			
			// 鍵盤オン・オフの種別と
			// イベントの1バイト目の下位4ビットのMIDIチャンネルを表示
			

			printf("note=%d ", c2);
			
			// イベントの2バイト目の鍵盤の位置(note)を表示
			

			printf("velo=%d\n", getchar());
			
			// イベントの3バイト目の鍵盤を動かす速度(強さ)を表示
			

			continue;
			
			// ループ先頭へ
			
		}

		printf("c1=0x%02x, c2=0x%02x\n", c1, c2);
		break;
		
		// イベントが期待した鍵盤オン・オフのイベント以外の場合
		// イベント1バイト目の値 c1
		// イベント2バイト目の値 c2
		// を表示し、ループから抜けてプログラムを終了する
		
	}
	return 0;
}

/* EOF */


prog_onoff2.c 解説

prog_onoff.c からの変更箇所のみ

#include <stdio.h>

int
main()
{
	int i, v, c, c1, c2, low, hi;
	char id[5];

	printf("header\n");

	for(i=0; i<4; i++) id[i] = getchar();
	id[i] = '\0';
	printf("id='%s'\n", id);

	v = 0;
	for(i=0; i<4; i++) v = (v << 8) | getchar();
	printf("size=%d\n", v);

	v = 0;
	for(i=0; i<2; i++) v = (v << 8) | getchar();
	printf("format type=%d\n", v);

	v = 0;
	for(i=0; i<2; i++) v = (v << 8) | getchar();
	printf("track num=%d\n", v);

	v = 0;
	for(i=0; i<2; i++) v = (v << 8) | getchar();
	printf("time division=%d (0x%x)\n\n", v, v);


	printf("track\n");

	for(i=0; i<4; i++) id[i] = getchar();
	id[i] = '\0';
	printf("id='%s'\n", id);

	v = 0;
	for(i=0; i<4; i++) v = (v << 8) | getchar();
	printf("size=%d\n", v);

	while(1){
		v = 0;
		do{
			if((c = getchar()) == EOF) break;
			v = (v << 7) | (c & 0x7f);
		}while(c & 0x80);
		if(c == EOF) break;
		printf("delta time=%d\n", v);
		
		c = getchar();
		if(c & 0x80){
			c1 = c;
			hi = (c1 >> 4) & 0xf;
			low = c1 & 0xf;
			c2 = getchar();
		}else{
			c2 = c;
		}

		if(hi == 9 || hi == 8){
			printf("%s ch=%d ", hi == 9 ? "on" : "off", low);
			printf("note=%d ", c2);
			printf("velo=%d\n", getchar());
			continue;
		}

		if(c1 == 0xff){
			printf("meta event type=%d ", c2);
			v = getchar();
			printf("len=%d ...\n", v);
			for(i=0; i<v; i++) c = getchar(); /* skip */
			continue;
		}

		printf("c1=0x%02x, c2=0x%02x\n", c1, c2);
		break;
	}
	return 0;
}

/* EOF */


#include <stdio.h>

int
main()
{
	int i, v, c, c1, c2, low, hi;
	char id[5];

	printf("header\n");

	for(i=0; i<4; i++) id[i] = getchar();
	id[i] = '\0';
	printf("id='%s'\n", id);

	v = 0;
	for(i=0; i<4; i++) v = (v << 8) | getchar();
	printf("size=%d\n", v);

	v = 0;
	for(i=0; i<2; i++) v = (v << 8) | getchar();
	printf("format type=%d\n", v);

	v = 0;
	for(i=0; i<2; i++) v = (v << 8) | getchar();
	printf("track num=%d\n", v);

	v = 0;
	for(i=0; i<2; i++) v = (v << 8) | getchar();
	printf("time division=%d (0x%x)\n\n", v, v);


	printf("track\n");

	for(i=0; i<4; i++) id[i] = getchar();
	id[i] = '\0';
	printf("id='%s'\n", id);

	v = 0;
	for(i=0; i<4; i++) v = (v << 8) | getchar();
	printf("size=%d\n", v);

	while(1){
		v = 0;
		do{
			if((c = getchar()) == EOF) break;
			v = (v << 7) | (c & 0x7f);
		}while(c & 0x80);
		if(c == EOF) break;
		printf("delta time=%d\n", v);
		
		c = getchar();
		if(c & 0x80){
			c1 = c;
			hi = (c1 >> 4) & 0xf;
			low = c1 & 0xf;
			c2 = getchar();
		}else{
			c2 = c;
		}

		if(hi == 9 || hi == 8){
			printf("%s ch=%d ", hi == 9 ? "on" : "off", low);
			printf("note=%d ", c2);
			printf("velo=%d\n", getchar());
			continue;
		}

		if(c1 == 0xff){
		
		// イベントの1バイト目が 0xff ならば
		

			printf("meta event type=%d ", c2);
			
			// メタイベントの種別として、イベントの2バイト目の値を表示
			

			v = getchar();
			printf("len=%d ...\n", v);
			
			// イベントの3バイト目を読み込み表示 (4バイト目以降のバイト数)
			

			for(i=0; i<v; i++) c = getchar(); /* skip */
			
			// 4バイト目から末尾まで読み飛ばす
			

			continue;
			
			// ループ先頭へ
			
		}

		printf("c1=0x%02x, c2=0x%02x\n", c1, c2);
		break;
	}
	return 0;
}

/* EOF */


prog_onoff3.c 解説

prog_onoff2.c からの変更箇所のみ

#include <stdio.h>

int
main()
{
	int i, v, c, c1, c2, low, hi;
	char id[5];

	printf("header\n");

	for(i=0; i<4; i++) id[i] = getchar();
	id[i] = '\0';
	printf("id='%s'\n", id);

	v = 0;
	for(i=0; i<4; i++) v = (v << 8) | getchar();
	printf("size=%d\n", v);

	v = 0;
	for(i=0; i<2; i++) v = (v << 8) | getchar();
	printf("format type=%d\n", v);

	v = 0;
	for(i=0; i<2; i++) v = (v << 8) | getchar();
	printf("track num=%d\n", v);

	v = 0;
	for(i=0; i<2; i++) v = (v << 8) | getchar();
	printf("time division=%d (0x%x)\n\n", v, v);


	printf("track\n");

	for(i=0; i<4; i++) id[i] = getchar();
	id[i] = '\0';
	printf("id='%s'\n", id);

	v = 0;
	for(i=0; i<4; i++) v = (v << 8) | getchar();
	printf("size=%d\n", v);

	while(1){
		v = 0;
		do{
			if((c = getchar()) == EOF) break;
			v = (v << 7) | (c & 0x7f);
		}while(c & 0x80);
		if(c == EOF) break;
		printf("delta time=%d\n", v);
		
		c = getchar();
		if(c & 0x80){
			c1 = c;
			hi = (c1 >> 4) & 0xf;
			low = c1 & 0xf;
			c2 = getchar();
		}else{
			c2 = c;
		}

		if(hi == 9 || hi == 8){
			printf("%s ch=%d ", hi == 9 ? "on" : "off", low);
			printf("note=%d ", c2);
			printf("velo=%d\n", getchar());
			continue;
		}

		if(c1 == 0xff){
			printf("meta event type=%d ", c2);
			v = getchar();
			printf("len=%d ...\n", v);
			for(i=0; i<v; i++) c = getchar(); /* skip */
			continue;
		}

		if(c1 == 0xf0){
			printf("sys ex len=%d ...\n", c2);
			while(getchar() != 0xf7);
			continue;
		}

		printf("c1=0x%02x, c2=0x%02x\n", c1, c2);
		break;
	}
	return 0;
}

/* EOF */


#include <stdio.h>

int
main()
{
	int i, v, c, c1, c2, low, hi;
	char id[5];

	printf("header\n");

	for(i=0; i<4; i++) id[i] = getchar();
	id[i] = '\0';
	printf("id='%s'\n", id);

	v = 0;
	for(i=0; i<4; i++) v = (v << 8) | getchar();
	printf("size=%d\n", v);

	v = 0;
	for(i=0; i<2; i++) v = (v << 8) | getchar();
	printf("format type=%d\n", v);

	v = 0;
	for(i=0; i<2; i++) v = (v << 8) | getchar();
	printf("track num=%d\n", v);

	v = 0;
	for(i=0; i<2; i++) v = (v << 8) | getchar();
	printf("time division=%d (0x%x)\n\n", v, v);


	printf("track\n");

	for(i=0; i<4; i++) id[i] = getchar();
	id[i] = '\0';
	printf("id='%s'\n", id);

	v = 0;
	for(i=0; i<4; i++) v = (v << 8) | getchar();
	printf("size=%d\n", v);

	while(1){
		v = 0;
		do{
			if((c = getchar()) == EOF) break;
			v = (v << 7) | (c & 0x7f);
		}while(c & 0x80);
		if(c == EOF) break;
		printf("delta time=%d\n", v);
		
		c = getchar();
		if(c & 0x80){
			c1 = c;
			hi = (c1 >> 4) & 0xf;
			low = c1 & 0xf;
			c2 = getchar();
		}else{
			c2 = c;
		}

		if(hi == 9 || hi == 8){
			printf("%s ch=%d ", hi == 9 ? "on" : "off", low);
			printf("note=%d ", c2);
			printf("velo=%d\n", getchar());
			continue;
		}

		if(c1 == 0xff){
			printf("meta event type=%d ", c2);
			v = getchar();
			printf("len=%d ...\n", v);
			for(i=0; i<v; i++) c = getchar(); /* skip */
			continue;
		}

		if(c1 == 0xf0){
		
		// イベントの1バイト目が 0xf0 ならば
		

			printf("sys ex len=%d ...\n", c2);
			
			// システム・エクスクルーシブ・メッセージのデータ長として、
			// イベントの2バイト目の値を表示
			

			while(getchar() != 0xf7);
			
			// 3バイト目から、0xf7 が出現するまで読み飛ばす
			

			continue;
			
			// ループ先頭へ
			
		}

		printf("c1=0x%02x, c2=0x%02x\n", c1, c2);
		break;
	}
	return 0;
}

/* EOF */


prog_onoff4.c 解説

prog_onoff3.c からの変更箇所のみ

#include <stdio.h>

int
main()
{
	int i, v, c, c1, c2, low, hi;
	char id[5];

	printf("header\n");

	for(i=0; i<4; i++) id[i] = getchar();
	id[i] = '\0';
	printf("id='%s'\n", id);

	v = 0;
	for(i=0; i<4; i++) v = (v << 8) | getchar();
	printf("size=%d\n", v);

	v = 0;
	for(i=0; i<2; i++) v = (v << 8) | getchar();
	printf("format type=%d\n", v);

	v = 0;
	for(i=0; i<2; i++) v = (v << 8) | getchar();
	printf("track num=%d\n", v);

	v = 0;
	for(i=0; i<2; i++) v = (v << 8) | getchar();
	printf("time division=%d (0x%x)\n\n", v, v);


	printf("track\n");

	for(i=0; i<4; i++) id[i] = getchar();
	id[i] = '\0';
	printf("id='%s'\n", id);

	v = 0;
	for(i=0; i<4; i++) v = (v << 8) | getchar();
	printf("size=%d\n", v);

	while(1){
		v = 0;
		do{
			if((c = getchar()) == EOF) break;
			v = (v << 7) | (c & 0x7f);
		}while(c & 0x80);
		if(c == EOF) break;
		printf("delta time=%d\n", v);
		
		c = getchar();
		if(c & 0x80){
			c1 = c;
			hi = (c1 >> 4) & 0xf;
			low = c1 & 0xf;
			c2 = getchar();
		}else{
			c2 = c;
		}

		if(hi == 9 || hi == 8){
			printf("%s ch=%d ", hi == 9 ? "on" : "off", low);
			printf("note=%d ", c2);
			printf("velo=%d\n", getchar());
			continue;
		}

		if(c1 == 0xff){
			printf("meta event type=%d ", c2);
			v = getchar();
			printf("len=%d ...\n", v);
			for(i=0; i<v; i++) c = getchar(); /* skip */
			continue;
		}

		if(c1 == 0xf0){
			printf("sys ex len=%d ...\n", c2);
			while(getchar() != 0xf7);
			continue;
		}

		if(hi == 0xb){
			printf("%s ch=%d type=%d v=%d\n",
			       c2 < 120 ? "ctl chg" : "chg mode msg",
			       low, c2, getchar());
			continue;
		}

		printf("c1=0x%02x, c2=0x%02x\n", c1, c2);
		break;
	}
	return 0;
}

/* EOF */


#include <stdio.h>

int
main()
{
	int i, v, c, c1, c2, low, hi;
	char id[5];

	printf("header\n");

	for(i=0; i<4; i++) id[i] = getchar();
	id[i] = '\0';
	printf("id='%s'\n", id);

	v = 0;
	for(i=0; i<4; i++) v = (v << 8) | getchar();
	printf("size=%d\n", v);

	v = 0;
	for(i=0; i<2; i++) v = (v << 8) | getchar();
	printf("format type=%d\n", v);

	v = 0;
	for(i=0; i<2; i++) v = (v << 8) | getchar();
	printf("track num=%d\n", v);

	v = 0;
	for(i=0; i<2; i++) v = (v << 8) | getchar();
	printf("time division=%d (0x%x)\n\n", v, v);


	printf("track\n");

	for(i=0; i<4; i++) id[i] = getchar();
	id[i] = '\0';
	printf("id='%s'\n", id);

	v = 0;
	for(i=0; i<4; i++) v = (v << 8) | getchar();
	printf("size=%d\n", v);

	while(1){
		v = 0;
		do{
			if((c = getchar()) == EOF) break;
			v = (v << 7) | (c & 0x7f);
		}while(c & 0x80);
		if(c == EOF) break;
		printf("delta time=%d\n", v);
		
		c = getchar();
		if(c & 0x80){
			c1 = c;
			hi = (c1 >> 4) & 0xf;
			low = c1 & 0xf;
			c2 = getchar();
		}else{
			c2 = c;
		}

		if(hi == 9 || hi == 8){
			printf("%s ch=%d ", hi == 9 ? "on" : "off", low);
			printf("note=%d ", c2);
			printf("velo=%d\n", getchar());
			continue;
		}

		if(c1 == 0xff){
			printf("meta event type=%d ", c2);
			v = getchar();
			printf("len=%d ...\n", v);
			for(i=0; i<v; i++) c = getchar(); /* skip */
			continue;
		}

		if(c1 == 0xf0){
			printf("sys ex len=%d ...\n", c2);
			while(getchar() != 0xf7);
			continue;
		}

		if(hi == 0xb){
		
		// イベントの1バイト目の上位4ビットが 0xb ならば
		

			printf("%s ch=%d type=%d v=%d\n",
			       c2 < 120 ? "ctl chg" : "chg mode msg",
			       low, c2, getchar());
			
			// イベント2バイト目が 120未満ならば、コントロール・チェンジ
			// イベント2バイト目が 120以上ならば、チェンジ・モードメッセージ
			// と表示し、
			// イベントの1バイト目の下位4ビットを、MIDIチャンネルとして表示
			// イベント2バイト目をタイプとして表示
			// イベント3バイト目を読み込み、表示
			

			continue;
			
			// ループ先頭へ
			
		}

		printf("c1=0x%02x, c2=0x%02x\n", c1, c2);
		break;
	}
	return 0;
}

/* EOF */


prog_onoff5.c 解説

prog_onoff4.c からの変更箇所のみ

#include <stdio.h>

int
main()
{
	int i, v, c, c1, c2, low, hi;
	char id[5];

	printf("header\n");

	for(i=0; i<4; i++) id[i] = getchar();
	id[i] = '\0';
	printf("id='%s'\n", id);

	v = 0;
	for(i=0; i<4; i++) v = (v << 8) | getchar();
	printf("size=%d\n", v);

	v = 0;
	for(i=0; i<2; i++) v = (v << 8) | getchar();
	printf("format type=%d\n", v);

	v = 0;
	for(i=0; i<2; i++) v = (v << 8) | getchar();
	printf("track num=%d\n", v);

	v = 0;
	for(i=0; i<2; i++) v = (v << 8) | getchar();
	printf("time division=%d (0x%x)\n\n", v, v);


	printf("track\n");

	for(i=0; i<4; i++) id[i] = getchar();
	id[i] = '\0';
	printf("id='%s'\n", id);

	v = 0;
	for(i=0; i<4; i++) v = (v << 8) | getchar();
	printf("size=%d\n", v);

	while(1){
		v = 0;
		do{
			if((c = getchar()) == EOF) break;
			v = (v << 7) | (c & 0x7f);
		}while(c & 0x80);
		if(c == EOF) break;
		printf("delta time=%d\n", v);
		
		c = getchar();
		if(c & 0x80){
			c1 = c;
			hi = (c1 >> 4) & 0xf;
			low = c1 & 0xf;
			c2 = getchar();
		}else{
			c2 = c;
		}

		if(hi == 9 || hi == 8){
			printf("%s ch=%d ", hi == 9 ? "on" : "off", low);
			printf("note=%d ", c2);
			printf("velo=%d\n", getchar());
			continue;
		}

		if(c1 == 0xff){
			printf("meta event type=%d ", c2);
			v = getchar();
			printf("len=%d ...\n", v);
			for(i=0; i<v; i++) c = getchar(); /* skip */
			continue;
		}

		if(c1 == 0xf0){
			printf("sys ex len=%d ...\n", c2);
			while(getchar() != 0xf7);
			continue;
		}

		if(hi == 0xb){
			printf("%s ch=%d type=%d v=%d\n",
			       c2 < 120 ? "ctl chg" : "chg mode msg",
			       low, c2, getchar());
			continue;
		}

		if(hi == 0xc){
			printf("prog num ch=%d v=%d\n", low, c2);
			continue;
		}

		printf("c1=0x%02x, c2=0x%02x\n", c1, c2);
		break;
	}
	return 0;
}

/* EOF */


#include <stdio.h>

int
main()
{
	int i, v, c, c1, c2, low, hi;
	char id[5];

	printf("header\n");

	for(i=0; i<4; i++) id[i] = getchar();
	id[i] = '\0';
	printf("id='%s'\n", id);

	v = 0;
	for(i=0; i<4; i++) v = (v << 8) | getchar();
	printf("size=%d\n", v);

	v = 0;
	for(i=0; i<2; i++) v = (v << 8) | getchar();
	printf("format type=%d\n", v);

	v = 0;
	for(i=0; i<2; i++) v = (v << 8) | getchar();
	printf("track num=%d\n", v);

	v = 0;
	for(i=0; i<2; i++) v = (v << 8) | getchar();
	printf("time division=%d (0x%x)\n\n", v, v);


	printf("track\n");

	for(i=0; i<4; i++) id[i] = getchar();
	id[i] = '\0';
	printf("id='%s'\n", id);

	v = 0;
	for(i=0; i<4; i++) v = (v << 8) | getchar();
	printf("size=%d\n", v);

	while(1){
		v = 0;
		do{
			if((c = getchar()) == EOF) break;
			v = (v << 7) | (c & 0x7f);
		}while(c & 0x80);
		if(c == EOF) break;
		printf("delta time=%d\n", v);
		
		c = getchar();
		if(c & 0x80){
			c1 = c;
			hi = (c1 >> 4) & 0xf;
			low = c1 & 0xf;
			c2 = getchar();
		}else{
			c2 = c;
		}

		if(hi == 9 || hi == 8){
			printf("%s ch=%d ", hi == 9 ? "on" : "off", low);
			printf("note=%d ", c2);
			printf("velo=%d\n", getchar());
			continue;
		}

		if(c1 == 0xff){
			printf("meta event type=%d ", c2);
			v = getchar();
			printf("len=%d ...\n", v);
			for(i=0; i<v; i++) c = getchar(); /* skip */
			continue;
		}

		if(c1 == 0xf0){
			printf("sys ex len=%d ...\n", c2);
			while(getchar() != 0xf7);
			continue;
		}

		if(hi == 0xb){
			printf("%s ch=%d type=%d v=%d\n",
			       c2 < 120 ? "ctl chg" : "chg mode msg",
			       low, c2, getchar());
			continue;
		}

		if(hi == 0xc){
		
		// イベントの1バイト目の上位4ビットが 0xc ならば
		

			printf("prog num ch=%d v=%d\n", low, c2);
			
			// プログラム番号イベントと表示
			// イベントの1バイト目の下位4ビットを、MIDIチャンネルとして表示
			// イベント2バイト目をプログラム番号として表示
			

			continue;
			
			// ループ先頭へ
			
		}

		printf("c1=0x%02x, c2=0x%02x\n", c1, c2);
		break;
	}
	return 0;
}

/* EOF */


prog_onoff6.c 解説

prog_onoff5.c からの変更箇所のみ

#include <stdio.h>

int
main()
{
	int i, v, c, c1, c2, low, hi;
	char id[5];

	printf("header\n");

	for(i=0; i<4; i++) id[i] = getchar();
	id[i] = '\0';
	printf("id='%s'\n", id);

	v = 0;
	for(i=0; i<4; i++) v = (v << 8) | getchar();
	printf("size=%d\n", v);

	v = 0;
	for(i=0; i<2; i++) v = (v << 8) | getchar();
	printf("format type=%d\n", v);

	v = 0;
	for(i=0; i<2; i++) v = (v << 8) | getchar();
	printf("track num=%d\n", v);

	v = 0;
	for(i=0; i<2; i++) v = (v << 8) | getchar();
	printf("time division=%d (0x%x)\n\n", v, v);


	printf("track\n");

	for(i=0; i<4; i++) id[i] = getchar();
	id[i] = '\0';
	printf("id='%s'\n", id);

	v = 0;
	for(i=0; i<4; i++) v = (v << 8) | getchar();
	printf("size=%d\n", v);

	while(1){
		v = 0;
		do{
			if((c = getchar()) == EOF) break;
			v = (v << 7) | (c & 0x7f);
		}while(c & 0x80);
		if(c == EOF) break;
		printf("delta time=%d\n", v);
		
		c = getchar();
		if(c & 0x80){
			c1 = c;
			hi = (c1 >> 4) & 0xf;
			low = c1 & 0xf;
			c2 = getchar();
		}else{
			c2 = c;
		}

		if(hi == 9 || hi == 8){
			printf("%s ch=%d ", hi == 9 ? "on" : "off", low);
			printf("note=%d ", c2);
			printf("velo=%d\n", getchar());
			continue;
		}

		if(c1 == 0xff){
			printf("meta event type=%d ", c2);
			v = getchar();
			printf("len=%d ...\n", v);
			for(i=0; i<v; i++) c = getchar(); /* skip */
			continue;
		}

		if(c1 == 0xf0){
			printf("sys ex len=%d ...\n", c2);
			while(getchar() != 0xf7);
			continue;
		}

		if(hi == 0xb){
			printf("%s ch=%d type=%d v=%d\n",
			       c2 < 120 ? "ctl chg" : "chg mode msg",
			       low, c2, getchar());
			continue;
		}

		if(hi == 0xc){
			printf("prog num ch=%d v=%d\n", low, c2);
			continue;
		}

		if(hi == 0xe){
			printf("pitch wheel change ch=%d lsb=%d msb=%d\n", low, c2, getchar());
			continue;
		}

		printf("c1=0x%02x, c2=0x%02x\n", c1, c2);
		break;
	}
	return 0;
}

/* EOF */


#include <stdio.h>

int
main()
{
	int i, v, c, c1, c2, low, hi;
	char id[5];

	printf("header\n");

	for(i=0; i<4; i++) id[i] = getchar();
	id[i] = '\0';
	printf("id='%s'\n", id);

	v = 0;
	for(i=0; i<4; i++) v = (v << 8) | getchar();
	printf("size=%d\n", v);

	v = 0;
	for(i=0; i<2; i++) v = (v << 8) | getchar();
	printf("format type=%d\n", v);

	v = 0;
	for(i=0; i<2; i++) v = (v << 8) | getchar();
	printf("track num=%d\n", v);

	v = 0;
	for(i=0; i<2; i++) v = (v << 8) | getchar();
	printf("time division=%d (0x%x)\n\n", v, v);


	printf("track\n");

	for(i=0; i<4; i++) id[i] = getchar();
	id[i] = '\0';
	printf("id='%s'\n", id);

	v = 0;
	for(i=0; i<4; i++) v = (v << 8) | getchar();
	printf("size=%d\n", v);

	while(1){
		v = 0;
		do{
			if((c = getchar()) == EOF) break;
			v = (v << 7) | (c & 0x7f);
		}while(c & 0x80);
		if(c == EOF) break;
		printf("delta time=%d\n", v);
		
		c = getchar();
		if(c & 0x80){
			c1 = c;
			hi = (c1 >> 4) & 0xf;
			low = c1 & 0xf;
			c2 = getchar();
		}else{
			c2 = c;
		}

		if(hi == 9 || hi == 8){
			printf("%s ch=%d ", hi == 9 ? "on" : "off", low);
			printf("note=%d ", c2);
			printf("velo=%d\n", getchar());
			continue;
		}

		if(c1 == 0xff){
			printf("meta event type=%d ", c2);
			v = getchar();
			printf("len=%d ...\n", v);
			for(i=0; i<v; i++) c = getchar(); /* skip */
			continue;
		}

		if(c1 == 0xf0){
			printf("sys ex len=%d ...\n", c2);
			while(getchar() != 0xf7);
			continue;
		}

		if(hi == 0xb){
			printf("%s ch=%d type=%d v=%d\n",
			       c2 < 120 ? "ctl chg" : "chg mode msg",
			       low, c2, getchar());
			continue;
		}

		if(hi == 0xc){
			printf("prog num ch=%d v=%d\n", low, c2);
			continue;
		}

		if(hi == 0xe){
		
		// イベントの1バイト目の上位4ビットが 0xe ならば
		
			printf("pitch wheel change ch=%d lsb=%d msb=%d\n", low, c2, getchar());
			
			// pitch wheel changeと表示
			// イベントの1バイト目の下位4ビットを、MIDIチャンネルとして表示
			// イベント2バイト目をLSB値として表示
			// イベント3バイト目を読み込み、MSB値として表示
			

			continue;
			
			// ループ先頭へ
			
		}

		printf("c1=0x%02x, c2=0x%02x\n", c1, c2);
		break;
	}
	return 0;
}

/* EOF */


prog_onoff_sin2.c 解説

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <math.h>

#define MSG(s) fprintf(stderr, "%s() %s L%d : %s\n", __func__, __FILE__, __LINE__, s)
#define ERR(s) do{ fprintf(stderr, "ERR "); MSG(s); exit(1); }while(0)

int bk_buf = -1;

int
rd(void)
{
	int v;

	if((v = bk_buf) < 0) return getchar();
	bk_buf = -1;
	return v;
}

void
bk(int v)
{
	if(bk_buf >= 0) ERR("give up");
	bk_buf = v;
}

void
rd_str(int n, char *s)
{
	int i;

	for(i=0; i<n; i++) s[i] = rd();
	s[i] = '\0';
}

int
rd_str_chk(int n, char *s)
{
	char buf[256];

	rd_str(n, buf);
	return strcmp(buf, s) == 0;
}

int
rd_int(int n) /* big endian */
{
	int i, v;

	v = 0;
	for(i=0; i<n; i++) v = (v << 8) | rd();
	return v;
}

int
rd_delta(void)
{
	int v, c;

	v = 0;
	do{
		if((c = rd()) == EOF) return EOF;
		v = (v << 7) | (c & 0x7f);
	}while(c & 0x80);
	return v;
}


#define NOTE_BUF_N	256

struct note_rec{
	int ch;
	int note;
	double on_sec;
} note_buf[NOTE_BUF_N];

int smp_freq, smp_cnt;

int
note_buf_is_free(int i)
{
	return note_buf[i].ch < 0;
}

void
note_buf_free(int i)
{
	note_buf[i].ch = -1;
}

void
note_buf_init(void)
{
	int i;

	for(i=0; i<NOTE_BUF_N; i++) note_buf_free(i);
}

int
note_buf_search(int ch, int note)
{
	int i;

	for(i=0; i<NOTE_BUF_N; i++) {
		if(note_buf[i].ch == ch && 
		   (ch < 0 || note_buf[i].note == note)) return i;
	}
	return -1;
}

int
header(void)
{
	int v;

	if(!rd_str_chk(4, "MThd")) ERR("header id");
	if(rd_int(4) != 6) ERR("header size");
	if(rd_int(2) != 0) ERR("header format type");
	if(rd_int(2) != 1) ERR("header track num");
	if((v = rd_int(2)) & 0x8000) ERR("header division");
	return v; /* div4 */
}

double
note_to_freq(int note)
{
	return 440 * pow(2, (note - 69) / 12.0);
}

void
note_onoff(int onoff, double evt_sec, int ch, int note)
{
	double v, sec, freq, dsec;
	int i, iv;

	if(ch == 9) return;

	while((sec = (double)smp_cnt / smp_freq) < evt_sec){
		v = 0;
		for(i=0; i<NOTE_BUF_N; i++){
			if(note_buf_is_free(i)) continue;
			freq = note_to_freq(note_buf[i].note);
			dsec = sec - note_buf[i].on_sec;
			v += sin(2 * M_PI * freq * dsec);
		}
		v /= 16;
		iv = 128 + (int)(v * 127);
		putchar(iv);
		smp_cnt++;
	}
	;
	if(onoff){
		if((i = note_buf_search(-1, 0)) < 0){
			MSG("note_buf full");
			return;
		}
		note_buf[i].note = note;
		note_buf[i].ch = ch;
		note_buf[i].on_sec = evt_sec;
	}else{
		if((i = note_buf_search(ch, note)) < 0) return;
		note_buf_free(i);
	}
}

int
main()
{
	int div4, delta_sum;
	int i, n, v, hi, low, note;
	double sec;

	smp_freq = 8000;
	smp_cnt = 0;
	note_buf_init();

	div4 = header();

	if(!rd_str_chk(4, "MTrk")) ERR("track id");
	v = rd_int(4); /* skip */

	hi = low = 0;
	delta_sum = 0;
	while((v = rd_delta()) != EOF){
		delta_sum += v;
		sec = (double)delta_sum / div4 * 0.5;
		
		if((v = rd()) & 0x80){
			hi = (v >> 4) & 0xf;
			low  = v & 0xf;
		}else bk(v);

		switch(hi){
		case 8:
		case 9:
			note = rd();
			rd(); /* skip velo */
			note_onoff(hi == 9, sec, low, note);
			break;
		case 0xb:
		case 0xe:
			rd();
			rd();
			break;
		case 0xc:
			rd();
			break;
		case 0xf:
			rd();
			switch(low){
			case 0:
				while(rd() != 0xf7);
				break;
			case 0xf:
				n = rd();
				for(i=0; i<n; i++) rd();
				break;
			}
			break;
		}
	}
	return 0;
}

/* EOF */


#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <math.h>


#define MSG(s) fprintf(stderr, "%s() %s L%d : %s\n", __func__, __FILE__, __LINE__, s)
// 標準エラーへ、メッセージを出力するマクロ
//
// 呼び出し元の関数名、ファイル名、行番号と、引数の文字列 s を
// 標準エラーへ出力する



#define ERR(s) do{ fprintf(stderr, "ERR "); MSG(s); exit(1); }while(0)
// エラー終了用マクロ
//
// 引数の文字列 s を、MSG() マクロを使って出力し
// exit() 関数でプログラムを終了する



int bk_buf = -1;
// 標準入力のプッシュバック用の変数
//
// rd() 関数, bk() 関数から使用
// rd() 関数は、標準入力からの読み込み
// bk() 関数は、1バイトだけのプッシュバック用
// bk() 関数でプッシュバックした1バイト分を bk_buf に保持する
// 負の値は空を意味し、プッシュバックされてない状態を表す


int
rd(void)
{
	// 標準入力から1バイト読み込む
	//
	// 1バイトだけプッシュバック可能
	// プッシュバックは bk() 関数を使う
	

	int v;

	
	if((v = bk_buf) < 0) return getchar();
	// 変数 bk_buf を調べ、プッシュバックされてなければ、
	// getchar() で、標準入力から1バイト読み込み、返す
	

	
	bk_buf = -1;
	// プッシュバックされている値は、ローカル変数 vに代入済
	// 変数 bk_buf に負の値を設定し、空の状態に戻す
	

	
	return v;
	// プッシュバックされていた値を返す
	
}

void
bk(int v)
{
	// 標準入力のプッシュバック
	//
	// 一旦 rd() で読み込んだ値を、引数 v に指定し、
	// 1バイトだけプッシュバックで戻す
	

	
	if(bk_buf >= 0) ERR("give up");
	// 変数 bk_buf を調べ、空でなければ、
	// 既にプッシュバックされているので、エラー終了
	

	
	bk_buf = v;
	// プッシュバックされてない状態なので、
	// 引数で指定された値を、変数 bk_buf に設定して、
	// プッシュバックする
	
}

void
rd_str(int n, char *s)
{
	// 文字列の読み込み
	//
	// 引数 n で指定したバイト数を、標準入力から読み込み、
	// 引数 s に格納し、末尾に '\0' を設定して返る
	

	int i;

	for(i=0; i<n; i++) s[i] = rd();
	s[i] = '\0';
}

int
rd_str_chk(int n, char *s)
{
	// 文字列を読み込み、指定文字列と比較した結果を返す
	//
	// 関数 rd_str() を呼び出し、
	// 内部変数 buf に、nバイトの文字列を読み込む
	// 読み込んだ buf の内容を、引数 s で指定した文字列と比較
	// 一致したら真(1)を、一致しなければ偽(0)を返す
	

	char buf[256];

	rd_str(n, buf);
	return strcmp(buf, s) == 0;
}

int
rd_int(int n) /* big endian */
{
	// 整数の読み込み (ビッグエンディアン)
	//
	// 標準入力からビッグエンディアンの整数を読み込み返す
	// 整数のバイト数は、引数 n で指定
	

	int i, v;

	v = 0;
	for(i=0; i<n; i++) v = (v << 8) | rd();
	return v;
}

int
rd_delta(void)
{
	// デルタタイムの読み込み
	//
	// 標準入力からデルタタイムを読み込み返す
	

	int v, c;

	
	v = 0;
	do{
		if((c = rd()) == EOF) return EOF;
		v = (v << 7) | (c & 0x7f);
	}while(c & 0x80);
	return v;

	// 1バイトデータ読み込み時にファイル終端判定をし、終端ならループをぬける
	// データは基本的にビッグエンディアンの整数
	// 各バイトの最上位ビットが、後続データの有無を表す
	// データ自体は、下位7ビット分
	
}



#define NOTE_BUF_N	256
// 鍵盤のオン情報を記録するバッファ数の上限


struct note_rec{
	
	int ch;
	// MIDIチャンネル
	

	
	int note;
	// 鍵盤の位置
	

	
	double on_sec;
	// 鍵盤をオンにした時の時刻(秒)
	


} note_buf[NOTE_BUF_N];
// 鍵盤のオン情報を記録するバッファ




int smp_freq, smp_cnt;
// サンプリング周波数と、サンプリング回数
//
// サンプリング周波数
// 1秒あたりのサンプル数(出力データ数)
//
// サンプリング回数
// 0から順に増加
// サンプリング・データを1つ出力する毎に +1 していく
// サンプリング周波数 smp_freq の値まで達すると、1秒分のデータが出力されている


int
note_buf_is_free(int i)
{
	// 鍵盤のオン情報を記録するバッファの解放判定
	//
	// 引数 i で指定した、インデックスのバッファが、
	// 解放されているか判定する
	

	
	return note_buf[i].ch < 0;
	// バッファのMIDIチャンネルが、負の値なら、
	// 解放されていると判定する
	// 0 以上の値なら、使用中と判定する
	
}

void
note_buf_free(int i)
{
	// 鍵盤のオン情報を記録するバッファの解放
	//
	// 引数 i で指定した、インデックスのバッファを解放する
	

	
	note_buf[i].ch = -1;
	// 指定のバッファのMIDIチャンネルに、負の値を設定する
	
}

void
note_buf_init(void)
{
	// 鍵盤のオン情報を記録するバッファ全体の初期化
	

	int i;

	
	for(i=0; i<NOTE_BUF_N; i++) note_buf_free(i);
	// 全てのバッファを解放状態に設定する
	
}

int
note_buf_search(int ch, int note)
{
	// 鍵盤のオン情報を記録するバッファの探索
	//
	// 引数 ch で指定したMIDIチャンネル
	// 引数 note で指定した鍵盤の位置
	// を保持しているバッファを探索し、
	// そのバッファのインデックスを返す
	//
	// ただし、引数 ch に -1が指定された場合は、引数 note は無視し、
	// MIDIチャンネルが -1 のバッファ(つまり解放されているバッファ)
	// のインデックスを返す
	

	int i;

	for(i=0; i<NOTE_BUF_N; i++) {
		if(note_buf[i].ch == ch && 
		   (ch < 0 || note_buf[i].note == note)) return i;
	}
	return -1;
}

int
header(void)
{
	// SMFのヘッダ部分の読み込み
	//
	// 標準入力からSMFのヘッダ部分を読み込み、時間分解能を返す
	

	int v;

	
	if(!rd_str_chk(4, "MThd")) ERR("header id");
	// 先頭4バイトのIDが "MThd" か判定
	// 異なればエラー終了
	

	
	if(rd_int(4) != 6) ERR("header size");
	// 続く4バイトのサイズ情報が、6(バイト)か判定
	// 異なればエラー終了
	

	
	if(rd_int(2) != 0) ERR("header format type");
	// 続く2バイトのフォーマットタイプが 0 か判定
	// 異なればエラー終了
	

	
	if(rd_int(2) != 1) ERR("header track num");
	// 続く2バイトのトラック数が 1 か判定
	// 異なればエラー終了
	

	
	if((v = rd_int(2)) & 0x8000) ERR("header division");
	// 続く2バイトの時間分解能を、変数vに保持
	// 最上位ビットが '1' の場合は取り扱わないので、
	// エラー終了
	

	
	return v; /* div4 */
	// 変数vに保持してる、時間分解能を返す
	
}

double
note_to_freq(int note)
{
	// 鍵盤の位置(note)から、音の周波数への変換
	//
	// 鍵盤の位置 note は、ノート番号を指定
	// 対応する周波数を返す
	

	
	return 440 * pow(2, (note - 69) / 12.0);
	// ノート番号69は440Hzに相当する
	// ノート番号が12増えると1オクターブ上がるので周波数は2倍になる
	// よって、ノート番号が1増えると周波数は 2^(1/12) 倍になる
	
}

void
note_onoff(int onoff, double evt_sec, int ch, int note)
{
	// 鍵盤オン・オフのイベントを処理する関数
	//
	// 引数 onoff は、鍵盤オンなら 1 を指定、鍵盤オフなら 0 を指定
	// 引数 evt_sec は、イベントの発生時刻(秒)
	// 引数 ch は、MIDIチャンネル
	// 引数 note は、鍵盤のノート番号
	

	double v, sec, freq, dsec;
	int i, iv;

	
	if(ch == 9) return;
	// MIDIチャンネルが 9 の場合は、ドラムパートなので、
	// 今の段階では、あきらめて、何もしないで返る
	

	
	while((sec = (double)smp_cnt / smp_freq) < evt_sec){
	// 変数 smp_cnt のサンプリング回数(データ出力回数)を、
	// 変数 smp_freq のサンプリング周波数で割って、
	// サンプリング回数を、曲開始からの時刻(秒)に換算し、
	// 変数 sec に保持
	//
	// 曲開始からの時刻(秒) sec が、
	// 引数 evt_sec のイベントの発生時刻(秒) より小さい間は、
	// 処理ループを実行し、データ出力を続ける
	

		
		v = 0;
		// 今回のデータ出力値を保持する変数を 0 クリア
		

		
		for(i=0; i<NOTE_BUF_N; i++){
		// 鍵盤のオン情報を記録する全バッファ分の繰り返し
		// バッファのインデックスは、繰り返し変数 i
		

			
			if(note_buf_is_free(i)) continue;
			// 鍵盤のオン情報を記録するバッファの解放判定
			// インデックス i のバッファが解放されていれば
			// 何もせず、インデックスを更新し、ループ先頭へ
			// バッファが使用中ならば、以降の処理へ
			

			
			freq = note_to_freq(note_buf[i].note);
			// 使用中のバッファに記録されている、
			// ノート番号を、周波数に換算し、変数 freq に保持
			

			
			dsec = sec - note_buf[i].on_sec;
			// 使用中のバッファに記録されている、
			// 鍵盤をオンにした時の時刻(秒)を参照
			//
			// 現在の処理時刻(曲開始からの時刻) sec から、
			// 鍵盤をオンにした時の時刻(秒)を引き算
			// 
			// 結果の鍵盤をオンにしてからの経過時間(秒)を、
			// 変数 desc へ
			

			
			v += sin(2 * M_PI * freq * dsec);
			// 鳴らす音の周波数 freq と、
			// 鍵盤をオンにしてからの経過時間
			// (音が鳴り始めてからの経過時間) dsec をかけ算して、
			// サイクルを算出
			//
			// sin()関数は入力 0 から 2π でSINパターン1つ分
			// sin(2π × サイクル) で、現在の波形の値 -1.0〜+1.0 へ
			//
			// 現在の波形の値を、今回のデータ出力値を保持する変数 v に足し算する
			
		}
		
		v /= 16;
		// ループ終了後、変数 v には、
		// 使用中だったバッファ数分の sin()関数が加算されているので、
		// 使用中たったバッファ数を n とすると、
		// v のとる値は、最小 -1.0 * n、最大 +1.0 * n となり得る
		//
		// 同時にどれだけの和音が鳴るかは、曲次第だが、
		// MIDIチャンネル数 16 をひとつの目安として、
		// とりあえず 16 で割算してみている
		//
		// 以降、v の値は、-1.0〜+10 の範囲に収まってると見なして処理する
		

		
		iv = 128 + (int)(v * 127);
		// 出力するデータ形式は、ビット長 8 bit、符号なし
		//
		// v * 127 で -127.0 〜 +127.0 をとり
		// 128 + (int)(v * 127) で 1 〜 255 の値をとる
		// 
		// 変数 iv は 1 〜 255 の値
		

		
		putchar(iv);
		// 曲開始からの時刻 sec における出力データとして、
		// iv の値を標準出力へ出力
		

		
		smp_cnt++;
		// サンプリング回数を +1 して更新
		
	}
	
	// ループを抜けたら、
	// 引数 evt_sec までのデータ出力が、
	// 終了してる状態になっている
	

	
	if(onoff){
	// 引数 onoff が 1
	// つまり鍵盤オン・イベントならば
	

		
		if((i = note_buf_search(-1, 0)) < 0){
		// 鍵盤のオン情報を記録するバッファを探索し、
		// 解放されてるバッファのインデックスを、変数 i へ
		// 
		// 変数 i が負の値、
		// つまり解放されてるバッファがなかった場合を判定
		

			
			MSG("note_buf full");
			// バッファが満杯の旨のメッセージを表示
			

			
			return;
			// その鍵盤オン情報を処理しないだけで、
			// 関数から返る
			// プログラム終了まではしない
			
		}

		
		// この位置では、解放されてるバッファのインデックスが
		// 変数 i に保持されている

		note_buf[i].note = note;
		note_buf[i].ch = ch;
		note_buf[i].on_sec = evt_sec;
		// 解放されているバッファに、
		// - 鍵盤の位置(ノート番号)
		// - MIDIチャンネル
		// - 鍵盤をオンにした時の時刻(秒)
		// を記録
		//
		// バッファの MIDIチャンネルは、変数 ch の値
		// (非負の値)となり、そのバッファは使用中となる
		// 
		// 次のイベントを処理する際に、
		// この関数の冒頭の while()ループ箇所で、
		// 使用中のバッファの音は、全て出力されるので、
		// 次回のこの関数の実行から、
		// 登録した鍵盤オン情報の、音が出力され始める
		

	
	}else{
	// 引数 onoff が 0
	// つまり鍵盤オフ・イベントならば
	

		
		if((i = note_buf_search(ch, note)) < 0) return;
		// 鍵盤のオン情報を記録するバッファを探索
		//
		// 引数 ch のMIDIチャンネル、
		// 引数 note のノート番号をもつバッファを探し、
		// そのインデックスを変数 i へ
		//
		// 変数 i が負の値、
		// つまりオフにしようとしてる鍵盤の情報が、
		// バッファ内に見つからなければ、何もせずに返る
		

		
		note_buf_free(i);
		// オフにしようとしている鍵盤の情報は、
		// インデックス i のバッファ
		// よって、インデックス i のバッファを解放する
		//
		// 以降の処理では、オフにした鍵盤の音は鳴らない
		
	}
}

int
main()
{
	int div4, delta_sum;
	int i, n, v, hi, low, note;
	double sec;

	
	smp_freq = 8000;
	// サンプリング周波数
	//
	// 8000 Hz
	// 1秒間に8000回
	

	
	smp_cnt = 0;
	// サンプリング回数初期化
	// 0に設定
	//
	// サンプリング回数は、0から順に増加
	// サンプリング・データを1つ出力する毎に +1 していく
	// サンプリング周波数 smp_freq の値まで達すると、
	// 1秒分のデータが出力されている
	

	
	note_buf_init();
	// 鍵盤のオン情報を記録するバッファ全体の初期化
	

	
	div4 = header();
	// SMFのヘッダ部分の読み込み
	// ヘッダの時間分解能を、変数 div4 に
	

	
	if(!rd_str_chk(4, "MTrk")) ERR("track id");
	// トラックのID 4バイトを読み込み
	// "MTrk"か判定
	// 異なればエラー終了
	

	
	v = rd_int(4); /* skip */
	// トラックのサイズを読み込み
	// 変数 v に
	//
	// トラックの末尾は、標準入力の末尾(EOF)で判定するので、
	// この情報は、特に使用しない	
	//
	// 以降の標準入力には、
	// デルタタイムと、イベントの組が現れる
	

	
	hi = low = 0;
	// イベントの先頭の1バイト目の値の、
	// 上位4ビットを保持する変数 hi
	// 下位4ビットを保持する変数 low
	// について、0 で初期化
	

	
	delta_sum = 0;
	// デルタタイムの積算値を保持する変数 delta_sum を 0 で初期化
	

	
	while((v = rd_delta()) != EOF){
	// デルタタイムを読み込み
	// 変数 v へ
	// 
	// 変数 v が、データ末尾を表す値(EOF)なら、
	// 繰り返しループを抜ける
	//
	// その他の場合は、while()ループを繰り返す
	

		
		delta_sum += v;
		// 読み込んだデルタタイムを、
		// 変数 delta_sum に加算
		

		
		sec = (double)delta_sum / div4 * 0.5;
		// デルタタイムの積算値 delta_sum から
		// 次に控えるイベントの、イベント発生時刻に換算
		//
		// ここでは簡単のため、
		// 四分音符一つあたり0.5秒固定としている
		//
		// 曲の先頭からの時刻(秒)は
		// <デルタタイムの合計> ÷ <ヘッダの分解能> × 0.5
		
		
		
		if((v = rd()) & 0x80){
		// イベントの先頭の1バイト目を読み込み
		// 変数 v へ
		// その値の最上位ビットが '1' か判定
		

			
			hi = (v >> 4) & 0xf;
			low  = v & 0xf;
			// 最上位ビットが '1' の場合は、
			// 変数 v には、イベントの先頭の1バイト目が読み込まれているので、
			// その値の上位4ビットを、変数 hi へ
			// その値の下位4ビットを、変数 low へ
			

		
		}else bk(v);
			// 最上位ビットが '0' の場合は、
			// ランニング・ステータス・ルールにより、
			// 前回のイベントと同じ1バイト目の値のため、1バイト目が省略されている
			// 
			// よって、変数 v には、イベントの2バイト目が読み込まれている事になるので、
			// bk() 関数を呼び出し、プッシュバックして戻しておく
			//
			// 変数 hi, low には、前回のイベントの値が残っているはず
			

		
		switch(hi){
		// イベントの先頭の1バイト目の値の、
		// 上位4ビットの値により、分岐
		

		
		case 8:
		case 9:
		// 1バイト目の上位4ビットが 8 または 9 の場合
		

			
			note = rd();
			// イベントの2バイト目のノート番号を読み込み
			// 変数 note へ
			

			
			rd(); /* skip velo */
			// イベントの3バイト目のベロシティ(鍵盤を動かす速さ、強さ)は、
			// 今の段階では、使用しないので、
			// 空読みして、読み飛ばす
			

			
			note_onoff(hi == 9, sec, low, note);
			// 鍵盤オン・オフのイベントを処理する関数
			// note_onoff() を呼び出す
			//
			// 第一引数は、鍵盤オンなら 1 を指定、鍵盤オフなら 0 を指定する
			// 1バイト目の上位4ビットが 8 の場合、鍵盤のオフ・イベント
			// 1バイト目の上位4ビットが 9 の場合、鍵盤のオン・イベント
			// 従って、変数 hi が 9 ならば 1 、その他ならば 0 を指定している
			//
			// 第二引数は、イベントの発生時刻(秒)を指定する
			// デルタタイムの積算値から換算した値を保持してる、変数 sec を指定
			//
			// 第三引数は、MIDIチャンネルを指定する
			// 鍵盤のオン・オフのイベントでは、
			// 1バイト目の下位4ビットの値が、MIDIチャンネルを表す
			// 従って、変数 low を指定
			//
			// 第四引数は、鍵盤のノート番号を指定する
			// イベントの2バイト目として読み込んだ、変数 note を指定
			//
			// この呼び出しで、鍵盤のオン・オフのイベントが処理されて
			// sec で指定した時刻に至るまでの、波形データが出力される
			

			
			break;
			// switch文の分岐から抜ける
			

		
		case 0xb:
		case 0xe:
		// 1バイト目の上位4ビットが 0xb または 0xe の場合

			// イベントは、
			// コントロール・チェンジ・イベントあるいは、
			// チェンジ・モード・メッセージ・イベントあるいは、
			// pitch wheel change イベントのいづれか
			//
			// いずれも場合も、イベント長は3バイト
			

			
			rd();
			rd();
			// 今の段階では、使用しないので、
			// イベントの2バイト目、3バイト目を、
			// 空読みして、読み飛ばす
			

			
			break;
			// switch文の分岐から抜ける
			

		
		case 0xc:
		// 1バイト目の上位4ビットが 0xc の場合

			// イベントは、
			// プログラム番号イベント
			//
			// イベント長は2バイト
			

			
			rd();
			// 今の段階では、使用しないので、
			// イベントの2バイト目を、
			// 空読みして、読み飛ばす
			

			
			break;
			// switch文の分岐から抜ける
			

		
		case 0xf:
		// 1バイト目の上位4ビットが 0xf の場合

			// イベントは、
			// メタイベントあるいは、
			// システム・エクスクルーシブ・メッセージ・イベントのいづれか
			//
			// ただし、ターゲットとしているSMFを使う範囲では
			

			
			rd();
			// イベントの2バイト目は、
			// メタイベントならば、イベントタイプ
			// システム・エクスクルーシブ・メッセージ・イベントならば、データ長
			//
			// ここでは、使用しないので、
			// イベントの2バイト目を、
			// 空読みして、読み飛ばす
			//
			// システム・エクスクルーシブ・メッセージ・イベントのデータ長について
			//
			// イベント末尾判定としては、
			// イベント末尾のデータが 0xf7 で終端している事を利用するので、
			// データ長は、使用しない
			

			
			switch(low){
			// イベントの先頭の1バイト目の値の、
			// 下位4ビットの値により、分岐
			

			
			case 0:
			// 1バイト目の下位4ビットが 0 の場合

				// イベントは、システム・エクスクルーシブ・メッセージ
				

				
				while(rd() != 0xf7);
				// 3バイト目以降を、
				// 終端を表す 0xf7 が出現するまで、
				// 空読みして、読み飛ばす
				

				
				break;
				// switch文の分岐から抜ける
				

			
			case 0xf:
			// 1バイト目の下位4ビットが 0xf の場合

				// イベントは、メタイベント
				

				
				n = rd();
				// 3バイト目はデータ長で、4バイト目以降に続くバイト数
				// 変数 n へ
				

				
				for(i=0; i<n; i++) rd();
				// 4バイト目以降に続くデータを、
				// 変数 n の回数分、
				// 空読みして、読み飛ばす
				

				
				break;
				// switch文の分岐から抜ける
				
			}

			
			break;
			// switch文の分岐から抜ける
			
		}

	
		// while文の繰り返しループ末尾
		// ループ先頭へ戻る
	}
	

	
	// ループから抜けた位置

	return 0;
	// プログラム正常終了
	
}

/* EOF */


prog_onoff_sin3.c 解説

prog_onoff_sin2.c からの変更箇所のみ

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <math.h>

#define MSG(s) fprintf(stderr, "%s() %s L%d : %s\n", __func__, __FILE__, __LINE__, s)
#define ERR(s) do{ fprintf(stderr, "ERR "); MSG(s); exit(1); }while(0)

int bk_buf = -1;

int
rd(void)
{
	int v;

	if((v = bk_buf) < 0) return getchar();
	bk_buf = -1;
	return v;
}

void
bk(int v)
{
	if(bk_buf >= 0) ERR("give up");
	bk_buf = v;
}

void
rd_str(int n, char *s)
{
	int i;

	for(i=0; i<n; i++) s[i] = rd();
	s[i] = '\0';
}

int
rd_str_chk(int n, char *s)
{
	char buf[256];

	rd_str(n, buf);
	return strcmp(buf, s) == 0;
}

int
rd_int(int n) /* big endian */
{
	int i, v;

	v = 0;
	for(i=0; i<n; i++) v = (v << 8) | rd();
	return v;
}

int
rd_delta(void)
{
	int v, c;

	v = 0;
	do{
		if((c = rd()) == EOF) return EOF;
		v = (v << 7) | (c & 0x7f);
	}while(c & 0x80);
	return v;
}


#define NOTE_BUF_N	256

struct note_rec{
	int ch;
	int note;
	double on_sec;
} note_buf[NOTE_BUF_N];

int smp_freq, smp_cnt;

int
note_buf_is_free(int i)
{
	return note_buf[i].ch < 0;
}

void
note_buf_free(int i)
{
	note_buf[i].ch = -1;
}

void
note_buf_init(void)
{
	int i;

	for(i=0; i<NOTE_BUF_N; i++) note_buf_free(i);
}

int
note_buf_search(int ch, int note)
{
	int i;

	for(i=0; i<NOTE_BUF_N; i++) {
		if(note_buf[i].ch == ch &&
		   (ch < 0 || note_buf[i].note == note)) return i;
	}
	return -1;
}

int
header(void)
{
	int v;

	if(!rd_str_chk(4, "MThd")) ERR("header id");
	if(rd_int(4) != 6) ERR("header size");
	if(rd_int(2) != 0) ERR("header format type");
	if(rd_int(2) != 1) ERR("header track num");
	if((v = rd_int(2)) & 0x8000) ERR("header division");
	return v; /* div4 */
}

double
note_to_freq(int note)
{
	return 440 * pow(2, (note - 69) / 12.0);
}

void
note_onoff(int onoff, double evt_sec, int ch, int note)
{
	double v, sec, freq, dsec;
	int i, iv;

	if(ch == 9) return;

	while((sec = (double)smp_cnt / smp_freq) < evt_sec){
		v = 0;
		for(i=0; i<NOTE_BUF_N; i++){
			if(note_buf_is_free(i)) continue;
			freq = note_to_freq(note_buf[i].note);
			dsec = sec - note_buf[i].on_sec;
			v += sin(2 * M_PI * freq * dsec);
		}
		v /= 16;
		iv = 128 + (int)(v * 127);
		putchar(iv);
		smp_cnt++;
	}
	if(onoff){
		if((i = note_buf_search(-1, 0)) < 0){
			MSG("note_buf full");
			return;
		}
		note_buf[i].note = note;
		note_buf[i].ch = ch;
		note_buf[i].on_sec = evt_sec;
	}else{
		if((i = note_buf_search(ch, note)) < 0) return;
		note_buf_free(i);
	}
}

int
main()
{
	int div4, delta_sum;
	int i, n, v, hi, low, note;
	double sec;

	smp_freq = 8000;
	smp_cnt = 0;
	note_buf_init();

	div4 = header();

	if(!rd_str_chk(4, "MTrk")) ERR("track id");
	v = rd_int(4); /* skip */

	hi = low = 0;
	delta_sum = 0;
	while((v = rd_delta()) != EOF){
		delta_sum += v;
		sec = (double)delta_sum / div4 * 0.5;
		
		if((v = rd()) & 0x80){
			hi = (v >> 4) & 0xf;
			low  = v & 0xf;
		}else bk(v);

		switch(hi){
		case 8:
		case 9:
			note = rd();
			rd(); /* skip velo */
			note_onoff(hi == 9, sec, low, note);
			break;
		case 0xa:
		case 0xb:
		case 0xe:
			rd();
			rd();
			break;
		case 0xc:		
		case 0xd:
			rd();
			break;
		case 0xf:
			rd();
			switch(low){
			case 0:
				while(rd() != 0xf7);
				break;
			case 1:
			case 3:
				rd();
				break;
			case 2:
				rd();
				rd();
				break;
			case 0xf:
				n = rd();
				for(i=0; i<n; i++) rd();
				break;
			default:
				break;
			}
			break;
		}
	}
	return 0;
}

/* EOF */


#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <math.h>

#define MSG(s) fprintf(stderr, "%s() %s L%d : %s\n", __func__, __FILE__, __LINE__, s)
#define ERR(s) do{ fprintf(stderr, "ERR "); MSG(s); exit(1); }while(0)

int bk_buf = -1;

int
rd(void)
{
	int v;

	if((v = bk_buf) < 0) return getchar();
	bk_buf = -1;
	return v;
}

void
bk(int v)
{
	if(bk_buf >= 0) ERR("give up");
	bk_buf = v;
}

void
rd_str(int n, char *s)
{
	int i;

	for(i=0; i<n; i++) s[i] = rd();
	s[i] = '\0';
}

int
rd_str_chk(int n, char *s)
{
	char buf[256];

	rd_str(n, buf);
	return strcmp(buf, s) == 0;
}

int
rd_int(int n) /* big endian */
{
	int i, v;

	v = 0;
	for(i=0; i<n; i++) v = (v << 8) | rd();
	return v;
}

int
rd_delta(void)
{
	int v, c;

	v = 0;
	do{
		if((c = rd()) == EOF) return EOF;
		v = (v << 7) | (c & 0x7f);
	}while(c & 0x80);
	return v;
}


#define NOTE_BUF_N	256

struct note_rec{
	int ch;
	int note;
	double on_sec;
} note_buf[NOTE_BUF_N];

int smp_freq, smp_cnt;

int
note_buf_is_free(int i)
{
	return note_buf[i].ch < 0;
}

void
note_buf_free(int i)
{
	note_buf[i].ch = -1;
}

void
note_buf_init(void)
{
	int i;

	for(i=0; i<NOTE_BUF_N; i++) note_buf_free(i);
}

int
note_buf_search(int ch, int note)
{
	int i;

	for(i=0; i<NOTE_BUF_N; i++) {
		if(note_buf[i].ch == ch &&
		   (ch < 0 || note_buf[i].note == note)) return i;
	}
	return -1;
}

int
header(void)
{
	int v;

	if(!rd_str_chk(4, "MThd")) ERR("header id");
	if(rd_int(4) != 6) ERR("header size");
	if(rd_int(2) != 0) ERR("header format type");
	if(rd_int(2) != 1) ERR("header track num");
	if((v = rd_int(2)) & 0x8000) ERR("header division");
	return v; /* div4 */
}

double
note_to_freq(int note)
{
	return 440 * pow(2, (note - 69) / 12.0);
}

void
note_onoff(int onoff, double evt_sec, int ch, int note)
{
	double v, sec, freq, dsec;
	int i, iv;

	if(ch == 9) return;

	while((sec = (double)smp_cnt / smp_freq) < evt_sec){
		v = 0;
		for(i=0; i<NOTE_BUF_N; i++){
			if(note_buf_is_free(i)) continue;
			freq = note_to_freq(note_buf[i].note);
			dsec = sec - note_buf[i].on_sec;
			v += sin(2 * M_PI * freq * dsec);
		}
		v /= 16;
		iv = 128 + (int)(v * 127);
		putchar(iv);
		smp_cnt++;
	}
	if(onoff){
		if((i = note_buf_search(-1, 0)) < 0){
			MSG("note_buf full");
			return;
		}
		note_buf[i].note = note;
		note_buf[i].ch = ch;
		note_buf[i].on_sec = evt_sec;
	}else{
		if((i = note_buf_search(ch, note)) < 0) return;
		note_buf_free(i);
	}
}

int
main()
{
	int div4, delta_sum;
	int i, n, v, hi, low, note;
	double sec;

	smp_freq = 8000;
	smp_cnt = 0;
	note_buf_init();

	div4 = header();

	if(!rd_str_chk(4, "MTrk")) ERR("track id");
	v = rd_int(4); /* skip */

	hi = low = 0;
	delta_sum = 0;
	while((v = rd_delta()) != EOF){
		delta_sum += v;
		sec = (double)delta_sum / div4 * 0.5;
		
		if((v = rd()) & 0x80){
			hi = (v >> 4) & 0xf;
			low  = v & 0xf;
		}else bk(v);

		switch(hi){
		case 8:
		case 9:
			note = rd();
			rd(); /* skip velo */
			note_onoff(hi == 9, sec, low, note);
			break;
		case 0xa:
			// 1バイト目の上位4ビットが 0xa の場合
			// イベントは、キー・プレッシャー (アフター・タッチ) イベント
			// イベント長は3バイト
			
		case 0xb:
		case 0xe:
			rd();
			rd();
			break;
		case 0xc:		
		case 0xd:
			// 1バイト目の上位4ビットが 0xd の場合
			// イベントは、チャンネル・プレッシャー・イベント
			// イベント長は2バイト
			
			rd();
			break;
		case 0xf:
			rd();
			switch(low){
			case 0:
				while(rd() != 0xf7);
				break;
			case 1:
			case 3:
				rd();
				break;
				
				// 1バイト目の下位4ビットが 1 の場合
				// イベントは、MIDIタイムコード・イベント
				// 1バイト目の下位4ビットが 3 の場合
				// イベントは、ソング番号イベント
				// データ長は2バイト
				// 2バイト目を
				// 空読みして、読み飛ばす
				
			case 2:
				rd();
				rd();
				break;
				
				// 1バイト目の下位4ビットが 2 の場合
				// イベントは、ソング・ポジション・イベント
				// データ長は3バイト
				// 2バイト目、3バイト目を
				// 空読みして、読み飛ばす
				
			case 0xf:
				n = rd();
				for(i=0; i<n; i++) rd();
				break;
			default:
				break;
				
				// その他の場合、
				// イベント長は1バイト、または不明
				// 1バイトとして扱い、読み飛ばす
				
			}
			break;
		}
	}
	return 0;
}

/* EOF */


prog_onoff_sin4.c 解説

prog_onoff_sin3.c からの変更箇所のみ

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <math.h>

#define MSG(s) fprintf(stderr, "%s() %s L%d : %s\n", __func__, __FILE__, __LINE__, s)
#define ERR(s) do{ fprintf(stderr, "ERR "); MSG(s); exit(1); }while(0)

int bk_buf = -1;

int
rd(void)
{
	int v;

	if((v = bk_buf) < 0) return getchar();
	bk_buf = -1;
	return v;
}

void
bk(int v)
{
	if(bk_buf >= 0) ERR("give up");
	bk_buf = v;
}

void
rd_str(int n, char *s)
{
	int i;

	for(i=0; i<n; i++) s[i] = rd();
	s[i] = '\0';
}

int
rd_str_chk(int n, char *s)
{
	char buf[256];

	rd_str(n, buf);
	return strcmp(buf, s) == 0;
}

int
rd_int(int n) /* big endian */
{
	int i, v;

	v = 0;
	for(i=0; i<n; i++) v = (v << 8) | rd();
	return v;
}

int
rd_delta(void)
{
	int v, c;

	v = 0;
	do{
		if((c = rd()) == EOF) return EOF;
		v = (v << 7) | (c & 0x7f);
	}while(c & 0x80);
	return v;
}


#define NOTE_BUF_N	256

struct note_rec{
	int ch;
	int note;
	double on_sec;
} note_buf[NOTE_BUF_N];

int smp_freq, smp_cnt;

int
note_buf_is_free(int i)
{
	return note_buf[i].ch < 0;
}

void
note_buf_free(int i)
{
	note_buf[i].ch = -1;
}

void
note_buf_init(void)
{
	int i;

	for(i=0; i<NOTE_BUF_N; i++) note_buf_free(i);
}

int
note_buf_search(int ch, int note)
{
	int i;

	for(i=0; i<NOTE_BUF_N; i++) {
		if(note_buf[i].ch == ch && 
		   (ch < 0 || note_buf[i].note == note)) return i;
	}
	return -1;
}

int
header(void)
{
	int v;

	if(!rd_str_chk(4, "MThd")) ERR("header id");
	if(rd_int(4) != 6) ERR("header size");
	if(rd_int(2) != 0) ERR("header format type");
	if(rd_int(2) != 1) ERR("header track num");
	if((v = rd_int(2)) & 0x8000) ERR("header division");
	return v; /* div4 */
}

double
note_to_freq(int note)
{
	return 440 * pow(2, (note - 69) / 12.0);
}

void
note_onoff(int onoff, double evt_sec, int ch, int note)
{
	double v, sec, freq, dsec;
	int i, iv;

	if(ch == 9) return;

	while((sec = (double)smp_cnt / smp_freq) < evt_sec){
		v = 0;
		for(i=0; i<NOTE_BUF_N; i++){
			if(note_buf_is_free(i)) continue;
			freq = note_to_freq(note_buf[i].note);
			dsec = sec - note_buf[i].on_sec;
			v += sin(2 * M_PI * freq * dsec);
		}
		v /= 16;
		iv = 128 + (int)(v * 127);
		putchar(iv);
		smp_cnt++;
	}
	if(onoff){
		if((i = note_buf_search(-1, 0)) < 0){
			MSG("note_buf full");
			return;
		}
		note_buf[i].note = note;
		note_buf[i].ch = ch;
		note_buf[i].on_sec = evt_sec;
	}else{
		if((i = note_buf_search(ch, note)) < 0) return;
		note_buf_free(i);
	}
}

int
opt_int(char *key, int ac, char **av, int def)
{
	int i;

	for(i=1; i<ac; i++) if(strcmp(av[i], key) == 0) break;
	if(i+1 >= ac) return def;
	return strtol(av[i+1], NULL, 0);
}

int
main(int ac, char **av)
{
	int div4, delta_sum;
	int i, n, v, hi, low, note;
	double sec;

	smp_freq = opt_int("-r", ac, av, 8000);
	smp_cnt = 0;
	note_buf_init();

	div4 = header();

	if(!rd_str_chk(4, "MTrk")) ERR("track id");
	v = rd_int(4); /* skip */

	hi = low = 0;
	delta_sum = 0;
	while((v = rd_delta()) != EOF){
		delta_sum += v;
		sec = (double)delta_sum / div4 * 0.5;
		
		if((v = rd()) & 0x80){
			hi = (v >> 4) & 0xf;
			low  = v & 0xf;
		}else bk(v);

		switch(hi){
		case 8:
		case 9:
			note = rd();
			rd(); /* skip velo */
			note_onoff(hi == 9, sec, low, note);
			break;
		case 0xa:
		case 0xb:
		case 0xe:
			rd();
			rd();
			break;
		case 0xc:		
		case 0xd:
			rd();
			break;
		case 0xf:
			rd();
			switch(low){
			case 0:
				while(rd() != 0xf7);
				break;
			case 1:
			case 3:
				rd();
				break;
			case 2:
				rd();
				rd();
				break;
			case 0xf:
				n = rd();
				for(i=0; i<n; i++) rd();
				break;
			default:
				break;
			}
			break;
		}
	}
	return 0;
}

/* EOF */


#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <math.h>

#define MSG(s) fprintf(stderr, "%s() %s L%d : %s\n", __func__, __FILE__, __LINE__, s)
#define ERR(s) do{ fprintf(stderr, "ERR "); MSG(s); exit(1); }while(0)

int bk_buf = -1;

int
rd(void)
{
	int v;

	if((v = bk_buf) < 0) return getchar();
	bk_buf = -1;
	return v;
}

void
bk(int v)
{
	if(bk_buf >= 0) ERR("give up");
	bk_buf = v;
}

void
rd_str(int n, char *s)
{
	int i;

	for(i=0; i<n; i++) s[i] = rd();
	s[i] = '\0';
}

int
rd_str_chk(int n, char *s)
{
	char buf[256];

	rd_str(n, buf);
	return strcmp(buf, s) == 0;
}

int
rd_int(int n) /* big endian */
{
	int i, v;

	v = 0;
	for(i=0; i<n; i++) v = (v << 8) | rd();
	return v;
}

int
rd_delta(void)
{
	int v, c;

	v = 0;
	do{
		if((c = rd()) == EOF) return EOF;
		v = (v << 7) | (c & 0x7f);
	}while(c & 0x80);
	return v;
}


#define NOTE_BUF_N	256

struct note_rec{
	int ch;
	int note;
	double on_sec;
} note_buf[NOTE_BUF_N];

int smp_freq, smp_cnt;

int
note_buf_is_free(int i)
{
	return note_buf[i].ch < 0;
}

void
note_buf_free(int i)
{
	note_buf[i].ch = -1;
}

void
note_buf_init(void)
{
	int i;

	for(i=0; i<NOTE_BUF_N; i++) note_buf_free(i);
}

int
note_buf_search(int ch, int note)
{
	int i;

	for(i=0; i<NOTE_BUF_N; i++) {
		if(note_buf[i].ch == ch && 
		   (ch < 0 || note_buf[i].note == note)) return i;
	}
	return -1;
}

int
header(void)
{
	int v;

	if(!rd_str_chk(4, "MThd")) ERR("header id");
	if(rd_int(4) != 6) ERR("header size");
	if(rd_int(2) != 0) ERR("header format type");
	if(rd_int(2) != 1) ERR("header track num");
	if((v = rd_int(2)) & 0x8000) ERR("header division");
	return v; /* div4 */
}

double
note_to_freq(int note)
{
	return 440 * pow(2, (note - 69) / 12.0);
}

void
note_onoff(int onoff, double evt_sec, int ch, int note)
{
	double v, sec, freq, dsec;
	int i, iv;

	if(ch == 9) return;

	while((sec = (double)smp_cnt / smp_freq) < evt_sec){
		v = 0;
		for(i=0; i<NOTE_BUF_N; i++){
			if(note_buf_is_free(i)) continue;
			freq = note_to_freq(note_buf[i].note);
			dsec = sec - note_buf[i].on_sec;
			v += sin(2 * M_PI * freq * dsec);
		}
		v /= 16;
		iv = 128 + (int)(v * 127);
		putchar(iv);
		smp_cnt++;
	}
	if(onoff){
		if((i = note_buf_search(-1, 0)) < 0){
			MSG("note_buf full");
			return;
		}
		note_buf[i].note = note;
		note_buf[i].ch = ch;
		note_buf[i].on_sec = evt_sec;
	}else{
		if((i = note_buf_search(ch, note)) < 0) return;
		note_buf_free(i);
	}
}

int
opt_int(char *key, int ac, char **av, int def)
{
	
	// コマンドライン・パラメータで指定された整数を返す
	//
	// 起動時のコマンドライン中に ...  <整数の文字列> ...
	// の組を探索し、整数を返す
	//
	// 見つからなければ、指定されたデフォルト値を返す
	//
	// 引数 key は、を指定
	// 引数 ac, av は、main()関数の引数を指定
	// 引数 def は、デフォルト値として返す値を指定
	
	int i;

	for(i=1; i<ac; i++) if(strcmp(av[i], key) == 0) break;
	
	// コマンドライン・パラメータで指定された文字列から、
	// 引数 key の文字列を探索
	// 見つかれば、探索ループを抜ける
	

	if(i+1 >= ac) return def;
	
	// 探索ループ中にkey文字列が無かった場合、
	// あるいは、key文字列があったが、続く整数の文字列が無かった場合、
	// 引数 def で指定された、デフォルト値を返す
	

	return strtol(av[i+1], NULL, 0);
	
	// key文字列に続く、整数の文字列を、strtol()関数で整数に変換して返す
	
}

int

main(int ac, char **av)
{
	
	// プログラム起動時の、コマンドライン・パラメータを受け取るため、
	// 引数 int ac, char **av を追加
	

	int div4, delta_sum;
	int i, n, v, hi, low, note;
	double sec;


	smp_freq = opt_int("-r", ac, av, 8000);
	
	// コマンドライン・パラメータで指定された整数を取得する
	// -r <サンプリング周波数>
	// として指定された整数を取得し、変数 smp_freq へ設定
	// コマンドラインで指定が無かった場合は、
	// デフォルト値 8000 を設定
	

	smp_cnt = 0;
	note_buf_init();

	div4 = header();

	if(!rd_str_chk(4, "MTrk")) ERR("track id");
	v = rd_int(4); /* skip */

	hi = low = 0;
	delta_sum = 0;
	while((v = rd_delta()) != EOF){
		delta_sum += v;
		sec = (double)delta_sum / div4 * 0.5;
		
		if((v = rd()) & 0x80){
			hi = (v >> 4) & 0xf;
			low  = v & 0xf;
		}else bk(v);

		switch(hi){
		case 8:
		case 9:
			note = rd();
			rd(); /* skip velo */
			note_onoff(hi == 9, sec, low, note);
			break;
		case 0xa:
		case 0xb:
		case 0xe:
			rd();
			rd();
			break;
		case 0xc:		
		case 0xd:
			rd();
			break;
		case 0xf:
			rd();
			switch(low){
			case 0:
				while(rd() != 0xf7);
				break;
			case 1:
			case 3:
				rd();
				break;
			case 2:
				rd();
				rd();
				break;
			case 0xf:
				n = rd();
				for(i=0; i<n; i++) rd();
				break;
			default:
				break;
			}
			break;
		}
	}
	return 0;
}

/* EOF */


prog_onoff_sin5.c 解説

prog_onoff_sin4.c からの変更箇所のみ

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <math.h>

#define MSG(s) fprintf(stderr, "%s() %s L%d : %s\n", __func__, __FILE__, __LINE__, s)
#define ERR(s) do{ fprintf(stderr, "ERR "); MSG(s); exit(1); }while(0)

int bk_buf = -1;

int
rd(void)
{
	int v;

	if((v = bk_buf) < 0) return getchar();
	bk_buf = -1;
	return v;
}

void
bk(int v)
{
	if(bk_buf >= 0) ERR("give up");
	bk_buf = v;
}

void
rd_str(int n, char *s)
{
	int i;

	for(i=0; i<n; i++) s[i] = rd();
	s[i] = '\0';
}

int
rd_str_chk(int n, char *s)
{
	char buf[256];

	rd_str(n, buf);
	return strcmp(buf, s) == 0;
}

int
rd_int(int n) /* big endian */
{
	int i, v;

	v = 0;
	for(i=0; i<n; i++) v = (v << 8) | rd();
	return v;
}

int
rd_delta(void)
{
	int v, c;

	v = 0;
	do{
		if((c = rd()) == EOF) return EOF;
		v = (v << 7) | (c & 0x7f);
	}while(c & 0x80);
	return v;
}


#define NOTE_BUF_N	256

struct note_rec{
	int ch;
	int note;
	double on_sec;
} note_buf[NOTE_BUF_N];

int smp_freq, smp_cnt;
int bit_len;

int
note_buf_is_free(int i)
{
	return note_buf[i].ch < 0;
}

void
note_buf_free(int i)
{
	note_buf[i].ch = -1;
}

void
note_buf_init(void)
{
	int i;

	for(i=0; i<NOTE_BUF_N; i++) note_buf_free(i);
}

int
note_buf_search(int ch, int note)
{
	int i;

	for(i=0; i<NOTE_BUF_N; i++) {
		if(note_buf[i].ch == ch && 
		   (ch < 0 || note_buf[i].note == note)) return i;
	}
	return -1;
}

int
header(void)
{
	int v;

	if(!rd_str_chk(4, "MThd")) ERR("header id");
	if(rd_int(4) != 6) ERR("header size");
	if(rd_int(2) != 0) ERR("header format type");
	if(rd_int(2) != 1) ERR("header track num");
	if((v = rd_int(2)) & 0x8000) ERR("header division");
	return v; /* div4 */
}

double
note_to_freq(int note)
{
	return 440 * pow(2, (note - 69) / 12.0);
}

void
note_onoff(int onoff, double evt_sec, int ch, int note)
{
	double v, sec, freq, dsec;
	int i, iv;

	if(ch == 9) return;

	while((sec = (double)smp_cnt / smp_freq) < evt_sec){
		v = 0;
		for(i=0; i<NOTE_BUF_N; i++){
			if(note_buf_is_free(i)) continue;
			freq = note_to_freq(note_buf[i].note);
			dsec = sec - note_buf[i].on_sec;
			v += sin(2 * M_PI * freq * dsec);
		}
		v /= 16;
		switch(bit_len){
		case 8:
			iv = 128 + (int)(v * 127);
			putchar(iv);
			break;
		case 16:
			iv = 32768 + (int)(v * 32767);
			putchar(iv & 0xff);
			putchar((iv >> 8) & 0xff);
			break;
		}
		smp_cnt++;
	}
	if(onoff){
		if((i = note_buf_search(-1, 0)) < 0){
			MSG("note_buf full");
			return;
		}
		note_buf[i].note = note;
		note_buf[i].ch = ch;
		note_buf[i].on_sec = evt_sec;
	}else{
		if((i = note_buf_search(ch, note)) < 0) return;
		note_buf_free(i);
	}
}

int
opt_int(char *key, int ac, char **av, int def)
{
	int i;

	for(i=1; i<ac; i++) if(strcmp(av[i], key) == 0) break;
	if(i+1 >= ac) return def;
	return strtol(av[i+1], NULL, 0);
}

int
main(int ac, char **av)
{
	int div4, delta_sum;
	int i, n, v, hi, low, note;
	double sec;

	smp_freq = opt_int("-r", ac, av, 8000);
	smp_cnt = 0;
	bit_len = opt_int("-b", ac, av, 8);
	if(bit_len != 8 && bit_len != 16) ERR("bit_len");
	note_buf_init();

	div4 = header();

	if(!rd_str_chk(4, "MTrk")) ERR("track id");
	v = rd_int(4); /* skip */

	hi = low = 0;
	delta_sum = 0;
	while((v = rd_delta()) != EOF){
		delta_sum += v;
		sec = (double)delta_sum / div4 * 0.5;
		
		if((v = rd()) & 0x80){
			hi = (v >> 4) & 0xf;
			low  = v & 0xf;
		}else bk(v);

		switch(hi){
		case 8:
		case 9:
			note = rd();
			rd(); /* skip velo */
			note_onoff(hi == 9, sec, low, note);
			break;
		case 0xa:
		case 0xb:
		case 0xe:
			rd();
			rd();
			break;
		case 0xc:		
		case 0xd:
			rd();
			break;
		case 0xf:
			rd();
			switch(low){
			case 0:
				while(rd() != 0xf7);
				break;
			case 1:
			case 3:
				rd();
				break;
			case 2:
				rd();
				rd();
				break;
			case 0xf:
				n = rd();
				for(i=0; i<n; i++) rd();
				break;
			default:
				break;
			}
			break;
		}
	}
	return 0;
}

/* EOF */


#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <math.h>

#define MSG(s) fprintf(stderr, "%s() %s L%d : %s\n", __func__, __FILE__, __LINE__, s)
#define ERR(s) do{ fprintf(stderr, "ERR "); MSG(s); exit(1); }while(0)

int bk_buf = -1;

int
rd(void)
{
	int v;

	if((v = bk_buf) < 0) return getchar();
	bk_buf = -1;
	return v;
}

void
bk(int v)
{
	if(bk_buf >= 0) ERR("give up");
	bk_buf = v;
}

void
rd_str(int n, char *s)
{
	int i;

	for(i=0; i<n; i++) s[i] = rd();
	s[i] = '\0';
}

int
rd_str_chk(int n, char *s)
{
	char buf[256];

	rd_str(n, buf);
	return strcmp(buf, s) == 0;
}

int
rd_int(int n) /* big endian */
{
	int i, v;

	v = 0;
	for(i=0; i<n; i++) v = (v << 8) | rd();
	return v;
}

int
rd_delta(void)
{
	int v, c;

	v = 0;
	do{
		if((c = rd()) == EOF) return EOF;
		v = (v << 7) | (c & 0x7f);
	}while(c & 0x80);
	return v;
}


#define NOTE_BUF_N	256

struct note_rec{
	int ch;
	int note;
	double on_sec;
} note_buf[NOTE_BUF_N];

int smp_freq, smp_cnt;
int bit_len;

// PCMデータのビット長
// 値 8 ならば 8 ビット
// 値 16 ならば 16 ビット


int
note_buf_is_free(int i)
{
	return note_buf[i].ch < 0;
}

void
note_buf_free(int i)
{
	note_buf[i].ch = -1;
}

void
note_buf_init(void)
{
	int i;

	for(i=0; i<NOTE_BUF_N; i++) note_buf_free(i);
}

int
note_buf_search(int ch, int note)
{
	int i;

	for(i=0; i<NOTE_BUF_N; i++) {
		if(note_buf[i].ch == ch && 
		   (ch < 0 || note_buf[i].note == note)) return i;
	}
	return -1;
}

int
header(void)
{
	int v;

	if(!rd_str_chk(4, "MThd")) ERR("header id");
	if(rd_int(4) != 6) ERR("header size");
	if(rd_int(2) != 0) ERR("header format type");
	if(rd_int(2) != 1) ERR("header track num");
	if((v = rd_int(2)) & 0x8000) ERR("header division");
	return v; /* div4 */
}

double
note_to_freq(int note)
{
	return 440 * pow(2, (note - 69) / 12.0);
}

void
note_onoff(int onoff, double evt_sec, int ch, int note)
{
	double v, sec, freq, dsec;
	int i, iv;

	if(ch == 9) return;

	while((sec = (double)smp_cnt / smp_freq) < evt_sec){
		v = 0;
		for(i=0; i<NOTE_BUF_N; i++){
			if(note_buf_is_free(i)) continue;
			freq = note_to_freq(note_buf[i].note);
			dsec = sec - note_buf[i].on_sec;
			v += sin(2 * M_PI * freq * dsec);
		}
		v /= 16;
		switch(bit_len){
		
		// ビット長で分岐
		

		case 8:
		
		// 8ビットの場合
		// 従来通り、符号なし8ビットで出力
		
			iv = 128 + (int)(v * 127);
			putchar(iv);
			break;
		case 16:
		
		// 16ビットの場合
		// 符号なし16ビット(リトルエンディアン)で出力
		
			iv = 32768 + (int)(v * 32767);
			putchar(iv & 0xff);
			putchar((iv >> 8) & 0xff);
			break;
		}
		smp_cnt++;
	}
	if(onoff){
		if((i = note_buf_search(-1, 0)) < 0){
			MSG("note_buf full");
			return;
		}
		note_buf[i].note = note;
		note_buf[i].ch = ch;
		note_buf[i].on_sec = evt_sec;
	}else{
		if((i = note_buf_search(ch, note)) < 0) return;
		note_buf_free(i);
	}
}

int
opt_int(char *key, int ac, char **av, int def)
{
	int i;

	for(i=1; i<ac; i++) if(strcmp(av[i], key) == 0) break;
	if(i+1 >= ac) return def;
	return strtol(av[i+1], NULL, 0);
}

int
main(int ac, char **av)
{
	int div4, delta_sum;
	int i, n, v, hi, low, note;
	double sec;

	smp_freq = opt_int("-r", ac, av, 8000);
	smp_cnt = 0;
	bit_len = opt_int("-b", ac, av, 8);
	if(bit_len != 8 && bit_len != 16) ERR("bit_len");
	
	// コマンドライン・パラメータで指定された整数を取得する
	// -b <ビット長 (8 or 16)>
	// として指定された整数を取得し、変数 bit_len へ設定
	// コマンドラインで指定が無かった場合は、
	// デフォルト値 8 を設定
	//
	// bit_len に設定された整数が、
	// 8 でも 16 でもなければ、エラー終了
	

	note_buf_init();

	div4 = header();

	if(!rd_str_chk(4, "MTrk")) ERR("track id");
	v = rd_int(4); /* skip */

	hi = low = 0;
	delta_sum = 0;
	while((v = rd_delta()) != EOF){
		delta_sum += v;
		sec = (double)delta_sum / div4 * 0.5;
		
		if((v = rd()) & 0x80){
			hi = (v >> 4) & 0xf;
			low  = v & 0xf;
		}else bk(v);

		switch(hi){
		case 8:
		case 9:
			note = rd();
			rd(); /* skip velo */
			note_onoff(hi == 9, sec, low, note);
			break;
		case 0xa:
		case 0xb:
		case 0xe:
			rd();
			rd();
			break;
		case 0xc:		
		case 0xd:
			rd();
			break;
		case 0xf:
			rd();
			switch(low){
			case 0:
				while(rd() != 0xf7);
				break;
			case 1:
			case 3:
				rd();
				break;
			case 2:
				rd();
				rd();
				break;
			case 0xf:
				n = rd();
				for(i=0; i<n; i++) rd();
				break;
			default:
				break;
			}
			break;
		}
	}
	return 0;
}

/* EOF */


prog_onoff_sin6.c 解説

prog_onoff_sin5.c からの変更箇所のみ

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <math.h>

#define MSG(s) fprintf(stderr, "%s() %s L%d : %s\n", __func__, __FILE__, __LINE__, s)
#define ERR(s) do{ fprintf(stderr, "ERR "); MSG(s); exit(1); }while(0)

int bk_buf = -1;

int
rd(void)
{
	int v;

	if((v = bk_buf) < 0) return getchar();
	bk_buf = -1;
	return v;
}

void
bk(int v)
{
	if(bk_buf >= 0) ERR("give up");
	bk_buf = v;
}

void
rd_str(int n, char *s)
{
	int i;

	for(i=0; i<n; i++) s[i] = rd();
	s[i] = '\0';
}

int
rd_str_chk(int n, char *s)
{
	char buf[256];

	rd_str(n, buf);
	return strcmp(buf, s) == 0;
}

int
rd_int(int n) /* big endian */
{
	int i, v;

	v = 0;
	for(i=0; i<n; i++) v = (v << 8) | rd();
	return v;
}

int
rd_delta(void)
{
	int v, c;

	v = 0;
	do{
		if((c = rd()) == EOF) return EOF;
		v = (v << 7) | (c & 0x7f);
	}while(c & 0x80);
	return v;
}


#define NOTE_BUF_N	256

struct note_rec{
	int ch;
	int note;
	double on_sec;
} note_buf[NOTE_BUF_N];

int smp_freq, smp_cnt;
int bit_len;
int sign;

int
note_buf_is_free(int i)
{
	return note_buf[i].ch < 0;
}

void
note_buf_free(int i)
{
	note_buf[i].ch = -1;
}

void
note_buf_init(void)
{
	int i;

	for(i=0; i<NOTE_BUF_N; i++) note_buf_free(i);
}

int
note_buf_search(int ch, int note)
{
	int i;

	for(i=0; i<NOTE_BUF_N; i++) {
		if(note_buf[i].ch == ch && 
		   (ch < 0 || note_buf[i].note == note)) return i;
	}
	return -1;
}

int
header(void)
{
	int v;

	if(!rd_str_chk(4, "MThd")) ERR("header id");
	if(rd_int(4) != 6) ERR("header size");
	if(rd_int(2) != 0) ERR("header format type");
	if(rd_int(2) != 1) ERR("header track num");
	if((v = rd_int(2)) & 0x8000) ERR("header division");
	return v; /* div4 */
}

double
note_to_freq(int note)
{
	return 440 * pow(2, (note - 69) / 12.0);
}

void
note_onoff(int onoff, double evt_sec, int ch, int note)
{
	double v, sec, freq, dsec;
	int i, iv;
	int base, amp;
	int iv_min, iv_max;

	if(ch == 9) return;

	amp = bit_len == 8 ? 127 : 32767;
	base = sign ? 0 : amp + 1;
	iv_min = base - (amp + 1);
	iv_max = base + amp;

	while((sec = (double)smp_cnt / smp_freq) < evt_sec){
		v = 0;
		for(i=0; i<NOTE_BUF_N; i++){
			if(note_buf_is_free(i)) continue;
			freq = note_to_freq(note_buf[i].note);
			dsec = sec - note_buf[i].on_sec;
			v += sin(2 * M_PI * freq * dsec);
		}
		v /= 16;
		iv = base + (int)(v * amp);
		if(iv > iv_max) iv = iv_max;
		if(iv < iv_min) iv = iv_min;
		switch(bit_len){
		case 8:
			putchar(iv);
			break;
		case 16:
			putchar(iv & 0xff);
			putchar((iv >> 8) & 0xff);
			break;
		}
		smp_cnt++;
	}
	if(onoff){
		if((i = note_buf_search(-1, 0)) < 0){
			MSG("note_buf full");
			return;
		}
		note_buf[i].note = note;
		note_buf[i].ch = ch;
		note_buf[i].on_sec = evt_sec;
	}else{
		if((i = note_buf_search(ch, note)) < 0) return;
		note_buf_free(i);
	}
}

int
opt_idx(char *key, int ac, char **av)
{
	int i;

	for(i=1; i<ac; i++) if(strcmp(av[i], key) == 0) return i;
	return -1;
}

int
opt_int(char *key, int ac, char **av, int def)
{
	int i;

	i = opt_idx(key, ac, av);
	if(i < 0 || i+1 >= ac) return def;
	return strtol(av[i+1], NULL, 0);
}

int
main(int ac, char **av)
{
	int div4, delta_sum;
	int i, n, v, hi, low, note;
	double sec;

	smp_freq = opt_int("-r", ac, av, 8000);
	smp_cnt = 0;
	bit_len = opt_int("-b", ac, av, 8);
	if(bit_len != 8 && bit_len != 16) ERR("bit_len");
	sign = (opt_idx("-s", ac, av) >= 0);
	note_buf_init();

	div4 = header();

	if(!rd_str_chk(4, "MTrk")) ERR("track id");
	v = rd_int(4); /* skip */

	hi = low = 0;
	delta_sum = 0;
	while((v = rd_delta()) != EOF){
		delta_sum += v;
		sec = (double)delta_sum / div4 * 0.5;
		
		if((v = rd()) & 0x80){
			hi = (v >> 4) & 0xf;
			low  = v & 0xf;
		}else bk(v);

		switch(hi){
		case 8:
		case 9:
			note = rd();
			rd(); /* skip velo */
			note_onoff(hi == 9, sec, low, note);
			break;
		case 0xa:
		case 0xb:
		case 0xe:
			rd();
			rd();
			break;
		case 0xc:		
		case 0xd:
			rd();
			break;
		case 0xf:
			rd();
			switch(low){
			case 0:
				while(rd() != 0xf7);
				break;
			case 1:
			case 3:
				rd();
				break;
			case 2:
				rd();
				rd();
				break;
			case 0xf:
				n = rd();
				for(i=0; i<n; i++) rd();
				break;
			default:
				break;
			}
			break;
		}
	}
	return 0;
}

/* EOF */


#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <math.h>

#define MSG(s) fprintf(stderr, "%s() %s L%d : %s\n", __func__, __FILE__, __LINE__, s)
#define ERR(s) do{ fprintf(stderr, "ERR "); MSG(s); exit(1); }while(0)

int bk_buf = -1;

int
rd(void)
{
	int v;

	if((v = bk_buf) < 0) return getchar();
	bk_buf = -1;
	return v;
}

void
bk(int v)
{
	if(bk_buf >= 0) ERR("give up");
	bk_buf = v;
}

void
rd_str(int n, char *s)
{
	int i;

	for(i=0; i<n; i++) s[i] = rd();
	s[i] = '\0';
}

int
rd_str_chk(int n, char *s)
{
	char buf[256];

	rd_str(n, buf);
	return strcmp(buf, s) == 0;
}

int
rd_int(int n) /* big endian */
{
	int i, v;

	v = 0;
	for(i=0; i<n; i++) v = (v << 8) | rd();
	return v;
}

int
rd_delta(void)
{
	int v, c;

	v = 0;
	do{
		if((c = rd()) == EOF) return EOF;
		v = (v << 7) | (c & 0x7f);
	}while(c & 0x80);
	return v;
}


#define NOTE_BUF_N	256

struct note_rec{
	int ch;
	int note;
	double on_sec;
} note_buf[NOTE_BUF_N];

int smp_freq, smp_cnt;
int bit_len;
int sign;

// 符号有無の形式を保持する
// 0 なら 符号なし
// 1 なら 符号あり


int
note_buf_is_free(int i)
{
	return note_buf[i].ch < 0;
}

void
note_buf_free(int i)
{
	note_buf[i].ch = -1;
}

void
note_buf_init(void)
{
	int i;

	for(i=0; i<NOTE_BUF_N; i++) note_buf_free(i);
}

int
note_buf_search(int ch, int note)
{
	int i;

	for(i=0; i<NOTE_BUF_N; i++) {
		if(note_buf[i].ch == ch && 
		   (ch < 0 || note_buf[i].note == note)) return i;
	}
	return -1;
}

int
header(void)
{
	int v;

	if(!rd_str_chk(4, "MThd")) ERR("header id");
	if(rd_int(4) != 6) ERR("header size");
	if(rd_int(2) != 0) ERR("header format type");
	if(rd_int(2) != 1) ERR("header track num");
	if((v = rd_int(2)) & 0x8000) ERR("header division");
	return v; /* div4 */
}

double
note_to_freq(int note)
{
	return 440 * pow(2, (note - 69) / 12.0);
}

void
note_onoff(int onoff, double evt_sec, int ch, int note)
{
	double v, sec, freq, dsec;
	int i, iv;
	int base, amp;
	
	// データを整数に変換する際の、底上げする値と振幅を保持
	//
	// 整数 iv = base + 小数(-1.0〜+1.0) * amp
	// として変換する
	//
	// ループ中で毎回算出するのを避けて、
	// ループに入る前に算出し、値を変数に保持しておく
	
	int iv_min, iv_max;
	
	// 整数に変換した時の最小値と最大値
	// クリップ用に保持する
	

	if(ch == 9) return;

	amp = bit_len == 8 ? 127 : 32767;
	
	// 振幅 amp を設定
	// ビット長が 8 なら  (2^8) / 2 - 1
	// ビット長が 16 なら (2^16) / 2 -1
	

	base = sign ? 0 : amp + 1;
	
	// 底上げする値 base を設定
	// 符号あり (sign == 1) ならば、0
	// 符号なし (sign == 0) ならば、振幅 amp + 1
	// つまり
	//   ビット長が 8 なら  (2^8) / 2
	//   ビット長が 16 なら  (2^16) / 2
	

	iv_min = base - (amp + 1);
	iv_max = base + amp;
	
	// 整数に変換した時の最小値と最大値を変数 iv_min, iv_max へ
	//
	// 8 bit 符号なしなら 0, 255
	// 8 bit 符号ありなら -128, 127
	// 16 bit 符号なしなら 0, 65535
	// 16 bit 符号ありなら -32768, 32767
	

	while((sec = (double)smp_cnt / smp_freq) < evt_sec){
		v = 0;
		for(i=0; i<NOTE_BUF_N; i++){
			if(note_buf_is_free(i)) continue;
			freq = note_to_freq(note_buf[i].note);
			dsec = sec - note_buf[i].on_sec;
			v += sin(2 * M_PI * freq * dsec);
		}
		v /= 16;
		iv = base + (int)(v * amp);
		
		// 小数の値(-1.0〜+1.0)を、整数へ変換
		//
		// ビット長のswitch分岐内で処理してたが、外に出した
		//
		// ビット長、符号の有無による違いは、
		// 変数 base, amp に保持させて共通化した
		

		if(iv > iv_max) iv = iv_max;
		
		// 値の上限クリップ処理を追加
		

		if(iv < iv_min) iv = iv_min;
		
		// 値の下限クリップ処理を追加
		

		switch(bit_len){
		case 8:
			putchar(iv);
			break;
		case 16:
			putchar(iv & 0xff);
			putchar((iv >> 8) & 0xff);
			break;
		}
		smp_cnt++;
	}
	if(onoff){
		if((i = note_buf_search(-1, 0)) < 0){
			MSG("note_buf full");
			return;
		}
		note_buf[i].note = note;
		note_buf[i].ch = ch;
		note_buf[i].on_sec = evt_sec;
	}else{
		if((i = note_buf_search(ch, note)) < 0) return;
		note_buf_free(i);
	}
}

int
opt_idx(char *key, int ac, char **av)
{
	
	// コマンドライン・パラメータの文字列探索
	//
	// 起動時のコマンドライン中に ...  ...
	// が存在するか探索し、そのインデックスを返す
	//
	// 見つからなければ、-1 を返す
	//
	// 引数 key は、を指定
	// 引数 ac, av は、main()関数の引数を指定
	
	int i;

	for(i=1; i<ac; i++) if(strcmp(av[i], key) == 0) return i;
	return -1;
}

int
opt_int(char *key, int ac, char **av, int def)
{
	int i;

	i = opt_idx(key, ac, av);
	if(i < 0 || i+1 >= ac) return def;
	
	// 機能の変更は無し
	// 追加した opt_idx() 関数を使用するように変更
	
	return strtol(av[i+1], NULL, 0);
}

int
main(int ac, char **av)
{
	int div4, delta_sum;
	int i, n, v, hi, low, note;
	double sec;

	smp_freq = opt_int("-r", ac, av, 8000);
	smp_cnt = 0;
	bit_len = opt_int("-b", ac, av, 8);
	if(bit_len != 8 && bit_len != 16) ERR("bit_len");
	sign = (opt_idx("-s", ac, av) >= 0);
	
	// コマンドライン・パラメータ中に -s 指定があるか探索
	// -s があれば、変数 sign に 1 を、
	// -s がなかったら、変数 sign に 0 を設定する
	//
	// デフォルトの設定を、符号なし(sign = 0)としているので、
	// -u : 符号なし
	// の指定は、特に処理する必要がなかった
	// -u が存在しても無視するだけ
	
	note_buf_init();

	div4 = header();

	if(!rd_str_chk(4, "MTrk")) ERR("track id");
	v = rd_int(4); /* skip */

	hi = low = 0;
	delta_sum = 0;
	while((v = rd_delta()) != EOF){
		delta_sum += v;
		sec = (double)delta_sum / div4 * 0.5;
		
		if((v = rd()) & 0x80){
			hi = (v >> 4) & 0xf;
			low  = v & 0xf;
		}else bk(v);

		switch(hi){
		case 8:
		case 9:
			note = rd();
			rd(); /* skip velo */
			note_onoff(hi == 9, sec, low, note);
			break;
		case 0xa:
		case 0xb:
		case 0xe:
			rd();
			rd();
			break;
		case 0xc:		
		case 0xd:
			rd();
			break;
		case 0xf:
			rd();
			switch(low){
			case 0:
				while(rd() != 0xf7);
				break;
			case 1:
			case 3:
				rd();
				break;
			case 2:
				rd();
				rd();
				break;
			case 0xf:
				n = rd();
				for(i=0; i<n; i++) rd();
				break;
			default:
				break;
			}
			break;
		}
	}
	return 0;
}

/* EOF */


prog_onoff_sin7.c 解説

prog_onoff_sin6.c からの変更箇所のみ

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <math.h>

#define MSG(s) fprintf(stderr, "%s() %s L%d : %s\n", __func__, __FILE__, __LINE__, s)
#define ERR(s) do{ fprintf(stderr, "ERR "); MSG(s); exit(1); }while(0)

int bk_buf = -1;

int
rd(void)
{
	int v;

	if((v = bk_buf) < 0) return getchar();
	bk_buf = -1;
	return v;
}

void
bk(int v)
{
	if(bk_buf >= 0) ERR("give up");
	bk_buf = v;
}

void
rd_str(int n, char *s)
{
	int i;

	for(i=0; i<n; i++) s[i] = rd();
	s[i] = '\0';
}

int
rd_str_chk(int n, char *s)
{
	char buf[256];

	rd_str(n, buf);
	return strcmp(buf, s) == 0;
}

int
rd_int(int n) /* big endian */
{
	int i, v;

	v = 0;
	for(i=0; i<n; i++) v = (v << 8) | rd();
	return v;
}

int
rd_delta(void)
{
	int v, c;

	v = 0;
	do{
		if((c = rd()) == EOF) return EOF;
		v = (v << 7) | (c & 0x7f);
	}while(c & 0x80);
	return v;
}


#define NOTE_BUF_N	256

struct note_rec{
	int ch;
	int note;
	double on_sec;
} note_buf[NOTE_BUF_N];

int smp_freq, smp_cnt;
int bit_len;
int sign;
int ch_num;

int
note_buf_is_free(int i)
{
	return note_buf[i].ch < 0;
}

void
note_buf_free(int i)
{
	note_buf[i].ch = -1;
}

void
note_buf_init(void)
{
	int i;

	for(i=0; i<NOTE_BUF_N; i++) note_buf_free(i);
}

int
note_buf_search(int ch, int note)
{
	int i;

	for(i=0; i<NOTE_BUF_N; i++) {
		if(note_buf[i].ch == ch && 
		   (ch < 0 || note_buf[i].note == note)) return i;
	}
	return -1;
}

int
header(void)
{
	int v;

	if(!rd_str_chk(4, "MThd")) ERR("header id");
	if(rd_int(4) != 6) ERR("header size");
	if(rd_int(2) != 0) ERR("header format type");
	if(rd_int(2) != 1) ERR("header track num");
	if((v = rd_int(2)) & 0x8000) ERR("header division");
	return v; /* div4 */
}

double
note_to_freq(int note)
{
	return 440 * pow(2, (note - 69) / 12.0);
}

struct out_rec{
	int base;
	int amp;
	int iv_min;
	int iv_max;
} otr;

void
out_init(struct out_rec *ot)
{
	ot->amp = bit_len == 8 ? 127 : 32767;
	ot->base = sign ? 0 : ot->amp + 1;
	ot->iv_min = ot->base - (ot->amp + 1);
	ot->iv_max = ot->base + ot->amp;
}

void
out_do(struct out_rec *ot, double v)
{
	int iv;

	iv = ot->base + (int)(v *ot->amp);
	if(iv > ot->iv_max) iv = ot->iv_max;
	if(iv < ot->iv_min) iv = ot->iv_min;
	switch(bit_len){
	case 8:
		putchar(iv);
		break;
	case 16:
		putchar(iv & 0xff);
		putchar((iv >> 8) & 0xff);
		break;
	}
}

void
note_onoff(int onoff, double evt_sec, int ch, int note)
{
	double v, sec, freq, dsec;
	double vl, vr, pan;
	int i;

	if(ch == 9) return;

	while((sec = (double)smp_cnt / smp_freq) < evt_sec){
		vl = vr = 0;
		for(i=0; i<NOTE_BUF_N; i++){
			if(note_buf_is_free(i)) continue;
			freq = note_to_freq(note_buf[i].note);
			dsec = sec - note_buf[i].on_sec;
			v = sin(2 * M_PI * freq * dsec);
			if(ch_num == 1){
				vl += v;
			}else{
				pan = note_buf[i].ch / 15.0;
				vl += (1 - pan) * v;
				vr += pan * v;
			}
		}
		out_do(&otr, vl / 16);
		if(ch_num > 1) out_do(&otr, vr / 16);
		smp_cnt++;
	}
	if(onoff){
		if((i = note_buf_search(-1, 0)) < 0){
			MSG("note_buf full");
			return;
		}
		note_buf[i].note = note;
		note_buf[i].ch = ch;
		note_buf[i].on_sec = evt_sec;
	}else{
		if((i = note_buf_search(ch, note)) < 0) return;
		note_buf_free(i);
	}
}

int
opt_idx(char *key, int ac, char **av)
{
	int i;

	for(i=1; i<ac; i++) if(strcmp(av[i], key) == 0) return i;
	return -1;
}

int
opt_int(char *key, int ac, char **av, int def)
{
	int i;

	i = opt_idx(key, ac, av);
	if(i < 0 || i+1 >= ac) return def;
	return strtol(av[i+1], NULL, 0);
}

int
main(int ac, char **av)
{
	int div4, delta_sum;
	int i, n, v, hi, low, note;
	double sec;

	smp_freq = opt_int("-r", ac, av, 8000);
	smp_cnt = 0;
	bit_len = opt_int("-b", ac, av, 8);
	if(bit_len != 8 && bit_len != 16) ERR("bit_len");
	sign = (opt_idx("-s", ac, av) >= 0);
	ch_num = opt_int("-c", ac, av, 1);
	out_init(&otr);
	note_buf_init();

	div4 = header();

	if(!rd_str_chk(4, "MTrk")) ERR("track id");
	v = rd_int(4); /* skip */

	hi = low = 0;
	delta_sum = 0;
	while((v = rd_delta()) != EOF){
		delta_sum += v;
		sec = (double)delta_sum / div4 * 0.5;
		
		if((v = rd()) & 0x80){
			hi = (v >> 4) & 0xf;
			low  = v & 0xf;
		}else bk(v);

		switch(hi){
		case 8:
		case 9:
			note = rd();
			rd(); /* skip velo */
			note_onoff(hi == 9, sec, low, note);
			break;
		case 0xa:
		case 0xb:
		case 0xe:
			rd();
			rd();
			break;
		case 0xc:		
		case 0xd:
			rd();
			break;
		case 0xf:
			rd();
			switch(low){
			case 0:
				while(rd() != 0xf7);
				break;
			case 1:
			case 3:
				rd();
				break;
			case 2:
				rd();
				rd();
				break;
			case 0xf:
				n = rd();
				for(i=0; i<n; i++) rd();
				break;
			default:
				break;
			}
			break;
		}
	}
	return 0;
}

/* EOF */


#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <math.h>

#define MSG(s) fprintf(stderr, "%s() %s L%d : %s\n", __func__, __FILE__, __LINE__, s)
#define ERR(s) do{ fprintf(stderr, "ERR "); MSG(s); exit(1); }while(0)

int bk_buf = -1;

int
rd(void)
{
	int v;

	if((v = bk_buf) < 0) return getchar();
	bk_buf = -1;
	return v;
}

void
bk(int v)
{
	if(bk_buf >= 0) ERR("give up");
	bk_buf = v;
}

void
rd_str(int n, char *s)
{
	int i;

	for(i=0; i<n; i++) s[i] = rd();
	s[i] = '\0';
}

int
rd_str_chk(int n, char *s)
{
	char buf[256];

	rd_str(n, buf);
	return strcmp(buf, s) == 0;
}

int
rd_int(int n) /* big endian */
{
	int i, v;

	v = 0;
	for(i=0; i<n; i++) v = (v << 8) | rd();
	return v;
}

int
rd_delta(void)
{
	int v, c;

	v = 0;
	do{
		if((c = rd()) == EOF) return EOF;
		v = (v << 7) | (c & 0x7f);
	}while(c & 0x80);
	return v;
}


#define NOTE_BUF_N	256

struct note_rec{
	int ch;
	int note;
	double on_sec;
} note_buf[NOTE_BUF_N];

int smp_freq, smp_cnt;
int bit_len;
int sign;
int ch_num;
// チャンネル数を保持
// 値 1 は、モノラル
// 値 2 は、ステレオ

int
note_buf_is_free(int i)
{
	return note_buf[i].ch < 0;
}

void
note_buf_free(int i)
{
	note_buf[i].ch = -1;
}

void
note_buf_init(void)
{
	int i;

	for(i=0; i<NOTE_BUF_N; i++) note_buf_free(i);
}

int
note_buf_search(int ch, int note)
{
	int i;

	for(i=0; i<NOTE_BUF_N; i++) {
		if(note_buf[i].ch == ch && 
		   (ch < 0 || note_buf[i].note == note)) return i;
	}
	return -1;
}

int
header(void)
{
	int v;

	if(!rd_str_chk(4, "MThd")) ERR("header id");
	if(rd_int(4) != 6) ERR("header size");
	if(rd_int(2) != 0) ERR("header format type");
	if(rd_int(2) != 1) ERR("header track num");
	if((v = rd_int(2)) & 0x8000) ERR("header division");
	return v; /* div4 */
}

double
note_to_freq(int note)
{
	return 440 * pow(2, (note - 69) / 12.0);
}

struct out_rec{
// データ出力用のワーク情報を構造体 out_rec としてまとめた

	int base;
	// 底上げする値
	// 符号あり (sign == 1) ならば、0
	// 符号なし (sign == 0) ならば、振幅 amp + 1
	
	int amp;
	// 振幅
	// ビット長が 8 なら  (2^8) / 2 - 1
	// ビット長が 16 なら (2^16) / 2 -1
	
	int iv_min;
	// 整数に変換した時の最小値
	// 8 bit 符号なしなら 0
	// 8 bit 符号ありなら -128
	// 16 bit 符号なしなら 0
	// 16 bit 符号ありなら -32768
	
	int iv_max;
	// 整数に変換した時の最大値
	// 8 bit 符号なしなら 255
	// 8 bit 符号ありなら 127
	// 16 bit 符号なしなら 65535
	// 16 bit 符号ありなら 32767
	
} otr;
// 変数 otr として保持

void
out_init(struct out_rec *ot)
{
	// データ出力用のワーク情報を初期化
	//
	// 変数 bit_len, 変数 sign を参照して、
	// 構造体 out_rec の内容を設定する
	
	ot->amp = bit_len == 8 ? 127 : 32767;
	ot->base = sign ? 0 : ot->amp + 1;
	ot->iv_min = ot->base - (ot->amp + 1);
	ot->iv_max = ot->base + ot->amp;
}

void
out_do(struct out_rec *ot, double v)
{
	// データ出力
	//
	// データ出力用のワーク情報を参照して、
	// 引数 v (-1.0〜+1.0) を整数に変換して出力する
	
	int iv;

	iv = ot->base + (int)(v *ot->amp);
	if(iv > ot->iv_max) iv = ot->iv_max;
	if(iv < ot->iv_min) iv = ot->iv_min;
	switch(bit_len){
	case 8:
		putchar(iv);
		break;
	case 16:
		putchar(iv & 0xff);
		putchar((iv >> 8) & 0xff);
		break;
	}
}

void
note_onoff(int onoff, double evt_sec, int ch, int note)
{
	double v, sec, freq, dsec;
	double vl, vr, pan;
	// 左チャンネルの出力用の積算値と、
	// 右チャンネルの出力用の積算値、
	// 変数 pan は、0.0〜1.0 の値をとり、
	// 0.0 なら左側、1.0 なら右側から出力する

	// 従来の変数 iv, base, amp, iv_min, iv_max は、
	// 構造体 out_rec と、out_do() 関数を追加したため不要となった
	
	int i;

	if(ch == 9) return;

	while((sec = (double)smp_cnt / smp_freq) < evt_sec){
		vl = vr = 0;
		// 左右の積算値を 0 で初期化
		// ch_num が 1 (モノラル) の場合、vl のみ使用する
		
		for(i=0; i<NOTE_BUF_N; i++){
			if(note_buf_is_free(i)) continue;
			freq = note_to_freq(note_buf[i].note);
			dsec = sec - note_buf[i].on_sec;
			v = sin(2 * M_PI * freq * dsec);
			// 1つの音の波形の値を、vへ
			//
			// 従来、変数 v は積算値を保持していたが、
			// 積算値は、vl, vr で持するよう変更
			
			if(ch_num == 1){
			// ch_num が 1 (モノラル) の場合
			
				vl += v;
				// 変数 vl へ積算
				
			}else{
			// ch_num が 1 以外 (つまり、2 でステレオ) の場合
			
				pan = note_buf[i].ch / 15.0;
				// 鍵盤のオン情報を記録するバッファの
				// MIDIチャンネルの値 (0〜15) から、
				// 左右に振る値 (0.0 〜 1.0) を算出し、変数 pan へ
				
				vl += (1 - pan) * v;
				// 変数 pan の値から、左チャンネルの出力を算出し、変数 vl へと加算
				
				vr += pan * v;
				// 変数 pan の値から、右チャンネルの出力を算出し、変数 vr へと加算
				
			}
		}
		out_do(&otr, vl / 16);
		// モノラルの場合、全体の出力
		// ステレオの場合、左チャンネルの出力
		// out_do() 関数を呼び出して、データ出力する
		
		if(ch_num > 1) out_do(&otr, vr / 16);
		// ステレオの場合、右チャンネルの出力
		// out_do() 関数を呼び出して、データ出力する
		
		smp_cnt++;
	}
	if(onoff){
		if((i = note_buf_search(-1, 0)) < 0){
			MSG("note_buf full");
			return;
		}
		note_buf[i].note = note;
		note_buf[i].ch = ch;
		note_buf[i].on_sec = evt_sec;
	}else{
		if((i = note_buf_search(ch, note)) < 0) return;
		note_buf_free(i);
	}
}

int
opt_idx(char *key, int ac, char **av)
{
	int i;

	for(i=1; i<ac; i++) if(strcmp(av[i], key) == 0) return i;
	return -1;
}

int
opt_int(char *key, int ac, char **av, int def)
{
	int i;

	i = opt_idx(key, ac, av);
	if(i < 0 || i+1 >= ac) return def;
	return strtol(av[i+1], NULL, 0);
}

int
main(int ac, char **av)
{
	int div4, delta_sum;
	int i, n, v, hi, low, note;
	double sec;

	smp_freq = opt_int("-r", ac, av, 8000);
	smp_cnt = 0;
	bit_len = opt_int("-b", ac, av, 8);
	if(bit_len != 8 && bit_len != 16) ERR("bit_len");
	sign = (opt_idx("-s", ac, av) >= 0);
	ch_num = opt_int("-c", ac, av, 1);
	// コマンドライン・パラメータで指定された整数を取得する
	// -c <チャンネル数 (1 or 2)>
	// として指定された整数を取得し、変数 ch_num へ設定
	// コマンドラインで指定が無かった場合は、
	// デフォルト値 1 を設定
	
	out_init(&otr);
	// データ出力用のワーク情報を初期化
	
	note_buf_init();

	div4 = header();

	if(!rd_str_chk(4, "MTrk")) ERR("track id");
	v = rd_int(4); /* skip */

	hi = low = 0;
	delta_sum = 0;
	while((v = rd_delta()) != EOF){
		delta_sum += v;
		sec = (double)delta_sum / div4 * 0.5;
		
		if((v = rd()) & 0x80){
			hi = (v >> 4) & 0xf;
			low  = v & 0xf;
		}else bk(v);

		switch(hi){
		case 8:
		case 9:
			note = rd();
			rd(); /* skip velo */
			note_onoff(hi == 9, sec, low, note);
			break;
		case 0xa:
		case 0xb:
		case 0xe:
			rd();
			rd();
			break;
		case 0xc:		
		case 0xd:
			rd();
			break;
		case 0xf:
			rd();
			switch(low){
			case 0:
				while(rd() != 0xf7);
				break;
			case 1:
			case 3:
				rd();
				break;
			case 2:
				rd();
				rd();
				break;
			case 0xf:
				n = rd();
				for(i=0; i<n; i++) rd();
				break;
			default:
				break;
			}
			break;
		}
	}
	return 0;
}

/* EOF */


prog_onoff_sin8.c 解説

prog_onoff_sin7.c からの変更箇所のみ

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <math.h>

#define MSG(s) fprintf(stderr, "%s() %s L%d : %s\n", __func__, __FILE__, __LINE__, s)
#define ERR(s) do{ fprintf(stderr, "ERR "); MSG(s); exit(1); }while(0)

int bk_buf = -1;

int
rd(void)
{
	int v;

	if((v = bk_buf) < 0) return getchar();
	bk_buf = -1;
	return v;
}

void
bk(int v)
{
	if(bk_buf >= 0) ERR("give up");
	bk_buf = v;
}

void
rd_str(int n, char *s)
{
	int i;

	for(i=0; i<n; i++) s[i] = rd();
	s[i] = '\0';
}

int
rd_str_chk(int n, char *s)
{
	char buf[256];

	rd_str(n, buf);
	return strcmp(buf, s) == 0;
}

int
rd_int(int n) /* big endian */
{
	int i, v;

	v = 0;
	for(i=0; i<n; i++) v = (v << 8) | rd();
	return v;
}

int
rd_delta(void)
{
	int v, c;

	v = 0;
	do{
		if((c = rd()) == EOF) return EOF;
		v = (v << 7) | (c & 0x7f);
	}while(c & 0x80);
	return v;
}


#define NOTE_BUF_N	256

struct note_rec{
	int ch;
	int note;
	int onoff;
	double on_sec;
	double off_sec;
} note_buf[NOTE_BUF_N];

int smp_freq, smp_cnt;
int bit_len;
int sign;
int ch_num;

int
note_buf_is_free(int i)
{
	return note_buf[i].ch < 0;
}

void
note_buf_free(int i)
{
	note_buf[i].ch = -1;
}

void
note_buf_init(void)
{
	int i;

	for(i=0; i<NOTE_BUF_N; i++) note_buf_free(i);
}

int
note_buf_search(int ch, int note, int onoff)
{
	int i;

	for(i=0; i<NOTE_BUF_N; i++) {
		if( (ch < 0 && note_buf[i].ch < 0) ||
		    (note_buf[i].ch == ch &&
		     note_buf[i].note == note &&
		     note_buf[i].onoff == onoff) ) return i;
	}
	return -1;
}

int
header(void)
{
	int v;

	if(!rd_str_chk(4, "MThd")) ERR("header id");
	if(rd_int(4) != 6) ERR("header size");
	if(rd_int(2) != 0) ERR("header format type");
	if(rd_int(2) != 1) ERR("header track num");
	if((v = rd_int(2)) & 0x8000) ERR("header division");
	return v; /* div4 */
}

double
note_to_freq(int note)
{
	return 440 * pow(2, (note - 69) / 12.0);
}

struct out_rec{
	int base;
	int amp;
	int iv_min;
	int iv_max;
} otr;

void
out_init(struct out_rec *ot)
{
	ot->amp = bit_len == 8 ? 127 : 32767;
	ot->base = sign ? 0 : ot->amp + 1;
	ot->iv_min = ot->base - (ot->amp + 1);
	ot->iv_max = ot->base + ot->amp;
}

void
out_do(struct out_rec *ot, double v)
{
	int iv;

	iv = ot->base + (int)(v *ot->amp);
	if(iv > ot->iv_max) iv = ot->iv_max;
	if(iv < ot->iv_min) iv = ot->iv_min;
	switch(bit_len){
	case 8:
		putchar(iv);
		break;
	case 16:
		putchar(iv & 0xff);
		putchar((iv >> 8) & 0xff);
		break;
	}
}

void
note_onoff(int onoff, double evt_sec, int ch, int note)
{
	double v, sec, freq, dsec;
	double vl, vr, pan;
	double release;
	int i;

	if(ch == 9) return;

	release = 0.3;
	while((sec = (double)smp_cnt / smp_freq) < evt_sec){
		vl = vr = 0;
		for(i=0; i<NOTE_BUF_N; i++){
			if(note_buf_is_free(i)) continue;
			freq = note_to_freq(note_buf[i].note);
			dsec = sec - note_buf[i].on_sec;
			v = sin(2 * M_PI * freq * dsec);
			if(note_buf[i].onoff == 0){
				dsec = sec - note_buf[i].off_sec;
				v *= 1 - dsec / release;
				if(dsec >= release) note_buf_free(i);
			}
			if(ch_num == 1){
				vl += v;
			}else{
				pan = note_buf[i].ch / 15.0;
				vl += (1 - pan) * v;
				vr += pan * v;
			}
		}
		out_do(&otr, vl / 16);
		if(ch_num > 1) out_do(&otr, vr / 16);
		smp_cnt++;
	}
	if(onoff){
		if((i = note_buf_search(-1, -1, -1)) < 0){
			MSG("note_buf full");
			return;
		}
		note_buf[i].note = note;
		note_buf[i].ch = ch;
		note_buf[i].onoff = 1;
		note_buf[i].on_sec = evt_sec;
	}else{
		if((i = note_buf_search(ch, note, 1)) < 0) return;
		note_buf[i].onoff = 0;
		note_buf[i].off_sec = evt_sec;
	}
}

int
opt_idx(char *key, int ac, char **av)
{
	int i;

	for(i=1; i<ac; i++) if(strcmp(av[i], key) == 0) return i;
	return -1;
}

int
opt_int(char *key, int ac, char **av, int def)
{
	int i;

	i = opt_idx(key, ac, av);
	if(i < 0 || i+1 >= ac) return def;
	return strtol(av[i+1], NULL, 0);
}

int
main(int ac, char **av)
{
	int div4, delta_sum;
	int i, n, v, hi, low, note;
	double sec;

	smp_freq = opt_int("-r", ac, av, 8000);
	smp_cnt = 0;
	bit_len = opt_int("-b", ac, av, 8);
	if(bit_len != 8 && bit_len != 16) ERR("bit_len");
	sign = (opt_idx("-s", ac, av) >= 0);
	ch_num = opt_int("-c", ac, av, 1);
	out_init(&otr);
	note_buf_init();

	div4 = header();

	if(!rd_str_chk(4, "MTrk")) ERR("track id");
	v = rd_int(4); /* skip */

	hi = low = 0;
	delta_sum = 0;
	while((v = rd_delta()) != EOF){
		delta_sum += v;
		sec = (double)delta_sum / div4 * 0.5;
		
		if((v = rd()) & 0x80){
			hi = (v >> 4) & 0xf;
			low  = v & 0xf;
		}else bk(v);

		switch(hi){
		case 8:
		case 9:
			note = rd();
			rd(); /* skip velo */
			note_onoff(hi == 9, sec, low, note);
			break;
		case 0xa:
		case 0xb:
		case 0xe:
			rd();
			rd();
			break;
		case 0xc:		
		case 0xd:
			rd();
			break;
		case 0xf:
			rd();
			switch(low){
			case 0:
				while(rd() != 0xf7);
				break;
			case 1:
			case 3:
				rd();
				break;
			case 2:
				rd();
				rd();
				break;
			case 0xf:
				n = rd();
				for(i=0; i<n; i++) rd();
				break;
			default:
				break;
			}
			break;
		}
	}
	return 0;
}

/* EOF */


#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <math.h>

#define MSG(s) fprintf(stderr, "%s() %s L%d : %s\n", __func__, __FILE__, __LINE__, s)
#define ERR(s) do{ fprintf(stderr, "ERR "); MSG(s); exit(1); }while(0)

int bk_buf = -1;

int
rd(void)
{
	int v;

	if((v = bk_buf) < 0) return getchar();
	bk_buf = -1;
	return v;
}

void
bk(int v)
{
	if(bk_buf >= 0) ERR("give up");
	bk_buf = v;
}

void
rd_str(int n, char *s)
{
	int i;

	for(i=0; i<n; i++) s[i] = rd();
	s[i] = '\0';
}

int
rd_str_chk(int n, char *s)
{
	char buf[256];

	rd_str(n, buf);
	return strcmp(buf, s) == 0;
}

int
rd_int(int n) /* big endian */
{
	int i, v;

	v = 0;
	for(i=0; i<n; i++) v = (v << 8) | rd();
	return v;
}

int
rd_delta(void)
{
	int v, c;

	v = 0;
	do{
		if((c = rd()) == EOF) return EOF;
		v = (v << 7) | (c & 0x7f);
	}while(c & 0x80);
	return v;
}


#define NOTE_BUF_N	256

struct note_rec{
	int ch;
	int note;
	int onoff;
	// 鍵盤のオン・オフの状態
	// 鍵盤のオンならば、1
	// 鍵盤のオフならば、0
	
	double on_sec;
	double off_sec;
	// 鍵盤をオフにした時の時刻(秒)
	
} note_buf[NOTE_BUF_N];

int smp_freq, smp_cnt;
int bit_len;
int sign;
int ch_num;

int
note_buf_is_free(int i)
{
	return note_buf[i].ch < 0;
}

void
note_buf_free(int i)
{
	note_buf[i].ch = -1;
}

void
note_buf_init(void)
{
	int i;

	for(i=0; i<NOTE_BUF_N; i++) note_buf_free(i);
}

int
note_buf_search(int ch, int note, int onoff)
{
	// 鍵盤のオン情報を記録するバッファの探索
	//
	// 引数 onoff を追加
	// 引数 ch が負の場合の処理を、若干修正
	//
	// 以下、修正後の仕様
	//
	// 引数 ch で指定したMIDIチャンネル
	// 引数 note で指定した鍵盤の位置
	// 引数 onoff で指定した鍵盤の状態 (オン=1, オフ=0)
	// を保持しているバッファを探索し、
	// そのバッファのインデックスを返す
	//
	// ただし、引数 ch に負の値が指定された場合は、
	// その他の引数は無視し、
	// MIDIチャンネルが負のバッファ(つまり解放されているバッファ)
	// のインデックスを返す
	
	int i;

	for(i=0; i<NOTE_BUF_N; i++) {
		if( (ch < 0 && note_buf[i].ch < 0) ||
		    (note_buf[i].ch == ch &&
		     note_buf[i].note == note &&
		     note_buf[i].onoff == onoff) ) return i;
	}
	return -1;
}

int
header(void)
{
	int v;

	if(!rd_str_chk(4, "MThd")) ERR("header id");
	if(rd_int(4) != 6) ERR("header size");
	if(rd_int(2) != 0) ERR("header format type");
	if(rd_int(2) != 1) ERR("header track num");
	if((v = rd_int(2)) & 0x8000) ERR("header division");
	return v; /* div4 */
}

double
note_to_freq(int note)
{
	return 440 * pow(2, (note - 69) / 12.0);
}

struct out_rec{
	int base;
	int amp;
	int iv_min;
	int iv_max;
} otr;

void
out_init(struct out_rec *ot)
{
	ot->amp = bit_len == 8 ? 127 : 32767;
	ot->base = sign ? 0 : ot->amp + 1;
	ot->iv_min = ot->base - (ot->amp + 1);
	ot->iv_max = ot->base + ot->amp;
}

void
out_do(struct out_rec *ot, double v)
{
	int iv;

	iv = ot->base + (int)(v *ot->amp);
	if(iv > ot->iv_max) iv = ot->iv_max;
	if(iv < ot->iv_min) iv = ot->iv_min;
	switch(bit_len){
	case 8:
		putchar(iv);
		break;
	case 16:
		putchar(iv & 0xff);
		putchar((iv >> 8) & 0xff);
		break;
	}
}

void
note_onoff(int onoff, double evt_sec, int ch, int note)
{
	double v, sec, freq, dsec;
	double vl, vr, pan;
	double release;
	// リリース・タイム(秒)
	
	int i;

	if(ch == 9) return;

	release = 0.3;
	// リリース・タイムを、0.3 秒に設定
	
	while((sec = (double)smp_cnt / smp_freq) < evt_sec){
		vl = vr = 0;
		for(i=0; i<NOTE_BUF_N; i++){
			if(note_buf_is_free(i)) continue;
			freq = note_to_freq(note_buf[i].note);
			dsec = sec - note_buf[i].on_sec;
			v = sin(2 * M_PI * freq * dsec);
			if(note_buf[i].onoff == 0){
			// 鍵盤オフの場合
			
				dsec = sec - note_buf[i].off_sec;
				// 鍵盤オフにしてからの経過時間(秒)を算出し、dsecへ
				
				v *= 1 - dsec / release;
				// リリース時の振幅を算出し、波形の値 v にかけ算
				
				if(dsec >= release) note_buf_free(i);
				// 変数 release に設定されている、リリース・タイム(秒)を
				// 超過していたら、鍵盤情報を記録しているバッファを解放
				
			}
			if(ch_num == 1){
				vl += v;
			}else{
				pan = note_buf[i].ch / 15.0;
				vl += (1 - pan) * v;
				vr += pan * v;
			}
		}
		out_do(&otr, vl / 16);
		if(ch_num > 1) out_do(&otr, vr / 16);
		smp_cnt++;
	}
	if(onoff){
		if((i = note_buf_search(-1, -1, -1)) < 0){
		// note_buf_search() 関数の引数追加にともない、
		// 呼び出し時の引数を追加
		// 空きバッファの探索なので、先頭の引数の値のみ意味がある
		
			MSG("note_buf full");
			return;
		}
		note_buf[i].note = note;
		note_buf[i].ch = ch;
		note_buf[i].onoff = 1;
		// 鍵盤情報バッファに、鍵盤オン・オフ情報として、
		// オン=1 を記録
		
		note_buf[i].on_sec = evt_sec;
	}else{
		if((i = note_buf_search(ch, note, 1)) < 0) return;
		// 鍵盤情報を記録するバッファを探索
		//
		// 引数 ch のMIDIチャンネル、
		// 引数 note のノート番号、
		// 鍵盤オンの状態をもつバッファを探し、
		// そのインデックスを変数 i へ
		
		note_buf[i].onoff = 0;
		// 鍵盤情報バッファに、鍵盤オン・オフ情報として、
		// オフ=0 を記録
		
		note_buf[i].off_sec = evt_sec;
		// 鍵盤をオフにした時の時刻(秒)
		// を記録
		
	}
}

int
opt_idx(char *key, int ac, char **av)
{
	int i;

	for(i=1; i<ac; i++) if(strcmp(av[i], key) == 0) return i;
	return -1;
}

int
opt_int(char *key, int ac, char **av, int def)
{
	int i;

	i = opt_idx(key, ac, av);
	if(i < 0 || i+1 >= ac) return def;
	return strtol(av[i+1], NULL, 0);
}

int
main(int ac, char **av)
{
	int div4, delta_sum;
	int i, n, v, hi, low, note;
	double sec;

	smp_freq = opt_int("-r", ac, av, 8000);
	smp_cnt = 0;
	bit_len = opt_int("-b", ac, av, 8);
	if(bit_len != 8 && bit_len != 16) ERR("bit_len");
	sign = (opt_idx("-s", ac, av) >= 0);
	ch_num = opt_int("-c", ac, av, 1);
	out_init(&otr);
	note_buf_init();

	div4 = header();

	if(!rd_str_chk(4, "MTrk")) ERR("track id");
	v = rd_int(4); /* skip */

	hi = low = 0;
	delta_sum = 0;
	while((v = rd_delta()) != EOF){
		delta_sum += v;
		sec = (double)delta_sum / div4 * 0.5;
		
		if((v = rd()) & 0x80){
			hi = (v >> 4) & 0xf;
			low  = v & 0xf;
		}else bk(v);

		switch(hi){
		case 8:
		case 9:
			note = rd();
			rd(); /* skip velo */
			note_onoff(hi == 9, sec, low, note);
			break;
		case 0xa:
		case 0xb:
		case 0xe:
			rd();
			rd();
			break;
		case 0xc:		
		case 0xd:
			rd();
			break;
		case 0xf:
			rd();
			switch(low){
			case 0:
				while(rd() != 0xf7);
				break;
			case 1:
			case 3:
				rd();
				break;
			case 2:
				rd();
				rd();
				break;
			case 0xf:
				n = rd();
				for(i=0; i<n; i++) rd();
				break;
			default:
				break;
			}
			break;
		}
	}
	return 0;
}

/* EOF */


prog_onoff_sin9.c 解説

prog_onoff_sin8.c からの変更箇所のみ

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <math.h>

#define MSG(s) fprintf(stderr, "%s() %s L%d : %s\n", __func__, __FILE__, __LINE__, s)
#define ERR(s) do{ fprintf(stderr, "ERR "); MSG(s); exit(1); }while(0)

int bk_buf = -1;

int
rd(void)
{
	int v;

	if((v = bk_buf) < 0) return getchar();
	bk_buf = -1;
	return v;
}

void
bk(int v)
{
	if(bk_buf >= 0) ERR("give up");
	bk_buf = v;
}

void
rd_str(int n, char *s)
{
	int i;

	for(i=0; i<n; i++) s[i] = rd();
	s[i] = '\0';
}

int
rd_str_chk(int n, char *s)
{
	char buf[256];

	rd_str(n, buf);
	return strcmp(buf, s) == 0;
}

int
rd_int(int n) /* big endian */
{
	int i, v;

	v = 0;
	for(i=0; i<n; i++) v = (v << 8) | rd();
	return v;
}

int
rd_delta(void)
{
	int v, c;

	v = 0;
	do{
		if((c = rd()) == EOF) return EOF;
		v = (v << 7) | (c & 0x7f);
	}while(c & 0x80);
	return v;
}


#define NOTE_BUF_N	256

struct note_rec{
	int ch;
	int note;
	int onoff;
	double on_sec;
	double off_sec;
} note_buf[NOTE_BUF_N];

int
note_buf_is_free(int i)
{
	return note_buf[i].ch < 0;
}

void
note_buf_free(int i)
{
	note_buf[i].ch = -1;
}

void
note_buf_init(void)
{
	int i;

	for(i=0; i<NOTE_BUF_N; i++) note_buf_free(i);
}

int
note_buf_search(int ch, int note, int onoff)
{
	int i;

	for(i=0; i<NOTE_BUF_N; i++) {
		if( (ch < 0 && note_buf[i].ch < 0) ||
		    (note_buf[i].ch == ch &&
		     note_buf[i].note == note &&
		     note_buf[i].onoff == onoff) ) return i;
	}
	return -1;
}

int
header(void)
{
	int v;

	if(!rd_str_chk(4, "MThd")) ERR("header id");
	if(rd_int(4) != 6) ERR("header size");
	if(rd_int(2) != 0) ERR("header format type");
	if(rd_int(2) != 1) ERR("header track num");
	if((v = rd_int(2)) & 0x8000) ERR("header division");
	return v; /* div4 */
}

double
note_to_freq(int note)
{
	return 440 * pow(2, (note - 69) / 12.0);
}

int
opt_idx(char *key, int ac, char **av)
{
	int i;

	for(i=1; i<ac; i++) if(strcmp(av[i], key) == 0) return i;
	return -1;
}

int
opt_int(char *key, int ac, char **av, int def)
{
	int i;

	i = opt_idx(key, ac, av);
	if(i < 0 || i+1 >= ac) return def;
	return strtol(av[i+1], NULL, 0);
}

struct out_rec{
	int smp_freq, smp_cnt;
	int bit_len;
	int sign;
	int ch_num;

	int base;
	int amp;
	int iv_min;
	int iv_max;
};

void
out_init(struct out_rec *ot, int ac, char **av)
{
	ot->smp_freq = opt_int("-r", ac, av, 8000);
	ot->smp_cnt = 0;
	ot->bit_len = opt_int("-b", ac, av, 8);
	if(ot->bit_len != 8 && ot->bit_len != 16) ERR("bit_len");
	ot->sign = (opt_idx("-s", ac, av) >= 0);
	ot->ch_num = opt_int("-c", ac, av, 1);

	ot->amp = ot->bit_len == 8 ? 127 : 32767;
	ot->base = ot->sign ? 0 : ot->amp + 1;
	ot->iv_min = ot->base - (ot->amp + 1);
	ot->iv_max = ot->base + ot->amp;
}

void
out_do(struct out_rec *ot, double v)
{
	int iv;

	iv = ot->base + (int)(v *ot->amp);
	if(iv > ot->iv_max) iv = ot->iv_max;
	if(iv < ot->iv_min) iv = ot->iv_min;
	switch(ot->bit_len){
	case 8:
		putchar(iv);
		break;
	case 16:
		putchar(iv & 0xff);
		putchar((iv >> 8) & 0xff);
		break;
	}
}

void
note_onoff(struct out_rec *ot, int onoff, double evt_sec, int ch, int note)
{
	double v, sec, freq, dsec;
	double vl, vr, pan;
	double release;
	int i;

	if(ch == 9) return;

	release = 0.3;
	while((sec = (double)ot->smp_cnt / ot->smp_freq) < evt_sec){
		vl = vr = 0;
		for(i=0; i<NOTE_BUF_N; i++){
			if(note_buf_is_free(i)) continue;
			freq = note_to_freq(note_buf[i].note);
			dsec = sec - note_buf[i].on_sec;
			v = sin(2 * M_PI * freq * dsec);
			if(note_buf[i].onoff == 0){
				dsec = sec - note_buf[i].off_sec;
				v *= 1 - dsec / release;
				if(dsec >= release) note_buf_free(i);
			}
			if(ot->ch_num == 1){
				vl += v;
			}else{
				pan = note_buf[i].ch / 15.0;
				vl += (1 - pan) * v;
				vr += pan * v;
			}
		}
		out_do(ot, vl / 16);
		if(ot->ch_num > 1) out_do(ot, vr / 16);
		ot->smp_cnt++;
	}
	if(onoff){
		if((i = note_buf_search(-1, -1, -1)) < 0){
			MSG("note_buf full");
			return;
		}
		note_buf[i].note = note;
		note_buf[i].ch = ch;
		note_buf[i].onoff = 1;
		note_buf[i].on_sec = evt_sec;
	}else{
		if((i = note_buf_search(ch, note, 1)) < 0) return;
		note_buf[i].onoff = 0;
		note_buf[i].off_sec = evt_sec;
	}
}

int
main(int ac, char **av)
{
	int div4, delta_sum;
	int i, n, v, hi, low, note;
	double sec;
	struct out_rec otr;

	out_init(&otr, ac, av);
	note_buf_init();

	div4 = header();

	if(!rd_str_chk(4, "MTrk")) ERR("track id");
	v = rd_int(4); /* skip */

	hi = low = 0;
	delta_sum = 0;
	while((v = rd_delta()) != EOF){
		delta_sum += v;
		sec = (double)delta_sum / div4 * 0.5;
		
		if((v = rd()) & 0x80){
			hi = (v >> 4) & 0xf;
			low  = v & 0xf;
		}else bk(v);

		switch(hi){
		case 8:
		case 9:
			note = rd();
			rd(); /* skip velo */
			note_onoff(&otr, hi == 9, sec, low, note);
			break;
		case 0xa:
		case 0xb:
		case 0xe:
			rd();
			rd();
			break;
		case 0xc:		
		case 0xd:
			rd();
			break;
		case 0xf:
			rd();
			switch(low){
			case 0:
				while(rd() != 0xf7);
				break;
			case 1:
			case 3:
				rd();
				break;
			case 2:
				rd();
				rd();
				break;
			case 0xf:
				n = rd();
				for(i=0; i<n; i++) rd();
				break;
			default:
				break;
			}
			break;
		}
	}
	return 0;
}

/* EOF */


#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <math.h>

#define MSG(s) fprintf(stderr, "%s() %s L%d : %s\n", __func__, __FILE__, __LINE__, s)
#define ERR(s) do{ fprintf(stderr, "ERR "); MSG(s); exit(1); }while(0)

int bk_buf = -1;

int
rd(void)
{
	int v;

	if((v = bk_buf) < 0) return getchar();
	bk_buf = -1;
	return v;
}

void
bk(int v)
{
	if(bk_buf >= 0) ERR("give up");
	bk_buf = v;
}

void
rd_str(int n, char *s)
{
	int i;

	for(i=0; i<n; i++) s[i] = rd();
	s[i] = '\0';
}

int
rd_str_chk(int n, char *s)
{
	char buf[256];

	rd_str(n, buf);
	return strcmp(buf, s) == 0;
}

int
rd_int(int n) /* big endian */
{
	int i, v;

	v = 0;
	for(i=0; i<n; i++) v = (v << 8) | rd();
	return v;
}

int
rd_delta(void)
{
	int v, c;

	v = 0;
	do{
		if((c = rd()) == EOF) return EOF;
		v = (v << 7) | (c & 0x7f);
	}while(c & 0x80);
	return v;
}


#define NOTE_BUF_N	256

struct note_rec{
	int ch;
	int note;
	int onoff;
	double on_sec;
	double off_sec;
} note_buf[NOTE_BUF_N];

int
note_buf_is_free(int i)
{
	return note_buf[i].ch < 0;
}

void
note_buf_free(int i)
{
	note_buf[i].ch = -1;
}

void
note_buf_init(void)
{
	int i;

	for(i=0; i<NOTE_BUF_N; i++) note_buf_free(i);
}

int
note_buf_search(int ch, int note, int onoff)
{
	int i;

	for(i=0; i<NOTE_BUF_N; i++) {
		if( (ch < 0 && note_buf[i].ch < 0) ||
		    (note_buf[i].ch == ch &&
		     note_buf[i].note == note &&
		     note_buf[i].onoff == onoff) ) return i;
	}
	return -1;
}

int
header(void)
{
	int v;

	if(!rd_str_chk(4, "MThd")) ERR("header id");
	if(rd_int(4) != 6) ERR("header size");
	if(rd_int(2) != 0) ERR("header format type");
	if(rd_int(2) != 1) ERR("header track num");
	if((v = rd_int(2)) & 0x8000) ERR("header division");
	return v; /* div4 */
}

double
note_to_freq(int note)
{
	return 440 * pow(2, (note - 69) / 12.0);
}

int
opt_idx(char *key, int ac, char **av)
{
	// out_init() から呼び出すので、
	// 場所を out_init() の前に移動
	
	int i;

	for(i=1; i<ac; i++) if(strcmp(av[i], key) == 0) return i;
	return -1;
}

int
opt_int(char *key, int ac, char **av, int def)
{
	// out_init() から呼び出すので、
	// 場所を out_init() の前に移動
	
	int i;

	i = opt_idx(key, ac, av);
	if(i < 0 || i+1 >= ac) return def;
	return strtol(av[i+1], NULL, 0);
}

struct out_rec{
	int smp_freq, smp_cnt;
	int bit_len;
	int sign;
	int ch_num;
	// グローバル変数だった
	// smp_freq, smp_cnt, bit_len, sign, ch_num を
	// 構造体 out_rec のメンバとした
	
	int base;
	int amp;
	int iv_min;
	int iv_max;
};
// グローバル変数 otr はやめて
// main() 関数のローカル変数として otr を持たせるよう変更

void
out_init(struct out_rec *ot, int ac, char **av)
{
	// 引数に main() 関数の引数 ac, av を追加
	
	ot->smp_freq = opt_int("-r", ac, av, 8000);
	ot->smp_cnt = 0;
	ot->bit_len = opt_int("-b", ac, av, 8);
	if(ot->bit_len != 8 && ot->bit_len != 16) ERR("bit_len");
	ot->sign = (opt_idx("-s", ac, av) >= 0);
	ot->ch_num = opt_int("-c", ac, av, 1);
	// main() 関数内で、グローバル変数への設定としてた処理を、
	// 構造体のメンバへ設定するよう変更
	
	ot->amp = ot->bit_len == 8 ? 127 : 32767;
	ot->base = ot->sign ? 0 : ot->amp + 1;
	ot->iv_min = ot->base - (ot->amp + 1);
	ot->iv_max = ot->base + ot->amp;
}

void
out_do(struct out_rec *ot, double v)
{
	int iv;

	iv = ot->base + (int)(v *ot->amp);
	if(iv > ot->iv_max) iv = ot->iv_max;
	if(iv < ot->iv_min) iv = ot->iv_min;
	switch(ot->bit_len){
	// グローバル変数 bit_len は廃止
	// 構造体 out_rec のメンバ bit_len を参照するよう変更
	
	case 8:
		putchar(iv);
		break;
	case 16:
		putchar(iv & 0xff);
		putchar((iv >> 8) & 0xff);
		break;
	}
}

void
note_onoff(struct out_rec *ot, int onoff, double evt_sec, int ch, int note)
{
	// 先頭の引数として out_rec 構造体 を挿入
	// 以下、これまでグローバル変数 smp_freq, smp_cnt, ch_num
	// へのアクセスは、
	// out_rec 構造体のメンバとしてアクセスするよう変更
	
	double v, sec, freq, dsec;
	double vl, vr, pan;
	double release;
	int i;

	if(ch == 9) return;

	release = 0.3;
	while((sec = (double)ot->smp_cnt / ot->smp_freq) < evt_sec){
		vl = vr = 0;
		for(i=0; i<NOTE_BUF_N; i++){
			if(note_buf_is_free(i)) continue;
			freq = note_to_freq(note_buf[i].note);
			dsec = sec - note_buf[i].on_sec;
			v = sin(2 * M_PI * freq * dsec);
			if(note_buf[i].onoff == 0){
				dsec = sec - note_buf[i].off_sec;
				v *= 1 - dsec / release;
				if(dsec >= release) note_buf_free(i);
			}
			if(ot->ch_num == 1){
				vl += v;
			}else{
				pan = note_buf[i].ch / 15.0;
				vl += (1 - pan) * v;
				vr += pan * v;
			}
		}
		out_do(ot, vl / 16);
		if(ot->ch_num > 1) out_do(ot, vr / 16);
		ot->smp_cnt++;
	}
	if(onoff){
		if((i = note_buf_search(-1, -1, -1)) < 0){
			MSG("note_buf full");
			return;
		}
		note_buf[i].note = note;
		note_buf[i].ch = ch;
		note_buf[i].onoff = 1;
		note_buf[i].on_sec = evt_sec;
	}else{
		if((i = note_buf_search(ch, note, 1)) < 0) return;
		note_buf[i].onoff = 0;
		note_buf[i].off_sec = evt_sec;
	}
}

int
main(int ac, char **av)
{
	int div4, delta_sum;
	int i, n, v, hi, low, note;
	double sec;
	struct out_rec otr;
	// out_rec 構造体を ローカル変数として保持するよう変更
	
	out_init(&otr, ac, av);
	// 引数に ac, av を追加
	
	note_buf_init();

	div4 = header();

	if(!rd_str_chk(4, "MTrk")) ERR("track id");
	v = rd_int(4); /* skip */

	hi = low = 0;
	delta_sum = 0;
	while((v = rd_delta()) != EOF){
		delta_sum += v;
		sec = (double)delta_sum / div4 * 0.5;
		
		if((v = rd()) & 0x80){
			hi = (v >> 4) & 0xf;
			low  = v & 0xf;
		}else bk(v);

		switch(hi){
		case 8:
		case 9:
			note = rd();
			rd(); /* skip velo */
			note_onoff(&otr, hi == 9, sec, low, note);
			// 先頭の引数として out_rec 構造体を挿入
			
			break;
		case 0xa:
		case 0xb:
		case 0xe:
			rd();
			rd();
			break;
		case 0xc:		
		case 0xd:
			rd();
			break;
		case 0xf:
			rd();
			switch(low){
			case 0:
				while(rd() != 0xf7);
				break;
			case 1:
			case 3:
				rd();
				break;
			case 2:
				rd();
				rd();
				break;
			case 0xf:
				n = rd();
				for(i=0; i<n; i++) rd();
				break;
			default:
				break;
			}
			break;
		}
	}
	return 0;
}

/* EOF */


prog_onoff_sin10.c 解説

prog_onoff_sin9.c からの変更箇所のみ

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <math.h>

#define MSG(s) fprintf(stderr, "%s() %s L%d : %s\n", __func__, __FILE__, __LINE__, s)
#define ERR(s) do{ fprintf(stderr, "ERR "); MSG(s); exit(1); }while(0)

int bk_buf = -1;

int
rd(void)
{
	int v;

	if((v = bk_buf) < 0) return getchar();
	bk_buf = -1;
	return v;
}

void
bk(int v)
{
	if(bk_buf >= 0) ERR("give up");
	bk_buf = v;
}

void
rd_str(int n, char *s)
{
	int i;

	for(i=0; i<n; i++) s[i] = rd();
	s[i] = '\0';
}

int
rd_str_chk(int n, char *s)
{
	char buf[256];

	rd_str(n, buf);
	return strcmp(buf, s) == 0;
}

int
rd_int(int n) /* big endian */
{
	int i, v;

	v = 0;
	for(i=0; i<n; i++) v = (v << 8) | rd();
	return v;
}

int
rd_delta(void)
{
	int v, c;

	v = 0;
	do{
		if((c = rd()) == EOF) return EOF;
		v = (v << 7) | (c & 0x7f);
	}while(c & 0x80);
	return v;
}


#define NOTE_BUF_N	256

struct note_rec{
	int ch;
	int note;
	int onoff;
	double on_sec;
	double off_sec;
} note_buf[NOTE_BUF_N];

int
note_buf_is_free(int i)
{
	return note_buf[i].ch < 0;
}

void
note_buf_free(int i)
{
	note_buf[i].ch = -1;
}

void
note_buf_init(void)
{
	int i;

	for(i=0; i<NOTE_BUF_N; i++) note_buf_free(i);
}

int
note_buf_search(int ch, int note, int onoff)
{
	int i;

	for(i=0; i<NOTE_BUF_N; i++) {
		if( (ch < 0 && note_buf[i].ch < 0) ||
		    (note_buf[i].ch == ch &&
		     note_buf[i].note == note &&
		     note_buf[i].onoff == onoff) ) return i;
	}
	return -1;
}

int
header(void)
{
	int v;

	if(!rd_str_chk(4, "MThd")) ERR("header id");
	if(rd_int(4) != 6) ERR("header size");
	if(rd_int(2) != 0) ERR("header format type");
	if(rd_int(2) != 1) ERR("header track num");
	if((v = rd_int(2)) & 0x8000) ERR("header division");
	return v; /* div4 */
}

double
note_to_freq(int note)
{
	return 440 * pow(2, (note - 69) / 12.0);
}

int
opt_idx(char *key, int ac, char **av)
{
	int i;

	for(i=1; i<ac; i++) if(strcmp(av[i], key) == 0) return i;
	return -1;
}

char *
opt_str(char *key, int ac, char **av, char *def)
{
	int i;

	i = opt_idx(key, ac, av);
	if(i < 0 || i+1 >= ac) return def;
	return av[i+1];
}

int
opt_int(char *key, int ac, char **av, int def)
{
	char *s;

	if((s = opt_str(key, ac, av, NULL)) == NULL) return def;
	return strtol(s, NULL, 0);
}

struct out_rec{
	int smp_freq, smp_cnt;
	int bit_len;
	int sign;
	int ch_num;
	FILE *fp;

	int base;
	int amp;
	int iv_min;
	int iv_max;
};

void
out_init(struct out_rec *ot, int ac, char **av)
{
	char cmd[1024], *fn;

	ot->smp_freq = opt_int("-r", ac, av, 8000);
	ot->smp_cnt = 0;
	ot->bit_len = opt_int("-b", ac, av, 8);
	if(ot->bit_len != 8 && ot->bit_len != 16) ERR("bit_len");
	ot->sign = (opt_idx("-s", ac, av) >= 0);
	ot->ch_num = opt_int("-c", ac, av, 1);

	ot->fp = stdout;
	cmd[0] = '\0';
	fn = "";
	if(opt_idx("-play", ac, av) >= 0){
		strcat(cmd, "play");
	}else if(opt_idx("-sox", ac, av) >= 0){
		strcat(cmd, "sox");
		fn = opt_str("-sox", ac, av, "-d");
	}
	if(cmd[0]){
		sprintf(cmd + strlen(cmd), " -t raw -r %d -b %d %s -c %d - %s",
			ot->smp_freq, ot->bit_len,
			ot->sign ? "-s" : "-u",
			ot->ch_num, fn);
		if((ot->fp = popen(cmd, "w")) == NULL) ERR("popen");
	}
	ot->amp = ot->bit_len == 8 ? 127 : 32767;
	ot->base = ot->sign ? 0 : ot->amp + 1;
	ot->iv_min = ot->base - (ot->amp + 1);
	ot->iv_max = ot->base + ot->amp;
}

void
out_do(struct out_rec *ot, double v)
{
	int iv;

	iv = ot->base + (int)(v *ot->amp);
	if(iv > ot->iv_max) iv = ot->iv_max;
	if(iv < ot->iv_min) iv = ot->iv_min;
	switch(ot->bit_len){
	case 8:
		fputc(iv, ot->fp);
		break;
	case 16:
		fputc(iv & 0xff, ot->fp);
		fputc((iv >> 8) & 0xff, ot->fp);
		break;
	}
}

void
note_onoff(struct out_rec *ot, int onoff, double evt_sec, int ch, int note)
{
	double v, sec, freq, dsec;
	double vl, vr, pan;
	double release;
	int i;

	if(ch == 9) return;

	release = 0.3;
	while((sec = (double)ot->smp_cnt / ot->smp_freq) < evt_sec){
		vl = vr = 0;
		for(i=0; i<NOTE_BUF_N; i++){
			if(note_buf_is_free(i)) continue;
			freq = note_to_freq(note_buf[i].note);
			dsec = sec - note_buf[i].on_sec;
			v = sin(2 * M_PI * freq * dsec);
			if(note_buf[i].onoff == 0){
				dsec = sec - note_buf[i].off_sec;
				v *= 1 - dsec / release;
				if(dsec >= release) note_buf_free(i);
			}
			if(ot->ch_num == 1){
				vl += v;
			}else{
				pan = note_buf[i].ch / 15.0;
				vl += (1 - pan) * v;
				vr += pan * v;
			}
		}
		out_do(ot, vl / 16);
		if(ot->ch_num > 1) out_do(ot, vr / 16);
		ot->smp_cnt++;
	}
	if(onoff){
		if((i = note_buf_search(-1, -1, -1)) < 0){
			MSG("note_buf full");
			return;
		}
		note_buf[i].note = note;
		note_buf[i].ch = ch;
		note_buf[i].onoff = 1;
		note_buf[i].on_sec = evt_sec;
	}else{
		if((i = note_buf_search(ch, note, 1)) < 0) return;
		note_buf[i].onoff = 0;
		note_buf[i].off_sec = evt_sec;
	}
}

int
main(int ac, char **av)
{
	int div4, delta_sum;
	int i, n, v, hi, low, note;
	double sec;
	struct out_rec otr;

	out_init(&otr, ac, av);
	note_buf_init();

	div4 = header();

	if(!rd_str_chk(4, "MTrk")) ERR("track id");
	v = rd_int(4); /* skip */

	hi = low = 0;
	delta_sum = 0;
	while((v = rd_delta()) != EOF){
		delta_sum += v;
		sec = (double)delta_sum / div4 * 0.5;
		
		if((v = rd()) & 0x80){
			hi = (v >> 4) & 0xf;
			low  = v & 0xf;
		}else bk(v);

		switch(hi){
		case 8:
		case 9:
			note = rd();
			rd(); /* skip velo */
			note_onoff(&otr, hi == 9, sec, low, note);
			break;
		case 0xa:
		case 0xb:
		case 0xe:
			rd();
			rd();
			break;
		case 0xc:		
		case 0xd:
			rd();
			break;
		case 0xf:
			rd();
			switch(low){
			case 0:
				while(rd() != 0xf7);
				break;
			case 1:
			case 3:
				rd();
				break;
			case 2:
				rd();
				rd();
				break;
			case 0xf:
				n = rd();
				for(i=0; i<n; i++) rd();
				break;
			default:
				break;
			}
			break;
		}
	}
	if(otr.fp != stdout) pclose(otr.fp);
	return 0;
}

/* EOF */


#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <math.h>

#define MSG(s) fprintf(stderr, "%s() %s L%d : %s\n", __func__, __FILE__, __LINE__, s)
#define ERR(s) do{ fprintf(stderr, "ERR "); MSG(s); exit(1); }while(0)

int bk_buf = -1;

int
rd(void)
{
	int v;

	if((v = bk_buf) < 0) return getchar();
	bk_buf = -1;
	return v;
}

void
bk(int v)
{
	if(bk_buf >= 0) ERR("give up");
	bk_buf = v;
}

void
rd_str(int n, char *s)
{
	int i;

	for(i=0; i<n; i++) s[i] = rd();
	s[i] = '\0';
}

int
rd_str_chk(int n, char *s)
{
	char buf[256];

	rd_str(n, buf);
	return strcmp(buf, s) == 0;
}

int
rd_int(int n) /* big endian */
{
	int i, v;

	v = 0;
	for(i=0; i<n; i++) v = (v << 8) | rd();
	return v;
}

int
rd_delta(void)
{
	int v, c;

	v = 0;
	do{
		if((c = rd()) == EOF) return EOF;
		v = (v << 7) | (c & 0x7f);
	}while(c & 0x80);
	return v;
}


#define NOTE_BUF_N	256

struct note_rec{
	int ch;
	int note;
	int onoff;
	double on_sec;
	double off_sec;
} note_buf[NOTE_BUF_N];

int
note_buf_is_free(int i)
{
	return note_buf[i].ch < 0;
}

void
note_buf_free(int i)
{
	note_buf[i].ch = -1;
}

void
note_buf_init(void)
{
	int i;

	for(i=0; i<NOTE_BUF_N; i++) note_buf_free(i);
}

int
note_buf_search(int ch, int note, int onoff)
{
	int i;

	for(i=0; i<NOTE_BUF_N; i++) {
		if( (ch < 0 && note_buf[i].ch < 0) ||
		    (note_buf[i].ch == ch &&
		     note_buf[i].note == note &&
		     note_buf[i].onoff == onoff) ) return i;
	}
	return -1;
}

int
header(void)
{
	int v;

	if(!rd_str_chk(4, "MThd")) ERR("header id");
	if(rd_int(4) != 6) ERR("header size");
	if(rd_int(2) != 0) ERR("header format type");
	if(rd_int(2) != 1) ERR("header track num");
	if((v = rd_int(2)) & 0x8000) ERR("header division");
	return v; /* div4 */
}

double
note_to_freq(int note)
{
	return 440 * pow(2, (note - 69) / 12.0);
}

int
opt_idx(char *key, int ac, char **av)
{
	int i;

	for(i=1; i<ac; i++) if(strcmp(av[i], key) == 0) return i;
	return -1;
}

char *
opt_str(char *key, int ac, char **av, char *def)
{
	// コマンドライン・パラメータで指定された文字列を返す
	//
	// 起動時のコマンドライン中に ...  <対象の文字列> ...
	// の組を探索し、対象の文字列を返す
	//
	// 見つからなければ、指定されたデフォルトの文字列を返す
	//
	// 引数 key は、を指定
	// 引数 ac, av は、main()関数の引数を指定
	// 引数 def は、デフォルト値として返す文字列を指定
	
	int i;

	i = opt_idx(key, ac, av);
	if(i < 0 || i+1 >= ac) return def;
	return av[i+1];
}

int
opt_int(char *key, int ac, char **av, int def)
{
	char *s;

	if((s = opt_str(key, ac, av, NULL)) == NULL) return def;
	return strtol(s, NULL, 0);
	// 機能の変更は無し
	// 追加した opt_str() 関数を使用するように変更
	
}

struct out_rec{
	int smp_freq, smp_cnt;
	int bit_len;
	int sign;
	int ch_num;
	FILE *fp;
	// popen() の返すファイルポインタを保持する
	
	int base;
	int amp;
	int iv_min;
	int iv_max;
};

void
out_init(struct out_rec *ot, int ac, char **av)
{
	char cmd[1024], *fn;
	// cmd[] は、popen() で起動するコマンド文字列用のバッファ
	// fn は、"-sox" オプションに続いて指定される、
	// ファイル名を保持する
	
	ot->smp_freq = opt_int("-r", ac, av, 8000);
	ot->smp_cnt = 0;
	ot->bit_len = opt_int("-b", ac, av, 8);
	if(ot->bit_len != 8 && ot->bit_len != 16) ERR("bit_len");
	ot->sign = (opt_idx("-s", ac, av) >= 0);
	ot->ch_num = opt_int("-c", ac, av, 1);

	ot->fp = stdout;
	// デフォルトの出力先として、標準出力を設定する
	
	cmd[0] = '\0';
	// 起動コマンド用のバッファを空に設定
	
	fn = "";
	// 出力ファイル名の文字列を空に設定
	
	if(opt_idx("-play", ac, av) >= 0){
	// もし、コマンドパラメータに、"-play" 指定があれば
	
		strcat(cmd, "play");
		// 起動コマンド用のバッファに "play" を設定
		
	}else if(opt_idx("-sox", ac, av) >= 0){
	// もし、コマンドパラメータに、"-sox" 指定があれば
	
		strcat(cmd, "sox");
		// 起動コマンド用のバッファに "sox" を設定
		
		fn = opt_str("-sox", ac, av, "-d");
		// "-sox" に続いて指定されるファイル名を、変数 fn へ
		// もしファイル名がなければ、
		// デフォルト値として "-d" が fn に設定される
		
	}
	if(cmd[0]){
	// もし、起動コマンド用のバッファが空でなければ
	
		sprintf(cmd + strlen(cmd), " -t raw -r %d -b %d %s -c %d - %s",
			ot->smp_freq, ot->bit_len,
			ot->sign ? "-s" : "-u",
			ot->ch_num, fn);
		// コマンド起動用のバッファに、オプション指定を追加する
		// cmd + strlen(cmd) で、バッファ文字列 (cmd[]) の末尾位置を指定
		//
		// 追加する文字列は
		//   "<区切り用のスペース> -t raw -r <サンプリング周波数> -b <ビット長>
		//   <符号有無指定 (-u or -s)> -c <出力チャンネル数>
		//    - { fn が空でなければ <出力ファイル名> }"
		
		if((ot->fp = popen(cmd, "w")) == NULL) ERR("popen");
		// 作成したバッファを指定して popen() 関数を実行
		// 起動したコマンドの標準入力へのファイルポインタを、
		// out_rec 構造体のメンバ fp へ設定
		
	}
	ot->amp = ot->bit_len == 8 ? 127 : 32767;
	ot->base = ot->sign ? 0 : ot->amp + 1;
	ot->iv_min = ot->base - (ot->amp + 1);
	ot->iv_max = ot->base + ot->amp;
}

void
out_do(struct out_rec *ot, double v)
{
	int iv;

	iv = ot->base + (int)(v *ot->amp);
	if(iv > ot->iv_max) iv = ot->iv_max;
	if(iv < ot->iv_min) iv = ot->iv_min;
	switch(ot->bit_len){
	case 8:
		fputc(iv, ot->fp);
		// これまで putchar() 関数で、標準出力に書き出していたのを、
		// fputc() 関数で、out_rec 構造体のメンバ fp に保持している
		// ファイルポインタへ出力するように変更
		
		break;
	case 16:
		fputc(iv & 0xff, ot->fp);
		fputc((iv >> 8) & 0xff, ot->fp);
		// これまで putchar() 関数で、標準出力に書き出していたのを、
		// fputc() 関数で、out_rec 構造体のメンバ fp に保持している
		// ファイルポインタへ出力するように変更
		
		break;
	}
}

void
note_onoff(struct out_rec *ot, int onoff, double evt_sec, int ch, int note)
{
	double v, sec, freq, dsec;
	double vl, vr, pan;
	double release;
	int i;

	if(ch == 9) return;

	release = 0.3;
	while((sec = (double)ot->smp_cnt / ot->smp_freq) < evt_sec){
		vl = vr = 0;
		for(i=0; i<NOTE_BUF_N; i++){
			if(note_buf_is_free(i)) continue;
			freq = note_to_freq(note_buf[i].note);
			dsec = sec - note_buf[i].on_sec;
			v = sin(2 * M_PI * freq * dsec);
			if(note_buf[i].onoff == 0){
				dsec = sec - note_buf[i].off_sec;
				v *= 1 - dsec / release;
				if(dsec >= release) note_buf_free(i);
			}
			if(ot->ch_num == 1){
				vl += v;
			}else{
				pan = note_buf[i].ch / 15.0;
				vl += (1 - pan) * v;
				vr += pan * v;
			}
		}
		out_do(ot, vl / 16);
		if(ot->ch_num > 1) out_do(ot, vr / 16);
		ot->smp_cnt++;
	}
	if(onoff){
		if((i = note_buf_search(-1, -1, -1)) < 0){
			MSG("note_buf full");
			return;
		}
		note_buf[i].note = note;
		note_buf[i].ch = ch;
		note_buf[i].onoff = 1;
		note_buf[i].on_sec = evt_sec;
	}else{
		if((i = note_buf_search(ch, note, 1)) < 0) return;
		note_buf[i].onoff = 0;
		note_buf[i].off_sec = evt_sec;
	}
}

int
main(int ac, char **av)
{
	int div4, delta_sum;
	int i, n, v, hi, low, note;
	double sec;
	struct out_rec otr;

	out_init(&otr, ac, av);
	note_buf_init();

	div4 = header();

	if(!rd_str_chk(4, "MTrk")) ERR("track id");
	v = rd_int(4); /* skip */

	hi = low = 0;
	delta_sum = 0;
	while((v = rd_delta()) != EOF){
		delta_sum += v;
		sec = (double)delta_sum / div4 * 0.5;
		
		if((v = rd()) & 0x80){
			hi = (v >> 4) & 0xf;
			low  = v & 0xf;
		}else bk(v);

		switch(hi){
		case 8:
		case 9:
			note = rd();
			rd(); /* skip velo */
			note_onoff(&otr, hi == 9, sec, low, note);
			break;
		case 0xa:
		case 0xb:
		case 0xe:
			rd();
			rd();
			break;
		case 0xc:		
		case 0xd:
			rd();
			break;
		case 0xf:
			rd();
			switch(low){
			case 0:
				while(rd() != 0xf7);
				break;
			case 1:
			case 3:
				rd();
				break;
			case 2:
				rd();
				rd();
				break;
			case 0xf:
				n = rd();
				for(i=0; i<n; i++) rd();
				break;
			default:
				break;
			}
			break;
		}
	}
	if(otr.fp != stdout) pclose(otr.fp);
	// out_rec 構造体のメンバ fp が、stdout と異なれば、
	// popen() で返ったファイルポインタが保持されている
	// pclose() でクローズする
	
	return 0;
}

/* EOF */


prog_onoff_sin11.c 解説

prog_onoff_sin10.c からの変更箇所のみ

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <math.h>

#define MSG(s) fprintf(stderr, "%s() %s L%d : %s\n", __func__, __FILE__, __LINE__, s)
#define ERR(s) do{ fprintf(stderr, "ERR "); MSG(s); exit(1); }while(0)

int bk_buf = -1;

int
rd(void)
{
	int v;

	if((v = bk_buf) < 0) return getchar();
	bk_buf = -1;
	return v;
}

void
bk(int v)
{
	if(bk_buf >= 0) ERR("give up");
	bk_buf = v;
}

void
rd_str(int n, char *s)
{
	int i;

	for(i=0; i<n; i++) s[i] = rd();
	s[i] = '\0';
}

int
rd_str_chk(int n, char *s)
{
	char buf[256];

	rd_str(n, buf);
	return strcmp(buf, s) == 0;
}

int
rd_int(int n) /* big endian */
{
	int i, v;

	v = 0;
	for(i=0; i<n; i++) v = (v << 8) | rd();
	return v;
}

int
rd_delta(void)
{
	int v, c;

	v = 0;
	do{
		if((c = rd()) == EOF) return EOF;
		v = (v << 7) | (c & 0x7f);
	}while(c & 0x80);
	return v;
}


#define NOTE_BUF_N	256

struct note_rec{
	int ch;
	int note;
	int onoff;
	double on_sec;
	double off_sec;
	int velo;
} note_buf[NOTE_BUF_N];

int
note_buf_is_free(int i)
{
	return note_buf[i].ch < 0;
}

void
note_buf_free(int i)
{
	note_buf[i].ch = -1;
}

void
note_buf_init(void)
{
	int i;

	for(i=0; i<NOTE_BUF_N; i++) note_buf_free(i);
}

int
note_buf_search(int ch, int note, int onoff)
{
	int i;

	for(i=0; i<NOTE_BUF_N; i++) {
		if( (ch < 0 && note_buf[i].ch < 0) ||
		    (note_buf[i].ch == ch &&
		     note_buf[i].note == note &&
		     note_buf[i].onoff == onoff) ) return i;
	}
	return -1;
}

int
header(void)
{
	int v;

	if(!rd_str_chk(4, "MThd")) ERR("header id");
	if(rd_int(4) != 6) ERR("header size");
	if(rd_int(2) != 0) ERR("header format type");
	if(rd_int(2) != 1) ERR("header track num");
	if((v = rd_int(2)) & 0x8000) ERR("header division");
	return v; /* div4 */
}

double
note_to_freq(int note)
{
	return 440 * pow(2, (note - 69) / 12.0);
}

int
opt_idx(char *key, int ac, char **av)
{
	int i;

	for(i=1; i<ac; i++) if(strcmp(av[i], key) == 0) return i;
	return -1;
}

char *
opt_str(char *key, int ac, char **av, char *def)
{
	int i;

	i = opt_idx(key, ac, av);
	if(i < 0 || i+1 >= ac) return def;
	return av[i+1];
}

int
opt_int(char *key, int ac, char **av, int def)
{
	char *s;

	if((s = opt_str(key, ac, av, NULL)) == NULL) return def;
	return strtol(s, NULL, 0);
}

struct out_rec{
	int smp_freq, smp_cnt;
	int bit_len;
	int sign;
	int ch_num;
	FILE *fp;

	int base;
	int amp;
	int iv_min;
	int iv_max;
};

void
out_init(struct out_rec *ot, int ac, char **av)
{
	char cmd[1024], *fn;

	ot->smp_freq = opt_int("-r", ac, av, 8000);
	ot->smp_cnt = 0;
	ot->bit_len = opt_int("-b", ac, av, 8);
	if(ot->bit_len != 8 && ot->bit_len != 16) ERR("bit_len");
	ot->sign = (opt_idx("-s", ac, av) >= 0);
	ot->ch_num = opt_int("-c", ac, av, 1);

	ot->fp = stdout;
	cmd[0] = '\0';
	fn = "";
	if(opt_idx("-play", ac, av) >= 0){
		strcat(cmd, "play");
	}else if(opt_idx("-sox", ac, av) >= 0){
		strcat(cmd, "sox");
		fn = opt_str("-sox", ac, av, "-d");
	}
	if(cmd[0]){
		sprintf(cmd + strlen(cmd), " -t raw -r %d -b %d %s -c %d - %s",
			ot->smp_freq, ot->bit_len,
			ot->sign ? "-s" : "-u",
			ot->ch_num, fn);
		if((ot->fp = popen(cmd, "w")) == NULL) ERR("popen");
	}
	ot->amp = ot->bit_len == 8 ? 127 : 32767;
	ot->base = ot->sign ? 0 : ot->amp + 1;
	ot->iv_min = ot->base - (ot->amp + 1);
	ot->iv_max = ot->base + ot->amp;
}

void
out_do(struct out_rec *ot, double v)
{
	int iv;

	iv = ot->base + (int)(v *ot->amp);
	if(iv > ot->iv_max) iv = ot->iv_max;
	if(iv < ot->iv_min) iv = ot->iv_min;
	switch(ot->bit_len){
	case 8:
		fputc(iv, ot->fp);
		break;
	case 16:
		fputc(iv & 0xff, ot->fp);
		fputc((iv >> 8) & 0xff, ot->fp);
		break;
	}
}

void
note_onoff(struct out_rec *ot, int onoff, double evt_sec, int ch, int note, int velo)
{
	double v, sec, freq, dsec;
	double vl, vr, pan;
	double release;
	int i;

	if(ch == 9) return;

	release = 0.3;
	while((sec = (double)ot->smp_cnt / ot->smp_freq) < evt_sec){
		vl = vr = 0;
		for(i=0; i<NOTE_BUF_N; i++){
			if(note_buf_is_free(i)) continue;
			freq = note_to_freq(note_buf[i].note);
			dsec = sec - note_buf[i].on_sec;
			v = sin(2 * M_PI * freq * dsec);
			v *= note_buf[i].velo / 127.0;
			if(note_buf[i].onoff == 0){
				dsec = sec - note_buf[i].off_sec;
				v *= 1 - dsec / release;
				if(dsec >= release) note_buf_free(i);
			}
			if(ot->ch_num == 1){
				vl += v;
			}else{
				pan = note_buf[i].ch / 15.0;
				vl += (1 - pan) * v;
				vr += pan * v;
			}
		}
		out_do(ot, vl / 16);
		if(ot->ch_num > 1) out_do(ot, vr / 16);
		ot->smp_cnt++;
	}
	if(onoff){
		if((i = note_buf_search(-1, -1, -1)) < 0){
			MSG("note_buf full");
			return;
		}
		note_buf[i].note = note;
		note_buf[i].ch = ch;
		note_buf[i].onoff = 1;
		note_buf[i].on_sec = evt_sec;
		note_buf[i].velo = velo;
	}else{
		if((i = note_buf_search(ch, note, 1)) < 0) return;
		note_buf[i].onoff = 0;
		note_buf[i].off_sec = evt_sec;
	}
}

int
main(int ac, char **av)
{
	int div4, delta_sum;
	int i, n, v, hi, low, note, velo;
	double sec;
	struct out_rec otr;

	out_init(&otr, ac, av);
	note_buf_init();

	div4 = header();

	if(!rd_str_chk(4, "MTrk")) ERR("track id");
	v = rd_int(4); /* skip */

	hi = low = 0;
	delta_sum = 0;
	while((v = rd_delta()) != EOF){
		delta_sum += v;
		sec = (double)delta_sum / div4 * 0.5;
		
		if((v = rd()) & 0x80){
			hi = (v >> 4) & 0xf;
			low  = v & 0xf;
		}else bk(v);

		switch(hi){
		case 8:
		case 9:
			note = rd();
			velo = rd();
			note_onoff(&otr, hi == 9, sec, low, note, velo);
			break;
		case 0xa:
		case 0xb:
		case 0xe:
			rd();
			rd();
			break;
		case 0xc:		
		case 0xd:
			rd();
			break;
		case 0xf:
			rd();
			switch(low){
			case 0:
				while(rd() != 0xf7);
				break;
			case 1:
			case 3:
				rd();
				break;
			case 2:
				rd();
				rd();
				break;
			case 0xf:
				n = rd();
				for(i=0; i<n; i++) rd();
				break;
			default:
				break;
			}
			break;
		}
	}
	if(otr.fp != stdout) pclose(otr.fp);
	return 0;
}

/* EOF */


#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <math.h>

#define MSG(s) fprintf(stderr, "%s() %s L%d : %s\n", __func__, __FILE__, __LINE__, s)
#define ERR(s) do{ fprintf(stderr, "ERR "); MSG(s); exit(1); }while(0)

int bk_buf = -1;

int
rd(void)
{
	int v;

	if((v = bk_buf) < 0) return getchar();
	bk_buf = -1;
	return v;
}

void
bk(int v)
{
	if(bk_buf >= 0) ERR("give up");
	bk_buf = v;
}

void
rd_str(int n, char *s)
{
	int i;

	for(i=0; i<n; i++) s[i] = rd();
	s[i] = '\0';
}

int
rd_str_chk(int n, char *s)
{
	char buf[256];

	rd_str(n, buf);
	return strcmp(buf, s) == 0;
}

int
rd_int(int n) /* big endian */
{
	int i, v;

	v = 0;
	for(i=0; i<n; i++) v = (v << 8) | rd();
	return v;
}

int
rd_delta(void)
{
	int v, c;

	v = 0;
	do{
		if((c = rd()) == EOF) return EOF;
		v = (v << 7) | (c & 0x7f);
	}while(c & 0x80);
	return v;
}


#define NOTE_BUF_N	256

struct note_rec{
	int ch;
	int note;
	int onoff;
	double on_sec;
	double off_sec;
	int velo;
	// 鍵盤オン時の速度(強さ) 0〜127
	
} note_buf[NOTE_BUF_N];

int
note_buf_is_free(int i)
{
	return note_buf[i].ch < 0;
}

void
note_buf_free(int i)
{
	note_buf[i].ch = -1;
}

void
note_buf_init(void)
{
	int i;

	for(i=0; i<NOTE_BUF_N; i++) note_buf_free(i);
}

int
note_buf_search(int ch, int note, int onoff)
{
	int i;

	for(i=0; i<NOTE_BUF_N; i++) {
		if( (ch < 0 && note_buf[i].ch < 0) ||
		    (note_buf[i].ch == ch &&
		     note_buf[i].note == note &&
		     note_buf[i].onoff == onoff) ) return i;
	}
	return -1;
}

int
header(void)
{
	int v;

	if(!rd_str_chk(4, "MThd")) ERR("header id");
	if(rd_int(4) != 6) ERR("header size");
	if(rd_int(2) != 0) ERR("header format type");
	if(rd_int(2) != 1) ERR("header track num");
	if((v = rd_int(2)) & 0x8000) ERR("header division");
	return v; /* div4 */
}

double
note_to_freq(int note)
{
	return 440 * pow(2, (note - 69) / 12.0);
}

int
opt_idx(char *key, int ac, char **av)
{
	int i;

	for(i=1; i<ac; i++) if(strcmp(av[i], key) == 0) return i;
	return -1;
}

char *
opt_str(char *key, int ac, char **av, char *def)
{
	int i;

	i = opt_idx(key, ac, av);
	if(i < 0 || i+1 >= ac) return def;
	return av[i+1];
}

int
opt_int(char *key, int ac, char **av, int def)
{
	char *s;

	if((s = opt_str(key, ac, av, NULL)) == NULL) return def;
	return strtol(s, NULL, 0);
}

struct out_rec{
	int smp_freq, smp_cnt;
	int bit_len;
	int sign;
	int ch_num;
	FILE *fp;

	int base;
	int amp;
	int iv_min;
	int iv_max;
};

void
out_init(struct out_rec *ot, int ac, char **av)
{
	char cmd[1024], *fn;

	ot->smp_freq = opt_int("-r", ac, av, 8000);
	ot->smp_cnt = 0;
	ot->bit_len = opt_int("-b", ac, av, 8);
	if(ot->bit_len != 8 && ot->bit_len != 16) ERR("bit_len");
	ot->sign = (opt_idx("-s", ac, av) >= 0);
	ot->ch_num = opt_int("-c", ac, av, 1);

	ot->fp = stdout;
	cmd[0] = '\0';
	fn = "";
	if(opt_idx("-play", ac, av) >= 0){
		strcat(cmd, "play");
	}else if(opt_idx("-sox", ac, av) >= 0){
		strcat(cmd, "sox");
		fn = opt_str("-sox", ac, av, "-d");
	}
	if(cmd[0]){
		sprintf(cmd + strlen(cmd), " -t raw -r %d -b %d %s -c %d - %s",
			ot->smp_freq, ot->bit_len,
			ot->sign ? "-s" : "-u",
			ot->ch_num, fn);
		if((ot->fp = popen(cmd, "w")) == NULL) ERR("popen");
	}
	ot->amp = ot->bit_len == 8 ? 127 : 32767;
	ot->base = ot->sign ? 0 : ot->amp + 1;
	ot->iv_min = ot->base - (ot->amp + 1);
	ot->iv_max = ot->base + ot->amp;
}

void
out_do(struct out_rec *ot, double v)
{
	int iv;

	iv = ot->base + (int)(v *ot->amp);
	if(iv > ot->iv_max) iv = ot->iv_max;
	if(iv < ot->iv_min) iv = ot->iv_min;
	switch(ot->bit_len){
	case 8:
		fputc(iv, ot->fp);
		break;
	case 16:
		fputc(iv & 0xff, ot->fp);
		fputc((iv >> 8) & 0xff, ot->fp);
		break;
	}
}

void
note_onoff(struct out_rec *ot, int onoff, double evt_sec, int ch, int note, int velo)
{
	// 末尾の引数として、鍵盤を動かしたときの速度(強さ)を表す
	//  velo を追加
	// 値は 0〜127
	
	double v, sec, freq, dsec;
	double vl, vr, pan;
	double release;
	int i;

	if(ch == 9) return;

	release = 0.3;
	while((sec = (double)ot->smp_cnt / ot->smp_freq) < evt_sec){
		vl = vr = 0;
		for(i=0; i<NOTE_BUF_N; i++){
			if(note_buf_is_free(i)) continue;
			freq = note_to_freq(note_buf[i].note);
			dsec = sec - note_buf[i].on_sec;
			v = sin(2 * M_PI * freq * dsec);
			v *= note_buf[i].velo / 127.0;
			// 鍵盤情報のバッファに記録されてる
			// 鍵盤オンの強さ(0〜127)を参照
			// 0.0〜1.0 の値に換算し、SIN波出力にかけ算
			
			if(note_buf[i].onoff == 0){
				dsec = sec - note_buf[i].off_sec;
				v *= 1 - dsec / release;
				if(dsec >= release) note_buf_free(i);
			}
			if(ot->ch_num == 1){
				vl += v;
			}else{
				pan = note_buf[i].ch / 15.0;
				vl += (1 - pan) * v;
				vr += pan * v;
			}
		}
		out_do(ot, vl / 16);
		if(ot->ch_num > 1) out_do(ot, vr / 16);
		ot->smp_cnt++;
	}
	if(onoff){
		if((i = note_buf_search(-1, -1, -1)) < 0){
			MSG("note_buf full");
			return;
		}
		note_buf[i].note = note;
		note_buf[i].ch = ch;
		note_buf[i].onoff = 1;
		note_buf[i].on_sec = evt_sec;
		note_buf[i].velo = velo;
		// 鍵盤オン時の速さ(強さ)を構造体に記録
		
	}else{
		if((i = note_buf_search(ch, note, 1)) < 0) return;
		note_buf[i].onoff = 0;
		note_buf[i].off_sec = evt_sec;
	}
}

int
main(int ac, char **av)
{
	int div4, delta_sum;
	int i, n, v, hi, low, note, velo;
	// 変数 velo 追加
	// 鍵盤オン・オフ時の速度(強さ)
	
	double sec;
	struct out_rec otr;

	out_init(&otr, ac, av);
	note_buf_init();

	div4 = header();

	if(!rd_str_chk(4, "MTrk")) ERR("track id");
	v = rd_int(4); /* skip */

	hi = low = 0;
	delta_sum = 0;
	while((v = rd_delta()) != EOF){
		delta_sum += v;
		sec = (double)delta_sum / div4 * 0.5;
		
		if((v = rd()) & 0x80){
			hi = (v >> 4) & 0xf;
			low  = v & 0xf;
		}else bk(v);

		switch(hi){
		case 8:
		case 9:
			note = rd();
			velo = rd();
			// スキップしてた 3バイト目を、
			// 変数 velo に設定するよう変更
			
			note_onoff(&otr, hi == 9, sec, low, note, velo);
			// 関数 note_onoff() の引数追加
			// 末尾に鍵盤オン・オフ時の速度(強さ) velo を追加
			
			break;
		case 0xa:
		case 0xb:
		case 0xe:
			rd();
			rd();
			break;
		case 0xc:		
		case 0xd:
			rd();
			break;
		case 0xf:
			rd();
			switch(low){
			case 0:
				while(rd() != 0xf7);
				break;
			case 1:
			case 3:
				rd();
				break;
			case 2:
				rd();
				rd();
				break;
			case 0xf:
				n = rd();
				for(i=0; i<n; i++) rd();
				break;
			default:
				break;
			}
			break;
		}
	}
	if(otr.fp != stdout) pclose(otr.fp);
	return 0;
}

/* EOF */


prog_onoff_sin12.c 解説

prog_onoff_sin11.c からの変更箇所のみ

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <math.h>

#define MSG(s) fprintf(stderr, "%s() %s L%d : %s\n", __func__, __FILE__, __LINE__, s)
#define ERR(s) do{ fprintf(stderr, "ERR "); MSG(s); exit(1); }while(0)

int bk_buf = -1;

int
rd(void)
{
	int v;

	if((v = bk_buf) < 0) return getchar();
	bk_buf = -1;
	return v;
}

void
bk(int v)
{
	if(bk_buf >= 0) ERR("give up");
	bk_buf = v;
}

void
rd_str(int n, char *s)
{
	int i;

	for(i=0; i<n; i++) s[i] = rd();
	s[i] = '\0';
}

int
rd_str_chk(int n, char *s)
{
	char buf[256];

	rd_str(n, buf);
	return strcmp(buf, s) == 0;
}

int
rd_int(int n) /* big endian */
{
	int i, v;

	v = 0;
	for(i=0; i<n; i++) v = (v << 8) | rd();
	return v;
}

int
rd_delta(void)
{
	int v, c;

	v = 0;
	do{
		if((c = rd()) == EOF) return EOF;
		v = (v << 7) | (c & 0x7f);
	}while(c & 0x80);
	return v;
}


#define NOTE_BUF_N	256

struct note_rec{
	int ch;
	int note;
	int onoff;
	double on_sec;
	double off_sec;
	int velo;
} note_buf[NOTE_BUF_N];

int
note_buf_is_free(int i)
{
	return note_buf[i].ch < 0;
}

void
note_buf_free(int i)
{
	note_buf[i].ch = -1;
}

void
note_buf_init(void)
{
	int i;

	for(i=0; i<NOTE_BUF_N; i++) note_buf_free(i);
}

int
note_buf_search(int ch, int note, int onoff)
{
	int i;

	for(i=0; i<NOTE_BUF_N; i++) {
		if( (ch < 0 && note_buf[i].ch < 0) ||
		    (note_buf[i].ch == ch &&
		     note_buf[i].note == note &&
		     note_buf[i].onoff == onoff) ) return i;
	}
	return -1;
}

int
header(void)
{
	int v;

	if(!rd_str_chk(4, "MThd")) ERR("header id");
	if(rd_int(4) != 6) ERR("header size");
	if(rd_int(2) != 0) ERR("header format type");
	if(rd_int(2) != 1) ERR("header track num");
	if((v = rd_int(2)) & 0x8000) ERR("header division");
	return v; /* div4 */
}

double
note_to_freq(int note)
{
	return 440 * pow(2, (note - 69) / 12.0);
}

int
opt_idx(char *key, int ac, char **av)
{
	int i;

	for(i=1; i<ac; i++) if(strcmp(av[i], key) == 0) return i;
	return -1;
}

char *
opt_str(char *key, int ac, char **av, char *def)
{
	int i;

	i = opt_idx(key, ac, av);
	if(i < 0 || i+1 >= ac) return def;
	return av[i+1];
}

int
opt_int(char *key, int ac, char **av, int def)
{
	char *s;

	if((s = opt_str(key, ac, av, NULL)) == NULL) return def;
	return strtol(s, NULL, 0);
}

struct out_rec{
	int smp_freq, smp_cnt;
	int bit_len;
	int sign;
	int ch_num;
	FILE *fp;

	int base;
	int amp;
	int iv_min;
	int iv_max;
};

void
out_init(struct out_rec *ot, int ac, char **av)
{
	char cmd[1024], *fn;

	ot->smp_freq = opt_int("-r", ac, av, 8000);
	ot->smp_cnt = 0;
	ot->bit_len = opt_int("-b", ac, av, 8);
	if(ot->bit_len != 8 && ot->bit_len != 16) ERR("bit_len");
	ot->sign = (opt_idx("-s", ac, av) >= 0);
	ot->ch_num = opt_int("-c", ac, av, 1);

	ot->fp = stdout;
	cmd[0] = '\0';
	fn = "";
	if(opt_idx("-play", ac, av) >= 0){
		strcat(cmd, "play");
	}else if(opt_idx("-sox", ac, av) >= 0){
		strcat(cmd, "sox");
		fn = opt_str("-sox", ac, av, "-d");
	}
	if(cmd[0]){
		sprintf(cmd + strlen(cmd), " -t raw -r %d -b %d %s -c %d - %s",
			ot->smp_freq, ot->bit_len,
			ot->sign ? "-s" : "-u",
			ot->ch_num, fn);
		if((ot->fp = popen(cmd, "w")) == NULL) ERR("popen");
	}
	ot->amp = ot->bit_len == 8 ? 127 : 32767;
	ot->base = ot->sign ? 0 : ot->amp + 1;
	ot->iv_min = ot->base - (ot->amp + 1);
	ot->iv_max = ot->base + ot->amp;
}

void
out_do(struct out_rec *ot, double v)
{
	int iv;

	iv = ot->base + (int)(v *ot->amp);
	if(iv > ot->iv_max) iv = ot->iv_max;
	if(iv < ot->iv_min) iv = ot->iv_min;
	switch(ot->bit_len){
	case 8:
		fputc(iv, ot->fp);
		break;
	case 16:
		fputc(iv & 0xff, ot->fp);
		fputc((iv >> 8) & 0xff, ot->fp);
		break;
	}
}

void
data_out(struct out_rec *ot, double evt_sec)
{
	double v, sec, freq, dsec;
	double vl, vr, pan;
	double release;
	int i;

	release = 0.3;
	while((sec = (double)ot->smp_cnt / ot->smp_freq) < evt_sec){
		vl = vr = 0;
		for(i=0; i<NOTE_BUF_N; i++){
			if(note_buf_is_free(i)) continue;
			freq = note_to_freq(note_buf[i].note);
			dsec = sec - note_buf[i].on_sec;
			v = sin(2 * M_PI * freq * dsec);
			v *= note_buf[i].velo / 127.0;
			if(note_buf[i].onoff == 0){
				dsec = sec - note_buf[i].off_sec;
				v *= 1 - dsec / release;
				if(dsec >= release) note_buf_free(i);
			}
			if(ot->ch_num == 1){
				vl += v;
			}else{
				pan = note_buf[i].ch / 15.0;
				vl += (1 - pan) * v;
				vr += pan * v;
			}
		}
		out_do(ot, vl / 16);
		if(ot->ch_num > 1) out_do(ot, vr / 16);
		ot->smp_cnt++;
	}
}

void
note_onoff(int onoff, double evt_sec, int ch, int note, int velo)
{
	int i;

	if(ch == 9) return;

	if(onoff){
		if((i = note_buf_search(-1, -1, -1)) < 0){
			MSG("note_buf full");
			return;
		}
		note_buf[i].note = note;
		note_buf[i].ch = ch;
		note_buf[i].onoff = 1;
		note_buf[i].on_sec = evt_sec;
		note_buf[i].velo = velo;
	}else{
		if((i = note_buf_search(ch, note, 1)) < 0) return;
		note_buf[i].onoff = 0;
		note_buf[i].off_sec = evt_sec;
	}
}

int
main(int ac, char **av)
{
	int div4, delta_sum;
	int i, n, v, hi, low, note, velo;
	double sec;
	struct out_rec otr;

	out_init(&otr, ac, av);
	note_buf_init();

	div4 = header();

	if(!rd_str_chk(4, "MTrk")) ERR("track id");
	v = rd_int(4); /* skip */

	hi = low = 0;
	delta_sum = 0;
	while((v = rd_delta()) != EOF){
		delta_sum += v;
		sec = (double)delta_sum / div4 * 0.5;
		
		if((v = rd()) & 0x80){
			hi = (v >> 4) & 0xf;
			low  = v & 0xf;
		}else bk(v);

		data_out(&otr, sec);

		switch(hi){
		case 8:
		case 9:
			note = rd();
			velo = rd();
			note_onoff(hi == 9, sec, low, note, velo);
			break;
		case 0xa:
		case 0xb:
		case 0xe:
			rd();
			rd();
			break;
		case 0xc:		
		case 0xd:
			rd();
			break;
		case 0xf:
			rd();
			switch(low){
			case 0:
				while(rd() != 0xf7);
				break;
			case 1:
			case 3:
				rd();
				break;
			case 2:
				rd();
				rd();
				break;
			case 0xf:
				n = rd();
				for(i=0; i<n; i++) rd();
				break;
			default:
				break;
			}
			break;
		}
	}
	if(otr.fp != stdout) pclose(otr.fp);
	return 0;
}

/* EOF */


#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <math.h>

#define MSG(s) fprintf(stderr, "%s() %s L%d : %s\n", __func__, __FILE__, __LINE__, s)
#define ERR(s) do{ fprintf(stderr, "ERR "); MSG(s); exit(1); }while(0)

int bk_buf = -1;

int
rd(void)
{
	int v;

	if((v = bk_buf) < 0) return getchar();
	bk_buf = -1;
	return v;
}

void
bk(int v)
{
	if(bk_buf >= 0) ERR("give up");
	bk_buf = v;
}

void
rd_str(int n, char *s)
{
	int i;

	for(i=0; i<n; i++) s[i] = rd();
	s[i] = '\0';
}

int
rd_str_chk(int n, char *s)
{
	char buf[256];

	rd_str(n, buf);
	return strcmp(buf, s) == 0;
}

int
rd_int(int n) /* big endian */
{
	int i, v;

	v = 0;
	for(i=0; i<n; i++) v = (v << 8) | rd();
	return v;
}

int
rd_delta(void)
{
	int v, c;

	v = 0;
	do{
		if((c = rd()) == EOF) return EOF;
		v = (v << 7) | (c & 0x7f);
	}while(c & 0x80);
	return v;
}


#define NOTE_BUF_N	256

struct note_rec{
	int ch;
	int note;
	int onoff;
	double on_sec;
	double off_sec;
	int velo;
} note_buf[NOTE_BUF_N];

int
note_buf_is_free(int i)
{
	return note_buf[i].ch < 0;
}

void
note_buf_free(int i)
{
	note_buf[i].ch = -1;
}

void
note_buf_init(void)
{
	int i;

	for(i=0; i<NOTE_BUF_N; i++) note_buf_free(i);
}

int
note_buf_search(int ch, int note, int onoff)
{
	int i;

	for(i=0; i<NOTE_BUF_N; i++) {
		if( (ch < 0 && note_buf[i].ch < 0) ||
		    (note_buf[i].ch == ch &&
		     note_buf[i].note == note &&
		     note_buf[i].onoff == onoff) ) return i;
	}
	return -1;
}

int
header(void)
{
	int v;

	if(!rd_str_chk(4, "MThd")) ERR("header id");
	if(rd_int(4) != 6) ERR("header size");
	if(rd_int(2) != 0) ERR("header format type");
	if(rd_int(2) != 1) ERR("header track num");
	if((v = rd_int(2)) & 0x8000) ERR("header division");
	return v; /* div4 */
}

double
note_to_freq(int note)
{
	return 440 * pow(2, (note - 69) / 12.0);
}

int
opt_idx(char *key, int ac, char **av)
{
	int i;

	for(i=1; i<ac; i++) if(strcmp(av[i], key) == 0) return i;
	return -1;
}

char *
opt_str(char *key, int ac, char **av, char *def)
{
	int i;

	i = opt_idx(key, ac, av);
	if(i < 0 || i+1 >= ac) return def;
	return av[i+1];
}

int
opt_int(char *key, int ac, char **av, int def)
{
	char *s;

	if((s = opt_str(key, ac, av, NULL)) == NULL) return def;
	return strtol(s, NULL, 0);
}

struct out_rec{
	int smp_freq, smp_cnt;
	int bit_len;
	int sign;
	int ch_num;
	FILE *fp;

	int base;
	int amp;
	int iv_min;
	int iv_max;
};

void
out_init(struct out_rec *ot, int ac, char **av)
{
	char cmd[1024], *fn;

	ot->smp_freq = opt_int("-r", ac, av, 8000);
	ot->smp_cnt = 0;
	ot->bit_len = opt_int("-b", ac, av, 8);
	if(ot->bit_len != 8 && ot->bit_len != 16) ERR("bit_len");
	ot->sign = (opt_idx("-s", ac, av) >= 0);
	ot->ch_num = opt_int("-c", ac, av, 1);

	ot->fp = stdout;
	cmd[0] = '\0';
	fn = "";
	if(opt_idx("-play", ac, av) >= 0){
		strcat(cmd, "play");
	}else if(opt_idx("-sox", ac, av) >= 0){
		strcat(cmd, "sox");
		fn = opt_str("-sox", ac, av, "-d");
	}
	if(cmd[0]){
		sprintf(cmd + strlen(cmd), " -t raw -r %d -b %d %s -c %d - %s",
			ot->smp_freq, ot->bit_len,
			ot->sign ? "-s" : "-u",
			ot->ch_num, fn);
		if((ot->fp = popen(cmd, "w")) == NULL) ERR("popen");
	}
	ot->amp = ot->bit_len == 8 ? 127 : 32767;
	ot->base = ot->sign ? 0 : ot->amp + 1;
	ot->iv_min = ot->base - (ot->amp + 1);
	ot->iv_max = ot->base + ot->amp;
}

void
out_do(struct out_rec *ot, double v)
{
	int iv;

	iv = ot->base + (int)(v *ot->amp);
	if(iv > ot->iv_max) iv = ot->iv_max;
	if(iv < ot->iv_min) iv = ot->iv_min;
	switch(ot->bit_len){
	case 8:
		fputc(iv, ot->fp);
		break;
	case 16:
		fputc(iv & 0xff, ot->fp);
		fputc((iv >> 8) & 0xff, ot->fp);
		break;
	}
}

void
data_out(struct out_rec *ot, double evt_sec)
{
	// 以前の note_onoff() 関数から、
	// 冒頭の波形生成処理を切り出して、
	// 関数として独立させた

	// 引数 evt_sec の時刻(秒)に至るまでの、
	// 波形データを出力する
	
	double v, sec, freq, dsec;
	double vl, vr, pan;
	double release;
	int i;

	release = 0.3;
	while((sec = (double)ot->smp_cnt / ot->smp_freq) < evt_sec){
		vl = vr = 0;
		for(i=0; i<NOTE_BUF_N; i++){
			if(note_buf_is_free(i)) continue;
			freq = note_to_freq(note_buf[i].note);
			dsec = sec - note_buf[i].on_sec;
			v = sin(2 * M_PI * freq * dsec);
			v *= note_buf[i].velo / 127.0;
			if(note_buf[i].onoff == 0){
				dsec = sec - note_buf[i].off_sec;
				v *= 1 - dsec / release;
				if(dsec >= release) note_buf_free(i);
			}
			if(ot->ch_num == 1){
				vl += v;
			}else{
				pan = note_buf[i].ch / 15.0;
				vl += (1 - pan) * v;
				vr += pan * v;
			}
		}
		out_do(ot, vl / 16);
		if(ot->ch_num > 1) out_do(ot, vr / 16);
		ot->smp_cnt++;
	}
}

void
note_onoff(int onoff, double evt_sec, int ch, int note, int velo)
{
	// 以前のバージョンで冒頭にあった、
	// 波形出力処理は削除し、
	// data_out() 関数へと分離した

	// 不要となった引数の out_rec 構造体を削除
	
	int i;

	if(ch == 9) return;

	if(onoff){
		if((i = note_buf_search(-1, -1, -1)) < 0){
			MSG("note_buf full");
			return;
		}
		note_buf[i].note = note;
		note_buf[i].ch = ch;
		note_buf[i].onoff = 1;
		note_buf[i].on_sec = evt_sec;
		note_buf[i].velo = velo;
	}else{
		if((i = note_buf_search(ch, note, 1)) < 0) return;
		note_buf[i].onoff = 0;
		note_buf[i].off_sec = evt_sec;
	}
}

int
main(int ac, char **av)
{
	int div4, delta_sum;
	int i, n, v, hi, low, note, velo;
	double sec;
	struct out_rec otr;

	out_init(&otr, ac, av);
	note_buf_init();

	div4 = header();

	if(!rd_str_chk(4, "MTrk")) ERR("track id");
	v = rd_int(4); /* skip */

	hi = low = 0;
	delta_sum = 0;
	while((v = rd_delta()) != EOF){
		delta_sum += v;
		sec = (double)delta_sum / div4 * 0.5;
		
		if((v = rd()) & 0x80){
			hi = (v >> 4) & 0xf;
			low  = v & 0xf;
		}else bk(v);

		data_out(&otr, sec);
		// 鍵盤オン・オフのイベントに限らず
		// 全てのイベントで波形出力するように
		// 分離した data_out() 関数の呼び出しを
		// この位置に追加した
		
		switch(hi){
		case 8:
		case 9:
			note = rd();
			velo = rd();
			note_onoff(hi == 9, sec, low, note, velo);
			// note_onoff()関数の引数削除にともない
			// 呼び出し側も変更
			
			break;
		case 0xa:
		case 0xb:
		case 0xe:
			rd();
			rd();
			break;
		case 0xc:		
		case 0xd:
			rd();
			break;
		case 0xf:
			rd();
			switch(low){
			case 0:
				while(rd() != 0xf7);
				break;
			case 1:
			case 3:
				rd();
				break;
			case 2:
				rd();
				rd();
				break;
			case 0xf:
				n = rd();
				for(i=0; i<n; i++) rd();
				break;
			default:
				break;
			}
			break;
		}
	}
	if(otr.fp != stdout) pclose(otr.fp);
	return 0;
}

/* EOF */


prog1.c 解説

prog_onoff_sin12.c からの変更箇所のみ

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <math.h>

#define MSG(s) fprintf(stderr, "%s() %s L%d : %s\n", __func__, __FILE__, __LINE__, s)
#define ERR(s) do{ fprintf(stderr, "ERR "); MSG(s); exit(1); }while(0)

int bk_buf = -1;

int
rd(void)
{
	int v;

	if((v = bk_buf) < 0) return getchar();
	bk_buf = -1;
	return v;
}

void
bk(int v)
{
	if(bk_buf >= 0) ERR("give up");
	bk_buf = v;
}

void
rd_str(int n, char *s)
{
	int i;

	for(i=0; i<n; i++) s[i] = rd();
	s[i] = '\0';
}

int
rd_str_chk(int n, char *s)
{
	char buf[256];

	rd_str(n, buf);
	return strcmp(buf, s) == 0;
}

int
rd_int(int n) /* big endian */
{
	int i, v;

	v = 0;
	for(i=0; i<n; i++) v = (v << 8) | rd();
	return v;
}

int
rd_delta(void)
{
	int v, c;

	v = 0;
	do{
		if((c = rd()) == EOF) return EOF;
		v = (v << 7) | (c & 0x7f);
	}while(c & 0x80);
	return v;
}


#define NOTE_BUF_N	256

struct note_rec{
	int ch;
	int note;
	int onoff;
	double on_sec;
	double off_sec;
	int velo;
} note_buf[NOTE_BUF_N];

int
note_buf_is_free(int i)
{
	return note_buf[i].ch < 0;
}

void
note_buf_free(int i)
{
	note_buf[i].ch = -1;
}

void
note_buf_init(void)
{
	int i;

	for(i=0; i<NOTE_BUF_N; i++) note_buf_free(i);
}

int
note_buf_search(int ch, int note, int onoff)
{
	int i;

	for(i=0; i<NOTE_BUF_N; i++) {
		if( (ch < 0 && note_buf[i].ch < 0) ||
		    (note_buf[i].ch == ch &&
		     note_buf[i].note == note &&
		     note_buf[i].onoff == onoff) ) return i;
	}
	return -1;
}

int
header(void)
{
	int v;

	if(!rd_str_chk(4, "MThd")) ERR("header id");
	if(rd_int(4) != 6) ERR("header size");
	if(rd_int(2) != 0) ERR("header format type");
	if(rd_int(2) != 1) ERR("header track num");
	if((v = rd_int(2)) & 0x8000) ERR("header division");
	return v; /* div4 */
}

double
note_to_freq(int note)
{
	return 440 * pow(2, (note - 69) / 12.0);
}

int
opt_idx(char *key, int ac, char **av)
{
	int i;

	for(i=1; i<ac; i++) if(strcmp(av[i], key) == 0) return i;
	return -1;
}

char *
opt_str(char *key, int ac, char **av, char *def)
{
	int i;

	i = opt_idx(key, ac, av);
	if(i < 0 || i+1 >= ac) return def;
	return av[i+1];
}

int
opt_int(char *key, int ac, char **av, int def)
{
	char *s;

	if((s = opt_str(key, ac, av, NULL)) == NULL) return def;
	return strtol(s, NULL, 0);
}

struct out_rec{
	int smp_freq, smp_cnt;
	int bit_len;
	int sign;
	int ch_num;
	FILE *fp;

	int base;
	int amp;
	int iv_min;
	int iv_max;
};

void
out_init(struct out_rec *ot, int ac, char **av)
{
	char cmd[1024], *fn;

	ot->smp_freq = opt_int("-r", ac, av, 8000);
	ot->smp_cnt = 0;
	ot->bit_len = opt_int("-b", ac, av, 8);
	if(ot->bit_len != 8 && ot->bit_len != 16) ERR("bit_len");
	ot->sign = (opt_idx("-s", ac, av) >= 0);
	ot->ch_num = opt_int("-c", ac, av, 1);

	ot->fp = stdout;
	cmd[0] = '\0';
	fn = "";
	if(opt_idx("-play", ac, av) >= 0){
		strcat(cmd, "play");
	}else if(opt_idx("-sox", ac, av) >= 0){
		strcat(cmd, "sox");
		fn = opt_str("-sox", ac, av, "-d");
	}
	if(cmd[0]){
		sprintf(cmd + strlen(cmd), " -t raw -r %d -b %d %s -c %d - %s",
			ot->smp_freq, ot->bit_len,
			ot->sign ? "-s" : "-u",
			ot->ch_num, fn);
		if((ot->fp = popen(cmd, "w")) == NULL) ERR("popen");
	}
	ot->amp = ot->bit_len == 8 ? 127 : 32767;
	ot->base = ot->sign ? 0 : ot->amp + 1;
	ot->iv_min = ot->base - (ot->amp + 1);
	ot->iv_max = ot->base + ot->amp;
}

void
out_do(struct out_rec *ot, double v)
{
	int iv;

	iv = ot->base + (int)(v *ot->amp);
	if(iv > ot->iv_max) iv = ot->iv_max;
	if(iv < ot->iv_min) iv = ot->iv_min;
	switch(ot->bit_len){
	case 8:
		fputc(iv, ot->fp);
		break;
	case 16:
		fputc(iv & 0xff, ot->fp);
		fputc((iv >> 8) & 0xff, ot->fp);
		break;
	}
}

#define MIDI_CH_N	16
int ch_vol[ MIDI_CH_N ];

void
data_out(struct out_rec *ot, double evt_sec)
{
	double v, sec, freq, dsec;
	double vl, vr, pan;
	double release;
	int i;

	release = 0.3;
	while((sec = (double)ot->smp_cnt / ot->smp_freq) < evt_sec){
		vl = vr = 0;
		for(i=0; i<NOTE_BUF_N; i++){
			if(note_buf_is_free(i)) continue;
			freq = note_to_freq(note_buf[i].note);
			dsec = sec - note_buf[i].on_sec;
			v = sin(2 * M_PI * freq * dsec);
			v *= note_buf[i].velo / 127.0;
			v *= ch_vol[ note_buf[i].ch ] / (double)((1<<14)-1);
			if(note_buf[i].onoff == 0){
				dsec = sec - note_buf[i].off_sec;
				v *= 1 - dsec / release;
				if(dsec >= release) note_buf_free(i);
			}
			if(ot->ch_num == 1){
				vl += v;
			}else{
				pan = note_buf[i].ch / 15.0;
				vl += (1 - pan) * v;
				vr += pan * v;
			}
		}
		out_do(ot, vl / 16);
		if(ot->ch_num > 1) out_do(ot, vr / 16);
		ot->smp_cnt++;
	}
}

void
note_onoff(int onoff, double evt_sec, int ch, int note, int velo)
{
	int i;

	if(ch == 9) return;

	if(onoff){
		if((i = note_buf_search(-1, -1, -1)) < 0){
			MSG("note_buf full");
			return;
		}
		note_buf[i].note = note;
		note_buf[i].ch = ch;
		note_buf[i].onoff = 1;
		note_buf[i].on_sec = evt_sec;
		note_buf[i].velo = velo;
	}else{
		if((i = note_buf_search(ch, note, 1)) < 0) return;
		note_buf[i].onoff = 0;
		note_buf[i].off_sec = evt_sec;
	}
}

int
main(int ac, char **av)
{
	int div4, delta_sum;
	int i, n, v, hi, low, note, velo;
	int ch, type;
	double sec;
	struct out_rec otr;

	out_init(&otr, ac, av);
	note_buf_init();
	for(i=0; i<MIDI_CH_N; i++) ch_vol[i] = 0;

	div4 = header();

	if(!rd_str_chk(4, "MTrk")) ERR("track id");
	v = rd_int(4); /* skip */

	hi = low = 0;
	delta_sum = 0;
	while((v = rd_delta()) != EOF){
		delta_sum += v;
		sec = (double)delta_sum / div4 * 0.5;
		
		if((v = rd()) & 0x80){
			hi = (v >> 4) & 0xf;
			low  = v & 0xf;
		}else bk(v);

		data_out(&otr, sec);

		ch = low;
		switch(hi){
		case 8:
		case 9:
			note = rd();
			velo = rd();
			note_onoff(hi == 9, sec, ch, note, velo);
			break;
		case 0xb: /* control change */
			type = rd();
			v = rd();
			switch(type){
			case 7: /* channel volume msb */
				ch_vol[ch] &= ~(127<<7);
				ch_vol[ch] |= v<<7;
				break;
			case 39: /* channel volume lsb */
				ch_vol[ch] &= ~127;
				ch_vol[ch] |= v;
				break;
			}
			break;
		case 0xa:
		case 0xe:
			rd();
			rd();
			break;
		case 0xc:		
		case 0xd:
			rd();
			break;
		case 0xf:
			rd();
			switch(low){
			case 0:
				while(rd() != 0xf7);
				break;
			case 1:
			case 3:
				rd();
				break;
			case 2:
				rd();
				rd();
				break;
			case 0xf:
				n = rd();
				for(i=0; i<n; i++) rd();
				break;
			default:
				break;
			}
			break;
		}
	}
	if(otr.fp != stdout) pclose(otr.fp);
	return 0;
}

/* EOF */


#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <math.h>

#define MSG(s) fprintf(stderr, "%s() %s L%d : %s\n", __func__, __FILE__, __LINE__, s)
#define ERR(s) do{ fprintf(stderr, "ERR "); MSG(s); exit(1); }while(0)

int bk_buf = -1;

int
rd(void)
{
	int v;

	if((v = bk_buf) < 0) return getchar();
	bk_buf = -1;
	return v;
}

void
bk(int v)
{
	if(bk_buf >= 0) ERR("give up");
	bk_buf = v;
}

void
rd_str(int n, char *s)
{
	int i;

	for(i=0; i<n; i++) s[i] = rd();
	s[i] = '\0';
}

int
rd_str_chk(int n, char *s)
{
	char buf[256];

	rd_str(n, buf);
	return strcmp(buf, s) == 0;
}

int
rd_int(int n) /* big endian */
{
	int i, v;

	v = 0;
	for(i=0; i<n; i++) v = (v << 8) | rd();
	return v;
}

int
rd_delta(void)
{
	int v, c;

	v = 0;
	do{
		if((c = rd()) == EOF) return EOF;
		v = (v << 7) | (c & 0x7f);
	}while(c & 0x80);
	return v;
}


#define NOTE_BUF_N	256

struct note_rec{
	int ch;
	int note;
	int onoff;
	double on_sec;
	double off_sec;
	int velo;
} note_buf[NOTE_BUF_N];

int
note_buf_is_free(int i)
{
	return note_buf[i].ch < 0;
}

void
note_buf_free(int i)
{
	note_buf[i].ch = -1;
}

void
note_buf_init(void)
{
	int i;

	for(i=0; i<NOTE_BUF_N; i++) note_buf_free(i);
}

int
note_buf_search(int ch, int note, int onoff)
{
	int i;

	for(i=0; i<NOTE_BUF_N; i++) {
		if( (ch < 0 && note_buf[i].ch < 0) ||
		    (note_buf[i].ch == ch &&
		     note_buf[i].note == note &&
		     note_buf[i].onoff == onoff) ) return i;
	}
	return -1;
}

int
header(void)
{
	int v;

	if(!rd_str_chk(4, "MThd")) ERR("header id");
	if(rd_int(4) != 6) ERR("header size");
	if(rd_int(2) != 0) ERR("header format type");
	if(rd_int(2) != 1) ERR("header track num");
	if((v = rd_int(2)) & 0x8000) ERR("header division");
	return v; /* div4 */
}

double
note_to_freq(int note)
{
	return 440 * pow(2, (note - 69) / 12.0);
}

int
opt_idx(char *key, int ac, char **av)
{
	int i;

	for(i=1; i<ac; i++) if(strcmp(av[i], key) == 0) return i;
	return -1;
}

char *
opt_str(char *key, int ac, char **av, char *def)
{
	int i;

	i = opt_idx(key, ac, av);
	if(i < 0 || i+1 >= ac) return def;
	return av[i+1];
}

int
opt_int(char *key, int ac, char **av, int def)
{
	char *s;

	if((s = opt_str(key, ac, av, NULL)) == NULL) return def;
	return strtol(s, NULL, 0);
}

struct out_rec{
	int smp_freq, smp_cnt;
	int bit_len;
	int sign;
	int ch_num;
	FILE *fp;

	int base;
	int amp;
	int iv_min;
	int iv_max;
};

void
out_init(struct out_rec *ot, int ac, char **av)
{
	char cmd[1024], *fn;

	ot->smp_freq = opt_int("-r", ac, av, 8000);
	ot->smp_cnt = 0;
	ot->bit_len = opt_int("-b", ac, av, 8);
	if(ot->bit_len != 8 && ot->bit_len != 16) ERR("bit_len");
	ot->sign = (opt_idx("-s", ac, av) >= 0);
	ot->ch_num = opt_int("-c", ac, av, 1);

	ot->fp = stdout;
	cmd[0] = '\0';
	fn = "";
	if(opt_idx("-play", ac, av) >= 0){
		strcat(cmd, "play");
	}else if(opt_idx("-sox", ac, av) >= 0){
		strcat(cmd, "sox");
		fn = opt_str("-sox", ac, av, "-d");
	}
	if(cmd[0]){
		sprintf(cmd + strlen(cmd), " -t raw -r %d -b %d %s -c %d - %s",
			ot->smp_freq, ot->bit_len,
			ot->sign ? "-s" : "-u",
			ot->ch_num, fn);
		if((ot->fp = popen(cmd, "w")) == NULL) ERR("popen");
	}
	ot->amp = ot->bit_len == 8 ? 127 : 32767;
	ot->base = ot->sign ? 0 : ot->amp + 1;
	ot->iv_min = ot->base - (ot->amp + 1);
	ot->iv_max = ot->base + ot->amp;
}

void
out_do(struct out_rec *ot, double v)
{
	int iv;

	iv = ot->base + (int)(v *ot->amp);
	if(iv > ot->iv_max) iv = ot->iv_max;
	if(iv < ot->iv_min) iv = ot->iv_min;
	switch(ot->bit_len){
	case 8:
		fputc(iv, ot->fp);
		break;
	case 16:
		fputc(iv & 0xff, ot->fp);
		fputc((iv >> 8) & 0xff, ot->fp);
		break;
	}
}

#define MIDI_CH_N	16
// MIDIチャンネル数

int ch_vol[ MIDI_CH_N ];
// MIDIチャンネルごとのボリューム (14 bit)

void
data_out(struct out_rec *ot, double evt_sec)
{
	double v, sec, freq, dsec;
	double vl, vr, pan;
	double release;
	int i;

	release = 0.3;
	while((sec = (double)ot->smp_cnt / ot->smp_freq) < evt_sec){
		vl = vr = 0;
		for(i=0; i<NOTE_BUF_N; i++){
			if(note_buf_is_free(i)) continue;
			freq = note_to_freq(note_buf[i].note);
			dsec = sec - note_buf[i].on_sec;
			v = sin(2 * M_PI * freq * dsec);
			v *= note_buf[i].velo / 127.0;
			v *= ch_vol[ note_buf[i].ch ] / (double)((1<<14)-1);
			// 鍵盤情報のMIDIチャンネルから、
			// MIDIチャンネルごとのボリューム (14 bit) を参照
			// 14 bit の値を、0.0〜1.0 に換算
			// 0.0 〜 1.0 の値を、波形の値にかけ算
			
			if(note_buf[i].onoff == 0){
				dsec = sec - note_buf[i].off_sec;
				v *= 1 - dsec / release;
				if(dsec >= release) note_buf_free(i);
			}
			if(ot->ch_num == 1){
				vl += v;
			}else{
				pan = note_buf[i].ch / 15.0;
				vl += (1 - pan) * v;
				vr += pan * v;
			}
		}
		out_do(ot, vl / 16);
		if(ot->ch_num > 1) out_do(ot, vr / 16);
		ot->smp_cnt++;
	}
}

void
note_onoff(int onoff, double evt_sec, int ch, int note, int velo)
{
	int i;

	if(ch == 9) return;

	if(onoff){
		if((i = note_buf_search(-1, -1, -1)) < 0){
			MSG("note_buf full");
			return;
		}
		note_buf[i].note = note;
		note_buf[i].ch = ch;
		note_buf[i].onoff = 1;
		note_buf[i].on_sec = evt_sec;
		note_buf[i].velo = velo;
	}else{
		if((i = note_buf_search(ch, note, 1)) < 0) return;
		note_buf[i].onoff = 0;
		note_buf[i].off_sec = evt_sec;
	}
}

int
main(int ac, char **av)
{
	int div4, delta_sum;
	int i, n, v, hi, low, note, velo;
	int ch, type;
	// MIDIチャンネル用の変数 ch と、
	// コントロール・チェンジ・イベントの
	// 2バイト目を保持する変数 type を追加
	
	double sec;
	struct out_rec otr;

	out_init(&otr, ac, av);
	note_buf_init();
	for(i=0; i<MIDI_CH_N; i++) ch_vol[i] = 0;
	// MIDIチャンネルごとのボリュームを、全て 0 で初期化
	
	div4 = header();

	if(!rd_str_chk(4, "MTrk")) ERR("track id");
	v = rd_int(4); /* skip */

	hi = low = 0;
	delta_sum = 0;
	while((v = rd_delta()) != EOF){
		delta_sum += v;
		sec = (double)delta_sum / div4 * 0.5;
		
		if((v = rd()) & 0x80){
			hi = (v >> 4) & 0xf;
			low  = v & 0xf;
		}else bk(v);

		data_out(&otr, sec);

		ch = low;
		// MIDIチャンネル用の変数 ch を追加したので
		// 1バイト目の下位4 bitの値を、専用の変数 ch へ
		
		switch(hi){
		case 8:
		case 9:
			note = rd();
			velo = rd();
			note_onoff(hi == 9, sec, ch, note, velo);
			// 変数 ch を追加したので
			// 第4引数を low から ch へ変更
			
			break;
		case 0xb: /* control change */
		// 1バイト目の上位4 bitが 0xb ならば、
		// コントロール・チェンジ・イベント
		// または チェンジ・モード・メッセージ
		
			type = rd();
			// 2バイト目を読み込み、変数 type へ
			
			v = rd();
			// 3バイト目を読み込み、変数 v へ
			
			switch(type){
			case 7: /* channel volume msb */
			// 2バイト目の type が 7 ならば、
			
				ch_vol[ch] &= ~(127<<7);
				ch_vol[ch] |= v<<7;
				// MIDIチャンネルごとのボリュームの
				// 上位 7 bit の値を、変数 v の値に変更
				
				break;
			case 39: /* channel volume lsb */
			// 2バイト目の type が 39 ならば、
			
				ch_vol[ch] &= ~127;
				ch_vol[ch] |= v;
				// MIDIチャンネルごとのボリュームの
				// 下位 7 bit の値を、変数 v の値に変更
				
				break;
			}
			break;
		case 0xa:
		case 0xe:
			rd();
			rd();
			break;
		case 0xc:		
		case 0xd:
			rd();
			break;
		case 0xf:
			rd();
			switch(low){
			case 0:
				while(rd() != 0xf7);
				break;
			case 1:
			case 3:
				rd();
				break;
			case 2:
				rd();
				rd();
				break;
			case 0xf:
				n = rd();
				for(i=0; i<n; i++) rd();
				break;
			default:
				break;
			}
			break;
		}
	}
	if(otr.fp != stdout) pclose(otr.fp);
	return 0;
}

/* EOF */


prog2.c 解説

prog1.c からの変更箇所のみ

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <math.h>

#define MSG(s) fprintf(stderr, "%s() %s L%d : %s\n", __func__, __FILE__, __LINE__, s)
#define ERR(s) do{ fprintf(stderr, "ERR "); MSG(s); exit(1); }while(0)

int bk_buf = -1;

int
rd(void)
{
	int v;

	if((v = bk_buf) < 0) return getchar();
	bk_buf = -1;
	return v;
}

void
bk(int v)
{
	if(bk_buf >= 0) ERR("give up");
	bk_buf = v;
}

void
rd_str(int n, char *s)
{
	int i;

	for(i=0; i<n; i++) s[i] = rd();
	s[i] = '\0';
}

int
rd_str_chk(int n, char *s)
{
	char buf[256];

	rd_str(n, buf);
	return strcmp(buf, s) == 0;
}

int
rd_int(int n) /* big endian */
{
	int i, v;

	v = 0;
	for(i=0; i<n; i++) v = (v << 8) | rd();
	return v;
}

int
rd_delta(void)
{
	int v, c;

	v = 0;
	do{
		if((c = rd()) == EOF) return EOF;
		v = (v << 7) | (c & 0x7f);
	}while(c & 0x80);
	return v;
}


#define NOTE_BUF_N	256

struct note_rec{
	int ch;
	int note;
	int onoff;
	double on_sec;
	double off_sec;
	int velo;
} note_buf[NOTE_BUF_N];

int
note_buf_is_free(int i)
{
	return note_buf[i].ch < 0;
}

void
note_buf_free(int i)
{
	note_buf[i].ch = -1;
}

void
note_buf_init(void)
{
	int i;

	for(i=0; i<NOTE_BUF_N; i++) note_buf_free(i);
}

int
note_buf_search(int ch, int note, int onoff)
{
	int i;

	for(i=0; i<NOTE_BUF_N; i++) {
		if( (ch < 0 && note_buf[i].ch < 0) ||
		    (note_buf[i].ch == ch &&
		     note_buf[i].note == note &&
		     note_buf[i].onoff == onoff) ) return i;
	}
	return -1;
}

int
header(void)
{
	int v;

	if(!rd_str_chk(4, "MThd")) ERR("header id");
	if(rd_int(4) != 6) ERR("header size");
	if(rd_int(2) != 0) ERR("header format type");
	if(rd_int(2) != 1) ERR("header track num");
	if((v = rd_int(2)) & 0x8000) ERR("header division");
	return v; /* div4 */
}

double
note_to_freq(int note)
{
	return 440 * pow(2, (note - 69) / 12.0);
}

int
opt_idx(char *key, int ac, char **av)
{
	int i;

	for(i=1; i<ac; i++) if(strcmp(av[i], key) == 0) return i;
	return -1;
}

char *
opt_str(char *key, int ac, char **av, char *def)
{
	int i;

	i = opt_idx(key, ac, av);
	if(i < 0 || i+1 >= ac) return def;
	return av[i+1];
}

int
opt_int(char *key, int ac, char **av, int def)
{
	char *s;

	if((s = opt_str(key, ac, av, NULL)) == NULL) return def;
	return strtol(s, NULL, 0);
}

struct out_rec{
	int smp_freq, smp_cnt;
	int bit_len;
	int sign;
	int ch_num;
	FILE *fp;

	int base;
	int amp;
	int iv_min;
	int iv_max;
};

void
out_init(struct out_rec *ot, int ac, char **av)
{
	char cmd[1024], *fn;

	ot->smp_freq = opt_int("-r", ac, av, 8000);
	ot->smp_cnt = 0;
	ot->bit_len = opt_int("-b", ac, av, 8);
	if(ot->bit_len != 8 && ot->bit_len != 16) ERR("bit_len");
	ot->sign = (opt_idx("-s", ac, av) >= 0);
	ot->ch_num = opt_int("-c", ac, av, 1);

	ot->fp = stdout;
	cmd[0] = '\0';
	fn = "";
	if(opt_idx("-play", ac, av) >= 0){
		strcat(cmd, "play");
	}else if(opt_idx("-sox", ac, av) >= 0){
		strcat(cmd, "sox");
		fn = opt_str("-sox", ac, av, "-d");
	}
	if(cmd[0]){
		sprintf(cmd + strlen(cmd), " -t raw -r %d -b %d %s -c %d - %s",
			ot->smp_freq, ot->bit_len,
			ot->sign ? "-s" : "-u",
			ot->ch_num, fn);
		if((ot->fp = popen(cmd, "w")) == NULL) ERR("popen");
	}
	ot->amp = ot->bit_len == 8 ? 127 : 32767;
	ot->base = ot->sign ? 0 : ot->amp + 1;
	ot->iv_min = ot->base - (ot->amp + 1);
	ot->iv_max = ot->base + ot->amp;
}

void
out_do(struct out_rec *ot, double v)
{
	int iv;

	iv = ot->base + (int)(v *ot->amp);
	if(iv > ot->iv_max) iv = ot->iv_max;
	if(iv < ot->iv_min) iv = ot->iv_min;
	switch(ot->bit_len){
	case 8:
		fputc(iv, ot->fp);
		break;
	case 16:
		fputc(iv & 0xff, ot->fp);
		fputc((iv >> 8) & 0xff, ot->fp);
		break;
	}
}

#define MIDI_CH_N	16
int ch_vol[ MIDI_CH_N ];
int ch_pan[ MIDI_CH_N ];

void
data_out(struct out_rec *ot, double evt_sec)
{
	double v, sec, freq, dsec;
	double vl, vr, pan;
	double release;
	int i;

	release = 0.3;
	while((sec = (double)ot->smp_cnt / ot->smp_freq) < evt_sec){
		vl = vr = 0;
		for(i=0; i<NOTE_BUF_N; i++){
			if(note_buf_is_free(i)) continue;
			freq = note_to_freq(note_buf[i].note);
			dsec = sec - note_buf[i].on_sec;
			v = sin(2 * M_PI * freq * dsec);
			v *= note_buf[i].velo / 127.0;
			v *= ch_vol[ note_buf[i].ch ] / (double)((1<<14)-1);
			if(note_buf[i].onoff == 0){
				dsec = sec - note_buf[i].off_sec;
				v *= 1 - dsec / release;
				if(dsec >= release) note_buf_free(i);
			}
			if(ot->ch_num == 1){
				vl += v;
			}else{
				pan = ch_pan[ note_buf[i].ch ] / (double)(1<<14);
				vl += (1 - pan) * v;
				vr += pan * v;
			}
		}
		out_do(ot, vl / 16);
		if(ot->ch_num > 1) out_do(ot, vr / 16);
		ot->smp_cnt++;
	}
}

void
note_onoff(int onoff, double evt_sec, int ch, int note, int velo)
{
	int i;

	if(ch == 9) return;

	if(onoff){
		if((i = note_buf_search(-1, -1, -1)) < 0){
			MSG("note_buf full");
			return;
		}
		note_buf[i].note = note;
		note_buf[i].ch = ch;
		note_buf[i].onoff = 1;
		note_buf[i].on_sec = evt_sec;
		note_buf[i].velo = velo;
	}else{
		if((i = note_buf_search(ch, note, 1)) < 0) return;
		note_buf[i].onoff = 0;
		note_buf[i].off_sec = evt_sec;
	}
}

int
main(int ac, char **av)
{
	int div4, delta_sum;
	int i, n, v, hi, low, note, velo;
	int ch, type;
	double sec;
	struct out_rec otr;

	out_init(&otr, ac, av);
	note_buf_init();
	for(i=0; i<MIDI_CH_N; i++){
		ch_vol[i] = 0;
		ch_pan[i] = 1<<(14-1);
	}

	div4 = header();

	if(!rd_str_chk(4, "MTrk")) ERR("track id");
	v = rd_int(4); /* skip */

	hi = low = 0;
	delta_sum = 0;
	while((v = rd_delta()) != EOF){
		delta_sum += v;
		sec = (double)delta_sum / div4 * 0.5;
		
		if((v = rd()) & 0x80){
			hi = (v >> 4) & 0xf;
			low  = v & 0xf;
		}else bk(v);

		data_out(&otr, sec);

		ch = low;
		switch(hi){
		case 8:
		case 9:
			note = rd();
			velo = rd();
			note_onoff(hi == 9, sec, ch, note, velo);
			break;
		case 0xb: /* control change */
			type = rd();
			v = rd();
			switch(type){
			case 7: /* channel volume msb */
				ch_vol[ch] &= ~(127<<7);
				ch_vol[ch] |= v<<7;
				break;
			case 39: /* channel volume lsb */
				ch_vol[ch] &= ~127;
				ch_vol[ch] |= v;
				break;
			case 10: /* pan msb */
				ch_pan[ch] &= ~(127<<7);
				ch_pan[ch] |= v<<7;
				break;
			case 42: /* pan lsb */
				ch_pan[ch] &= ~127;
				ch_pan[ch] |= v;
				break;
			}
			break;
		case 0xa:
		case 0xe:
			rd();
			rd();
			break;
		case 0xc:		
		case 0xd:
			rd();
			break;
		case 0xf:
			rd();
			switch(low){
			case 0:
				while(rd() != 0xf7);
				break;
			case 1:
			case 3:
				rd();
				break;
			case 2:
				rd();
				rd();
				break;
			case 0xf:
				n = rd();
				for(i=0; i<n; i++) rd();
				break;
			default:
				break;
			}
			break;
		}
	}
	if(otr.fp != stdout) pclose(otr.fp);
	return 0;
}

/* EOF */


#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <math.h>

#define MSG(s) fprintf(stderr, "%s() %s L%d : %s\n", __func__, __FILE__, __LINE__, s)
#define ERR(s) do{ fprintf(stderr, "ERR "); MSG(s); exit(1); }while(0)

int bk_buf = -1;

int
rd(void)
{
	int v;

	if((v = bk_buf) < 0) return getchar();
	bk_buf = -1;
	return v;
}

void
bk(int v)
{
	if(bk_buf >= 0) ERR("give up");
	bk_buf = v;
}

void
rd_str(int n, char *s)
{
	int i;

	for(i=0; i<n; i++) s[i] = rd();
	s[i] = '\0';
}

int
rd_str_chk(int n, char *s)
{
	char buf[256];

	rd_str(n, buf);
	return strcmp(buf, s) == 0;
}

int
rd_int(int n) /* big endian */
{
	int i, v;

	v = 0;
	for(i=0; i<n; i++) v = (v << 8) | rd();
	return v;
}

int
rd_delta(void)
{
	int v, c;

	v = 0;
	do{
		if((c = rd()) == EOF) return EOF;
		v = (v << 7) | (c & 0x7f);
	}while(c & 0x80);
	return v;
}


#define NOTE_BUF_N	256

struct note_rec{
	int ch;
	int note;
	int onoff;
	double on_sec;
	double off_sec;
	int velo;
} note_buf[NOTE_BUF_N];

int
note_buf_is_free(int i)
{
	return note_buf[i].ch < 0;
}

void
note_buf_free(int i)
{
	note_buf[i].ch = -1;
}

void
note_buf_init(void)
{
	int i;

	for(i=0; i<NOTE_BUF_N; i++) note_buf_free(i);
}

int
note_buf_search(int ch, int note, int onoff)
{
	int i;

	for(i=0; i<NOTE_BUF_N; i++) {
		if( (ch < 0 && note_buf[i].ch < 0) ||
		    (note_buf[i].ch == ch &&
		     note_buf[i].note == note &&
		     note_buf[i].onoff == onoff) ) return i;
	}
	return -1;
}

int
header(void)
{
	int v;

	if(!rd_str_chk(4, "MThd")) ERR("header id");
	if(rd_int(4) != 6) ERR("header size");
	if(rd_int(2) != 0) ERR("header format type");
	if(rd_int(2) != 1) ERR("header track num");
	if((v = rd_int(2)) & 0x8000) ERR("header division");
	return v; /* div4 */
}

double
note_to_freq(int note)
{
	return 440 * pow(2, (note - 69) / 12.0);
}

int
opt_idx(char *key, int ac, char **av)
{
	int i;

	for(i=1; i<ac; i++) if(strcmp(av[i], key) == 0) return i;
	return -1;
}

char *
opt_str(char *key, int ac, char **av, char *def)
{
	int i;

	i = opt_idx(key, ac, av);
	if(i < 0 || i+1 >= ac) return def;
	return av[i+1];
}

int
opt_int(char *key, int ac, char **av, int def)
{
	char *s;

	if((s = opt_str(key, ac, av, NULL)) == NULL) return def;
	return strtol(s, NULL, 0);
}

struct out_rec{
	int smp_freq, smp_cnt;
	int bit_len;
	int sign;
	int ch_num;
	FILE *fp;

	int base;
	int amp;
	int iv_min;
	int iv_max;
};

void
out_init(struct out_rec *ot, int ac, char **av)
{
	char cmd[1024], *fn;

	ot->smp_freq = opt_int("-r", ac, av, 8000);
	ot->smp_cnt = 0;
	ot->bit_len = opt_int("-b", ac, av, 8);
	if(ot->bit_len != 8 && ot->bit_len != 16) ERR("bit_len");
	ot->sign = (opt_idx("-s", ac, av) >= 0);
	ot->ch_num = opt_int("-c", ac, av, 1);

	ot->fp = stdout;
	cmd[0] = '\0';
	fn = "";
	if(opt_idx("-play", ac, av) >= 0){
		strcat(cmd, "play");
	}else if(opt_idx("-sox", ac, av) >= 0){
		strcat(cmd, "sox");
		fn = opt_str("-sox", ac, av, "-d");
	}
	if(cmd[0]){
		sprintf(cmd + strlen(cmd), " -t raw -r %d -b %d %s -c %d - %s",
			ot->smp_freq, ot->bit_len,
			ot->sign ? "-s" : "-u",
			ot->ch_num, fn);
		if((ot->fp = popen(cmd, "w")) == NULL) ERR("popen");
	}
	ot->amp = ot->bit_len == 8 ? 127 : 32767;
	ot->base = ot->sign ? 0 : ot->amp + 1;
	ot->iv_min = ot->base - (ot->amp + 1);
	ot->iv_max = ot->base + ot->amp;
}

void
out_do(struct out_rec *ot, double v)
{
	int iv;

	iv = ot->base + (int)(v *ot->amp);
	if(iv > ot->iv_max) iv = ot->iv_max;
	if(iv < ot->iv_min) iv = ot->iv_min;
	switch(ot->bit_len){
	case 8:
		fputc(iv, ot->fp);
		break;
	case 16:
		fputc(iv & 0xff, ot->fp);
		fputc((iv >> 8) & 0xff, ot->fp);
		break;
	}
}

#define MIDI_CH_N	16
int ch_vol[ MIDI_CH_N ];
int ch_pan[ MIDI_CH_N ];
// MIDIチャンネルごとのPanpot (14 bit)

void
data_out(struct out_rec *ot, double evt_sec)
{
	double v, sec, freq, dsec;
	double vl, vr, pan;
	double release;
	int i;

	release = 0.3;
	while((sec = (double)ot->smp_cnt / ot->smp_freq) < evt_sec){
		vl = vr = 0;
		for(i=0; i<NOTE_BUF_N; i++){
			if(note_buf_is_free(i)) continue;
			freq = note_to_freq(note_buf[i].note);
			dsec = sec - note_buf[i].on_sec;
			v = sin(2 * M_PI * freq * dsec);
			v *= note_buf[i].velo / 127.0;
			v *= ch_vol[ note_buf[i].ch ] / (double)((1<<14)-1);
			if(note_buf[i].onoff == 0){
				dsec = sec - note_buf[i].off_sec;
				v *= 1 - dsec / release;
				if(dsec >= release) note_buf_free(i);
			}
			if(ot->ch_num == 1){
				vl += v;
			}else{
				pan = ch_pan[ note_buf[i].ch ] / (double)(1<<14);
				// 鍵盤情報のMIDIチャンネルから、
				// MIDIチャンネルごとのPanpot (14 bit) を参照
				// 14 bit の値を、0.0〜1.0 に換算
				// 0.0 〜 1.0 の値を、変数 pan へ
				
				vl += (1 - pan) * v;
				vr += pan * v;
			}
		}
		out_do(ot, vl / 16);
		if(ot->ch_num > 1) out_do(ot, vr / 16);
		ot->smp_cnt++;
	}
}

void
note_onoff(int onoff, double evt_sec, int ch, int note, int velo)
{
	int i;

	if(ch == 9) return;

	if(onoff){
		if((i = note_buf_search(-1, -1, -1)) < 0){
			MSG("note_buf full");
			return;
		}
		note_buf[i].note = note;
		note_buf[i].ch = ch;
		note_buf[i].onoff = 1;
		note_buf[i].on_sec = evt_sec;
		note_buf[i].velo = velo;
	}else{
		if((i = note_buf_search(ch, note, 1)) < 0) return;
		note_buf[i].onoff = 0;
		note_buf[i].off_sec = evt_sec;
	}
}

int
main(int ac, char **av)
{
	int div4, delta_sum;
	int i, n, v, hi, low, note, velo;
	int ch, type;
	double sec;
	struct out_rec otr;

	out_init(&otr, ac, av);
	note_buf_init();
	for(i=0; i<MIDI_CH_N; i++){
		ch_vol[i] = 0;
		ch_pan[i] = 1<<(14-1);
		// MIDIチャンネルごとのPanpotを、中央の設定で初期化
		
	}

	div4 = header();

	if(!rd_str_chk(4, "MTrk")) ERR("track id");
	v = rd_int(4); /* skip */

	hi = low = 0;
	delta_sum = 0;
	while((v = rd_delta()) != EOF){
		delta_sum += v;
		sec = (double)delta_sum / div4 * 0.5;
		
		if((v = rd()) & 0x80){
			hi = (v >> 4) & 0xf;
			low  = v & 0xf;
		}else bk(v);

		data_out(&otr, sec);

		ch = low;
		switch(hi){
		case 8:
		case 9:
			note = rd();
			velo = rd();
			note_onoff(hi == 9, sec, ch, note, velo);
			break;
		case 0xb: /* control change */
			type = rd();
			v = rd();
			switch(type){
			case 7: /* channel volume msb */
				ch_vol[ch] &= ~(127<<7);
				ch_vol[ch] |= v<<7;
				break;
			case 39: /* channel volume lsb */
				ch_vol[ch] &= ~127;
				ch_vol[ch] |= v;
				break;
			case 10: /* pan msb */
			// 2バイト目の type が 10 ならば、
			
				ch_pan[ch] &= ~(127<<7);
				ch_pan[ch] |= v<<7;
				// MIDIチャンネルごとのPanpotの
				// 上位 7 bit の値を、変数 v の値に変更
				
				break;
			case 42: /* pan lsb */
			// 2バイト目の type が 42 ならば、
			
				ch_pan[ch] &= ~127;
				ch_pan[ch] |= v;
				// MIDIチャンネルごとのPanpotの
				// 下位 7 bit の値を、変数 v の値に変更
				
				break;
				break;
			}
			break;
		case 0xa:
		case 0xe:
			rd();
			rd();
			break;
		case 0xc:		
		case 0xd:
			rd();
			break;
		case 0xf:
			rd();
			switch(low){
			case 0:
				while(rd() != 0xf7);
				break;
			case 1:
			case 3:
				rd();
				break;
			case 2:
				rd();
				rd();
				break;
			case 0xf:
				n = rd();
				for(i=0; i<n; i++) rd();
				break;
			default:
				break;
			}
			break;
		}
	}
	if(otr.fp != stdout) pclose(otr.fp);
	return 0;
}

/* EOF */


prog3.c 解説

prog2.c からの変更箇所のみ

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <math.h>

#define MSG(s) fprintf(stderr, "%s() %s L%d : %s\n", __func__, __FILE__, __LINE__, s)
#define ERR(s) do{ fprintf(stderr, "ERR "); MSG(s); exit(1); }while(0)

int bk_buf = -1;

int
rd(void)
{
	int v;

	if((v = bk_buf) < 0) return getchar();
	bk_buf = -1;
	return v;
}

void
bk(int v)
{
	if(bk_buf >= 0) ERR("give up");
	bk_buf = v;
}

void
rd_str(int n, char *s)
{
	int i;

	for(i=0; i<n; i++) s[i] = rd();
	s[i] = '\0';
}

int
rd_str_chk(int n, char *s)
{
	char buf[256];

	rd_str(n, buf);
	return strcmp(buf, s) == 0;
}

int
rd_int(int n) /* big endian */
{
	int i, v;

	v = 0;
	for(i=0; i<n; i++) v = (v << 8) | rd();
	return v;
}

int
rd_delta(void)
{
	int v, c;

	v = 0;
	do{
		if((c = rd()) == EOF) return EOF;
		v = (v << 7) | (c & 0x7f);
	}while(c & 0x80);
	return v;
}


#define NOTE_BUF_N	256

struct note_rec{
	int ch;
	int note;
	int onoff;
	double on_sec;
	double off_sec;
	int velo;
} note_buf[NOTE_BUF_N];

int
note_buf_is_free(int i)
{
	return note_buf[i].ch < 0;
}

void
note_buf_free(int i)
{
	note_buf[i].ch = -1;
}

void
note_buf_init(void)
{
	int i;

	for(i=0; i<NOTE_BUF_N; i++) note_buf_free(i);
}

int
note_buf_search(int ch, int note, int onoff)
{
	int i;

	for(i=0; i<NOTE_BUF_N; i++) {
		if( (ch < 0 && note_buf[i].ch < 0) ||
		    (note_buf[i].ch == ch &&
		     note_buf[i].note == note &&
		     note_buf[i].onoff == onoff) ) return i;
	}
	return -1;
}

int
header(void)
{
	int v;

	if(!rd_str_chk(4, "MThd")) ERR("header id");
	if(rd_int(4) != 6) ERR("header size");
	if(rd_int(2) != 0) ERR("header format type");
	if(rd_int(2) != 1) ERR("header track num");
	if((v = rd_int(2)) & 0x8000) ERR("header division");
	return v; /* div4 */
}

double
note_to_freq(int note)
{
	return 440 * pow(2, (note - 69) / 12.0);
}

int
opt_idx(char *key, int ac, char **av)
{
	int i;

	for(i=1; i<ac; i++) if(strcmp(av[i], key) == 0) return i;
	return -1;
}

char *
opt_str(char *key, int ac, char **av, char *def)
{
	int i;

	i = opt_idx(key, ac, av);
	if(i < 0 || i+1 >= ac) return def;
	return av[i+1];
}

int
opt_int(char *key, int ac, char **av, int def)
{
	char *s;

	if((s = opt_str(key, ac, av, NULL)) == NULL) return def;
	return strtol(s, NULL, 0);
}

struct out_rec{
	int smp_freq, smp_cnt;
	int bit_len;
	int sign;
	int ch_num;
	FILE *fp;

	int base;
	int amp;
	int iv_min;
	int iv_max;
};

void
out_init(struct out_rec *ot, int ac, char **av)
{
	char cmd[1024], *fn;

	ot->smp_freq = opt_int("-r", ac, av, 8000);
	ot->smp_cnt = 0;
	ot->bit_len = opt_int("-b", ac, av, 8);
	if(ot->bit_len != 8 && ot->bit_len != 16) ERR("bit_len");
	ot->sign = (opt_idx("-s", ac, av) >= 0);
	ot->ch_num = opt_int("-c", ac, av, 1);

	ot->fp = stdout;
	cmd[0] = '\0';
	fn = "";
	if(opt_idx("-play", ac, av) >= 0){
		strcat(cmd, "play");
	}else if(opt_idx("-sox", ac, av) >= 0){
		strcat(cmd, "sox");
		fn = opt_str("-sox", ac, av, "-d");
	}
	if(cmd[0]){
		sprintf(cmd + strlen(cmd), " -t raw -r %d -b %d %s -c %d - %s",
			ot->smp_freq, ot->bit_len,
			ot->sign ? "-s" : "-u",
			ot->ch_num, fn);
		if((ot->fp = popen(cmd, "w")) == NULL) ERR("popen");
	}
	ot->amp = ot->bit_len == 8 ? 127 : 32767;
	ot->base = ot->sign ? 0 : ot->amp + 1;
	ot->iv_min = ot->base - (ot->amp + 1);
	ot->iv_max = ot->base + ot->amp;
}

void
out_do(struct out_rec *ot, double v)
{
	int iv;

	iv = ot->base + (int)(v *ot->amp);
	if(iv > ot->iv_max) iv = ot->iv_max;
	if(iv < ot->iv_min) iv = ot->iv_min;
	switch(ot->bit_len){
	case 8:
		fputc(iv, ot->fp);
		break;
	case 16:
		fputc(iv & 0xff, ot->fp);
		fputc((iv >> 8) & 0xff, ot->fp);
		break;
	}
}

#define MIDI_CH_N	16
int ch_vol[ MIDI_CH_N ];
int ch_pan[ MIDI_CH_N ];

void
data_out(struct out_rec *ot, double evt_sec)
{
	double v, sec, freq, dsec;
	double vl, vr, pan;
	double release;
	int i;

	release = 0.3;
	while((sec = (double)ot->smp_cnt / ot->smp_freq) < evt_sec){
		vl = vr = 0;
		for(i=0; i<NOTE_BUF_N; i++){
			if(note_buf_is_free(i)) continue;
			freq = note_to_freq(note_buf[i].note);
			dsec = sec - note_buf[i].on_sec;
			v = sin(2 * M_PI * freq * dsec);
			v *= note_buf[i].velo / 127.0;
			v *= ch_vol[ note_buf[i].ch ] / (double)((1<<14)-1);
			if(note_buf[i].onoff == 0){
				dsec = sec - note_buf[i].off_sec;
				v *= 1 - dsec / release;
				if(dsec >= release) note_buf_free(i);
			}
			if(ot->ch_num == 1){
				vl += v;
			}else{
				pan = ch_pan[ note_buf[i].ch ] / (double)(1<<14);
				vl += (1 - pan) * v;
				vr += pan * v;
			}
		}
		out_do(ot, vl / 16);
		if(ot->ch_num > 1) out_do(ot, vr / 16);
		ot->smp_cnt++;
	}
}

void
note_onoff(int onoff, double evt_sec, int ch, int note, int velo)
{
	int i;

	if(ch == 9) return;

	if(onoff){
		if((i = note_buf_search(-1, -1, -1)) < 0){
			MSG("note_buf full");
			return;
		}
		note_buf[i].note = note;
		note_buf[i].ch = ch;
		note_buf[i].onoff = 1;
		note_buf[i].on_sec = evt_sec;
		note_buf[i].velo = velo;
	}else{
		if((i = note_buf_search(ch, note, 1)) < 0) return;
		note_buf[i].onoff = 0;
		note_buf[i].off_sec = evt_sec;
	}
}

int
main(int ac, char **av)
{
	int div4, delta_sum;
	int i, n, v, hi, low, note, velo;
	int ch, type;
	double sec;
	struct out_rec otr;
	int tempo, tempo_delta_sum;
	double tempo_sec;

	out_init(&otr, ac, av);
	note_buf_init();
	for(i=0; i<MIDI_CH_N; i++){
		ch_vol[i] = 0;
		ch_pan[i] = 1<<(14-1);
	}
	tempo = 500000;
	tempo_delta_sum = 0;
	tempo_sec = 0;

	div4 = header();

	if(!rd_str_chk(4, "MTrk")) ERR("track id");
	v = rd_int(4); /* skip */

	hi = low = 0;
	delta_sum = 0;
	while((v = rd_delta()) != EOF){
		delta_sum += v;
		sec = tempo_sec + (double)(delta_sum - tempo_delta_sum) / div4 * tempo * 0.000001;
		
		if((v = rd()) & 0x80){
			hi = (v >> 4) & 0xf;
			low  = v & 0xf;
		}else bk(v);

		data_out(&otr, sec);

		ch = low;
		switch(hi){
		case 8:
		case 9:
			note = rd();
			velo = rd();
			note_onoff(hi == 9, sec, ch, note, velo);
			break;
		case 0xb: /* control change */
			type = rd();
			v = rd();
			switch(type){
			case 7: /* channel volume msb */
				ch_vol[ch] &= ~(127<<7);
				ch_vol[ch] |= v<<7;
				break;
			case 39: /* channel volume lsb */
				ch_vol[ch] &= ~127;
				ch_vol[ch] |= v;
				break;
			case 10: /* pan msb */
				ch_pan[ch] &= ~(127<<7);
				ch_pan[ch] |= v<<7;
				break;
			case 42: /* pan lsb */
				ch_pan[ch] &= ~127;
				ch_pan[ch] |= v;
				break;
			}
			break;
		case 0xa:
		case 0xe:
			rd();
			rd();
			break;
		case 0xc:		
		case 0xd:
			rd();
			break;
		case 0xf:
			type = rd();
			switch(low){
			case 0:
				while(rd() != 0xf7);
				break;
			case 1:
			case 3:
				rd();
				break;
			case 2:
				rd();
				rd();
				break;
			case 0xf: /* meta */
				n = rd();
				switch(type){
				case 0x51: /* set tempo */
					v = rd_int(n);
					tempo = v;
					tempo_delta_sum = delta_sum;
					tempo_sec = sec;
					break;
				default:
					for(i=0; i<n; i++) rd();
					break;
				}
				break;
			default:
				break;
			}
			break;
		}
	}
	if(otr.fp != stdout) pclose(otr.fp);
	return 0;
}

/* EOF */


#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <math.h>

#define MSG(s) fprintf(stderr, "%s() %s L%d : %s\n", __func__, __FILE__, __LINE__, s)
#define ERR(s) do{ fprintf(stderr, "ERR "); MSG(s); exit(1); }while(0)

int bk_buf = -1;

int
rd(void)
{
	int v;

	if((v = bk_buf) < 0) return getchar();
	bk_buf = -1;
	return v;
}

void
bk(int v)
{
	if(bk_buf >= 0) ERR("give up");
	bk_buf = v;
}

void
rd_str(int n, char *s)
{
	int i;

	for(i=0; i<n; i++) s[i] = rd();
	s[i] = '\0';
}

int
rd_str_chk(int n, char *s)
{
	char buf[256];

	rd_str(n, buf);
	return strcmp(buf, s) == 0;
}

int
rd_int(int n) /* big endian */
{
	int i, v;

	v = 0;
	for(i=0; i<n; i++) v = (v << 8) | rd();
	return v;
}

int
rd_delta(void)
{
	int v, c;

	v = 0;
	do{
		if((c = rd()) == EOF) return EOF;
		v = (v << 7) | (c & 0x7f);
	}while(c & 0x80);
	return v;
}


#define NOTE_BUF_N	256

struct note_rec{
	int ch;
	int note;
	int onoff;
	double on_sec;
	double off_sec;
	int velo;
} note_buf[NOTE_BUF_N];

int
note_buf_is_free(int i)
{
	return note_buf[i].ch < 0;
}

void
note_buf_free(int i)
{
	note_buf[i].ch = -1;
}

void
note_buf_init(void)
{
	int i;

	for(i=0; i<NOTE_BUF_N; i++) note_buf_free(i);
}

int
note_buf_search(int ch, int note, int onoff)
{
	int i;

	for(i=0; i<NOTE_BUF_N; i++) {
		if( (ch < 0 && note_buf[i].ch < 0) ||
		    (note_buf[i].ch == ch &&
		     note_buf[i].note == note &&
		     note_buf[i].onoff == onoff) ) return i;
	}
	return -1;
}

int
header(void)
{
	int v;

	if(!rd_str_chk(4, "MThd")) ERR("header id");
	if(rd_int(4) != 6) ERR("header size");
	if(rd_int(2) != 0) ERR("header format type");
	if(rd_int(2) != 1) ERR("header track num");
	if((v = rd_int(2)) & 0x8000) ERR("header division");
	return v; /* div4 */
}

double
note_to_freq(int note)
{
	return 440 * pow(2, (note - 69) / 12.0);
}

int
opt_idx(char *key, int ac, char **av)
{
	int i;

	for(i=1; i<ac; i++) if(strcmp(av[i], key) == 0) return i;
	return -1;
}

char *
opt_str(char *key, int ac, char **av, char *def)
{
	int i;

	i = opt_idx(key, ac, av);
	if(i < 0 || i+1 >= ac) return def;
	return av[i+1];
}

int
opt_int(char *key, int ac, char **av, int def)
{
	char *s;

	if((s = opt_str(key, ac, av, NULL)) == NULL) return def;
	return strtol(s, NULL, 0);
}

struct out_rec{
	int smp_freq, smp_cnt;
	int bit_len;
	int sign;
	int ch_num;
	FILE *fp;

	int base;
	int amp;
	int iv_min;
	int iv_max;
};

void
out_init(struct out_rec *ot, int ac, char **av)
{
	char cmd[1024], *fn;

	ot->smp_freq = opt_int("-r", ac, av, 8000);
	ot->smp_cnt = 0;
	ot->bit_len = opt_int("-b", ac, av, 8);
	if(ot->bit_len != 8 && ot->bit_len != 16) ERR("bit_len");
	ot->sign = (opt_idx("-s", ac, av) >= 0);
	ot->ch_num = opt_int("-c", ac, av, 1);

	ot->fp = stdout;
	cmd[0] = '\0';
	fn = "";
	if(opt_idx("-play", ac, av) >= 0){
		strcat(cmd, "play");
	}else if(opt_idx("-sox", ac, av) >= 0){
		strcat(cmd, "sox");
		fn = opt_str("-sox", ac, av, "-d");
	}
	if(cmd[0]){
		sprintf(cmd + strlen(cmd), " -t raw -r %d -b %d %s -c %d - %s",
			ot->smp_freq, ot->bit_len,
			ot->sign ? "-s" : "-u",
			ot->ch_num, fn);
		if((ot->fp = popen(cmd, "w")) == NULL) ERR("popen");
	}
	ot->amp = ot->bit_len == 8 ? 127 : 32767;
	ot->base = ot->sign ? 0 : ot->amp + 1;
	ot->iv_min = ot->base - (ot->amp + 1);
	ot->iv_max = ot->base + ot->amp;
}

void
out_do(struct out_rec *ot, double v)
{
	int iv;

	iv = ot->base + (int)(v *ot->amp);
	if(iv > ot->iv_max) iv = ot->iv_max;
	if(iv < ot->iv_min) iv = ot->iv_min;
	switch(ot->bit_len){
	case 8:
		fputc(iv, ot->fp);
		break;
	case 16:
		fputc(iv & 0xff, ot->fp);
		fputc((iv >> 8) & 0xff, ot->fp);
		break;
	}
}

#define MIDI_CH_N	16
int ch_vol[ MIDI_CH_N ];
int ch_pan[ MIDI_CH_N ];

void
data_out(struct out_rec *ot, double evt_sec)
{
	double v, sec, freq, dsec;
	double vl, vr, pan;
	double release;
	int i;

	release = 0.3;
	while((sec = (double)ot->smp_cnt / ot->smp_freq) < evt_sec){
		vl = vr = 0;
		for(i=0; i<NOTE_BUF_N; i++){
			if(note_buf_is_free(i)) continue;
			freq = note_to_freq(note_buf[i].note);
			dsec = sec - note_buf[i].on_sec;
			v = sin(2 * M_PI * freq * dsec);
			v *= note_buf[i].velo / 127.0;
			v *= ch_vol[ note_buf[i].ch ] / (double)((1<<14)-1);
			if(note_buf[i].onoff == 0){
				dsec = sec - note_buf[i].off_sec;
				v *= 1 - dsec / release;
				if(dsec >= release) note_buf_free(i);
			}
			if(ot->ch_num == 1){
				vl += v;
			}else{
				pan = ch_pan[ note_buf[i].ch ] / (double)(1<<14);
				vl += (1 - pan) * v;
				vr += pan * v;
			}
		}
		out_do(ot, vl / 16);
		if(ot->ch_num > 1) out_do(ot, vr / 16);
		ot->smp_cnt++;
	}
}

void
note_onoff(int onoff, double evt_sec, int ch, int note, int velo)
{
	int i;

	if(ch == 9) return;

	if(onoff){
		if((i = note_buf_search(-1, -1, -1)) < 0){
			MSG("note_buf full");
			return;
		}
		note_buf[i].note = note;
		note_buf[i].ch = ch;
		note_buf[i].onoff = 1;
		note_buf[i].on_sec = evt_sec;
		note_buf[i].velo = velo;
	}else{
		if((i = note_buf_search(ch, note, 1)) < 0) return;
		note_buf[i].onoff = 0;
		note_buf[i].off_sec = evt_sec;
	}
}

int
main(int ac, char **av)
{
	int div4, delta_sum;
	int i, n, v, hi, low, note, velo;
	int ch, type;
	double sec;
	struct out_rec otr;
	int tempo, tempo_delta_sum;
	double tempo_sec;
	// 変数 tempo, tempo_delta_sum, tempo_sec を追加
	// tempo は、四分音符一つあたりのマイクロ秒
	// tempo_delta_sum は、テンポを設定したときのデルタタイムの合計
	// tempo_sec は、テンポを設定したときの時刻(秒)
	
	out_init(&otr, ac, av);
	note_buf_init();
	for(i=0; i<MIDI_CH_N; i++){
		ch_vol[i] = 0;
		ch_pan[i] = 1<<(14-1);
	}
	tempo = 500000;
	tempo_delta_sum = 0;
	tempo_sec = 0;
	// 追加したテンポ関連の変数の初期値を設定
	// (四分音符一つあたり 0.5 秒)
	
	div4 = header();

	if(!rd_str_chk(4, "MTrk")) ERR("track id");
	v = rd_int(4); /* skip */

	hi = low = 0;
	delta_sum = 0;
	while((v = rd_delta()) != EOF){
		delta_sum += v;
		sec = tempo_sec + (double)(delta_sum - tempo_delta_sum) / div4 * tempo * 0.000001;
		// デルタタイムの合計から、時刻の換算する処理
		// テンポ関連の変数を使うように変更
		// テンポ設定時からの経過時間を出してから、テンポ設定時の時刻に足し算
		
		if((v = rd()) & 0x80){
			hi = (v >> 4) & 0xf;
			low  = v & 0xf;
		}else bk(v);

		data_out(&otr, sec);

		ch = low;
		switch(hi){
		case 8:
		case 9:
			note = rd();
			velo = rd();
			note_onoff(hi == 9, sec, ch, note, velo);
			break;
		case 0xb: /* control change */
			type = rd();
			v = rd();
			switch(type){
			case 7: /* channel volume msb */
				ch_vol[ch] &= ~(127<<7);
				ch_vol[ch] |= v<<7;
				break;
			case 39: /* channel volume lsb */
				ch_vol[ch] &= ~127;
				ch_vol[ch] |= v;
				break;
			case 10: /* pan msb */
				ch_pan[ch] &= ~(127<<7);
				ch_pan[ch] |= v<<7;
				break;
			case 42: /* pan lsb */
				ch_pan[ch] &= ~127;
				ch_pan[ch] |= v;
				break;
			}
			break;
		case 0xa:
		case 0xe:
			rd();
			rd();
			break;
		case 0xc:		
		case 0xd:
			rd();
			break;
		case 0xf:
			type = rd();
			// これまで 2バイト目を読み飛ばしていたが
			// イベントのタイプとして、変数 type へ設定
			
			switch(low){
			case 0:
				while(rd() != 0xf7);
				break;
			case 1:
			case 3:
				rd();
				break;
			case 2:
				rd();
				rd();
				break;
			case 0xf: /* meta */
				n = rd();
				switch(type){
				case 0x51: /* set tempo */
				// メタ・イベントのタイプが 0x51 (set tempo)ならば、
				
					v = rd_int(n);
					// 続く n バイト(set tempo なら 3バイト) を、
					// ビッグ・エンディアンの整数として読み込み
					// 変数 v へ
					
					tempo = v;
					tempo_delta_sum = delta_sum;
					tempo_sec = sec;
					// 追加した tempo 関連の変数を設定
					
					break;
				default:
					for(i=0; i<n; i++) rd();
					break;
				}
				break;
			default:
				break;
			}
			break;
		}
	}
	if(otr.fp != stdout) pclose(otr.fp);
	return 0;
}

/* EOF */


prog_onoff8.c 解説

主に prog_onoff6.c からの変更箇所のみ

#include <stdio.h>
#include <math.h>

int
main()
{
	int i, v, c, c1, c2, low, hi;
	char id[5];
	int div4, delta_sum;
	double sec;
	int tempo, tempo_delta_sum;
	double tempo_sec;

	printf("header\n");

	for(i=0; i<4; i++) id[i] = getchar();
	id[i] = '\0';
	printf("id='%s'\n", id);

	v = 0;
	for(i=0; i<4; i++) v = (v << 8) | getchar();
	printf("size=%d\n", v);

	v = 0;
	for(i=0; i<2; i++) v = (v << 8) | getchar();
	printf("format type=%d\n", v);

	v = 0;
	for(i=0; i<2; i++) v = (v << 8) | getchar();
	printf("track num=%d\n", v);

	v = 0;
	for(i=0; i<2; i++) v = (v << 8) | getchar();
	printf("time division=%d (0x%x)\n\n", v, v);
	div4 = v;


	printf("track\n");

	for(i=0; i<4; i++) id[i] = getchar();
	id[i] = '\0';
	printf("id='%s'\n", id);

	v = 0;
	for(i=0; i<4; i++) v = (v << 8) | getchar();
	printf("size=%d\n", v);

	tempo = 500000;
	tempo_delta_sum = 0;
	tempo_sec = 0;

	delta_sum = 0;
	while(1){
		v = 0;
		do{
			if((c = getchar()) == EOF) break;
			v = (v << 7) | (c & 0x7f);
		}while(c & 0x80);
		if(c == EOF) break;
		delta_sum += v;
		sec = tempo_sec + (double)(delta_sum - tempo_delta_sum) / div4 * tempo * 0.000001;
		printf("sec=%.3f ", sec);
		
		c = getchar();
		if(c & 0x80){
			c1 = c;
			hi = (c1 >> 4) & 0xf;
			low = c1 & 0xf;
			c2 = getchar();
		}else{
			c2 = c;
		}

		if(hi == 9 || hi == 8){
			printf("%s ch=%d ", hi == 9 ? "on" : "off", low);
			printf("note=%d ", c2);
			printf("velo=%d\n", getchar());
			continue;
		}

		if(c1 == 0xff){
			printf("meta event type=%d ", c2);
			v = getchar();
			printf("len=%d ", v);

			if(c2 == 0x51){ /* set tempo */
				tempo = 0;
			}
			for(i=0; i<v; i++){
				c = getchar(); /* skip */
				if(i < 16) printf("0x%02x ", c);
				if(c2 == 0x51){ /* set tempo */
					tempo <<= 8;
					tempo |= c;
				}
			}
			printf("\n");
			if(c2 == 0x51){ /* set tempo */
				tempo_delta_sum = delta_sum;
				tempo_sec = sec;
			}
			continue;
		}

		if(c1 == 0xf0){
			printf("sys ex len=%d ...\n", c2);
			while(getchar() != 0xf7);
			continue;
		}

		if(hi == 0xb){
			printf("%s ch=%d type=%d v=%d\n",
			       c2 < 120 ? "ctl chg" : "chg mode msg",
			       low, c2, getchar());
			continue;
		}

		if(hi == 0xc){
			printf("prog num ch=%d v=%d\n", low, c2);
			continue;
		}

		if(hi == 0xe){
			printf("pitch wheel change ch=%d lsb=%d msb=%d\n", low, c2, getchar());
			continue;
		}

		printf("c1=0x%02x, c2=0x%02x\n", c1, c2);
		break;
	}
	return 0;
}

/* EOF */


#include <stdio.h>
#include <math.h>

int
main()
{
	int i, v, c, c1, c2, low, hi;
	char id[5];
	int div4, delta_sum;
	double sec;
	int tempo, tempo_delta_sum;
	double tempo_sec;
	// 変数 div4, delta_sum, sec
	// tempo, tempo_dleta_sum, tempo_sec 追加
	//
	// div4 は、ヘッダの分解能
	// delta_sum は、デルタタイムの合計
	// sec は、時刻
	// tempo は、四分音符一つあたりのマイクロ秒
	// tempo_delta_sum は、テンポ設定時のデルタタイムの合計
	// tempo_sec は、テンポ設定時の時刻
	
	printf("header\n");

	for(i=0; i<4; i++) id[i] = getchar();
	id[i] = '\0';
	printf("id='%s'\n", id);

	v = 0;
	for(i=0; i<4; i++) v = (v << 8) | getchar();
	printf("size=%d\n", v);

	v = 0;
	for(i=0; i<2; i++) v = (v << 8) | getchar();
	printf("format type=%d\n", v);

	v = 0;
	for(i=0; i<2; i++) v = (v << 8) | getchar();
	printf("track num=%d\n", v);

	v = 0;
	for(i=0; i<2; i++) v = (v << 8) | getchar();
	printf("time division=%d (0x%x)\n\n", v, v);
	div4 = v;
	// ヘッダの分解能を、追加した変数 div4 へ
	
	printf("track\n");

	for(i=0; i<4; i++) id[i] = getchar();
	id[i] = '\0';
	printf("id='%s'\n", id);

	v = 0;
	for(i=0; i<4; i++) v = (v << 8) | getchar();
	printf("size=%d\n", v);

	tempo = 500000;
	tempo_delta_sum = 0;
	tempo_sec = 0;
	// 追加したテンポ関連の変数の初期値を設定
	// (四分音符一つあたり 0.5 秒)
	
	delta_sum = 0;
	// 追加した変数 delta_sum 初期化
	
	while(1){
		v = 0;
		do{
			if((c = getchar()) == EOF) break;
			v = (v << 7) | (c & 0x7f);
		}while(c & 0x80);
		if(c == EOF) break;
		delta_sum += v;
		sec = tempo_sec + (double)(delta_sum - tempo_delta_sum) / div4 * tempo * 0.000001;
		printf("sec=%.3f ", sec);
		// 追加した変数 delta_sum を更新し、
		// 時刻を算出して表示
		
		c = getchar();
		if(c & 0x80){
			c1 = c;
			hi = (c1 >> 4) & 0xf;
			low = c1 & 0xf;
			c2 = getchar();
		}else{
			c2 = c;
		}

		if(hi == 9 || hi == 8){
			printf("%s ch=%d ", hi == 9 ? "on" : "off", low);
			printf("note=%d ", c2);
			printf("velo=%d\n", getchar());
			continue;
		}

		if(c1 == 0xff){
			printf("meta event type=%d ", c2);
			v = getchar();
			printf("len=%d ", v);

			if(c2 == 0x51){ /* set tempo */
				tempo = 0;
			}
			// メタ・イベントの 2バイト目が 0x51 (set tempo ならば)
			// 変数 tempo を 設定しなおす前処理
			
			for(i=0; i<v; i++){
				c = getchar(); /* skip */
				if(i < 16) printf("0x%02x ", c);
				if(c2 == 0x51){ /* set tempo */
				// メタ・イベントの 2バイト目が 0x51 (set tempo ならば)
				
					tempo <<= 8;
					tempo |= c;
					// ビッグ・エンディアンの 3 バイトの整数を
					// 変数 tempo へ
					
				}
			}
			printf("\n");
			if(c2 == 0x51){ /* set tempo */
			// メタ・イベントの 2バイト目が 0x51 (set tempo ならば)
			
				tempo_delta_sum = delta_sum;
				tempo_sec = sec;
				// 追加した tempo 関連の変数を設定
				
			}
			continue;
		}

		if(c1 == 0xf0){
			printf("sys ex len=%d ...\n", c2);
			while(getchar() != 0xf7);
			continue;
		}

		if(hi == 0xb){
			printf("%s ch=%d type=%d v=%d\n",
			       c2 < 120 ? "ctl chg" : "chg mode msg",
			       low, c2, getchar());
			continue;
		}

		if(hi == 0xc){
			printf("prog num ch=%d v=%d\n", low, c2);
			continue;
		}

		if(hi == 0xe){
			printf("pitch wheel change ch=%d lsb=%d msb=%d\n", low, c2, getchar());
			continue;
		}

		printf("c1=0x%02x, c2=0x%02x\n", c1, c2);
		break;
	}
	return 0;
}

/* EOF */


prog4.c 解説

prog3.c からの変更箇所のみ

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <math.h>

#define MSG(s) fprintf(stderr, "%s() %s L%d : %s\n", __func__, __FILE__, __LINE__, s)
#define ERR(s) do{ fprintf(stderr, "ERR "); MSG(s); exit(1); }while(0)

int bk_buf = -1;

int
rd(void)
{
	int v;

	if((v = bk_buf) < 0) return getchar();
	bk_buf = -1;
	return v;
}

void
bk(int v)
{
	if(bk_buf >= 0) ERR("give up");
	bk_buf = v;
}

void
rd_str(int n, char *s)
{
	int i;

	for(i=0; i<n; i++) s[i] = rd();
	s[i] = '\0';
}

int
rd_str_chk(int n, char *s)
{
	char buf[256];

	rd_str(n, buf);
	return strcmp(buf, s) == 0;
}

int
rd_int(int n) /* big endian */
{
	int i, v;

	v = 0;
	for(i=0; i<n; i++) v = (v << 8) | rd();
	return v;
}

int
rd_delta(void)
{
	int v, c;

	v = 0;
	do{
		if((c = rd()) == EOF) return EOF;
		v = (v << 7) | (c & 0x7f);
	}while(c & 0x80);
	return v;
}


#define NOTE_BUF_N	256

struct note_rec{
	int ch;
	int note;
	int onoff;
	double on_sec;
	double off_sec;
	int velo;
	double cycle, sec;
} note_buf[NOTE_BUF_N];

int
note_buf_is_free(int i)
{
	return note_buf[i].ch < 0;
}

void
note_buf_free(int i)
{
	note_buf[i].ch = -1;
}

void
note_buf_init(void)
{
	int i;

	for(i=0; i<NOTE_BUF_N; i++) note_buf_free(i);
}

int
note_buf_search(int ch, int note, int onoff)
{
	int i;

	for(i=0; i<NOTE_BUF_N; i++) {
		if( (ch < 0 && note_buf[i].ch < 0) ||
		    (note_buf[i].ch == ch &&
		     note_buf[i].note == note &&
		     note_buf[i].onoff == onoff) ) return i;
	}
	return -1;
}

int
header(void)
{
	int v;

	if(!rd_str_chk(4, "MThd")) ERR("header id");
	if(rd_int(4) != 6) ERR("header size");
	if(rd_int(2) != 0) ERR("header format type");
	if(rd_int(2) != 1) ERR("header track num");
	if((v = rd_int(2)) & 0x8000) ERR("header division");
	return v; /* div4 */
}

double
note_to_freq(int note)
{
	return 440 * pow(2, (note - 69) / 12.0);
}

int
opt_idx(char *key, int ac, char **av)
{
	int i;

	for(i=1; i<ac; i++) if(strcmp(av[i], key) == 0) return i;
	return -1;
}

char *
opt_str(char *key, int ac, char **av, char *def)
{
	int i;

	i = opt_idx(key, ac, av);
	if(i < 0 || i+1 >= ac) return def;
	return av[i+1];
}

int
opt_int(char *key, int ac, char **av, int def)
{
	char *s;

	if((s = opt_str(key, ac, av, NULL)) == NULL) return def;
	return strtol(s, NULL, 0);
}

struct out_rec{
	int smp_freq, smp_cnt;
	int bit_len;
	int sign;
	int ch_num;
	FILE *fp;

	int base;
	int amp;
	int iv_min;
	int iv_max;
};

void
out_init(struct out_rec *ot, int ac, char **av)
{
	char cmd[1024], *fn;

	ot->smp_freq = opt_int("-r", ac, av, 8000);
	ot->smp_cnt = 0;
	ot->bit_len = opt_int("-b", ac, av, 8);
	if(ot->bit_len != 8 && ot->bit_len != 16) ERR("bit_len");
	ot->sign = (opt_idx("-s", ac, av) >= 0);
	ot->ch_num = opt_int("-c", ac, av, 1);

	ot->fp = stdout;
	cmd[0] = '\0';
	fn = "";
	if(opt_idx("-play", ac, av) >= 0){
		strcat(cmd, "play");
	}else if(opt_idx("-sox", ac, av) >= 0){
		strcat(cmd, "sox");
		fn = opt_str("-sox", ac, av, "-d");
	}
	if(cmd[0]){
		sprintf(cmd + strlen(cmd), " -t raw -r %d -b %d %s -c %d - %s",
			ot->smp_freq, ot->bit_len,
			ot->sign ? "-s" : "-u",
			ot->ch_num, fn);
		if((ot->fp = popen(cmd, "w")) == NULL) ERR("popen");
	}
	ot->amp = ot->bit_len == 8 ? 127 : 32767;
	ot->base = ot->sign ? 0 : ot->amp + 1;
	ot->iv_min = ot->base - (ot->amp + 1);
	ot->iv_max = ot->base + ot->amp;
}

void
out_do(struct out_rec *ot, double v)
{
	int iv;

	iv = ot->base + (int)(v *ot->amp);
	if(iv > ot->iv_max) iv = ot->iv_max;
	if(iv < ot->iv_min) iv = ot->iv_min;
	switch(ot->bit_len){
	case 8:
		fputc(iv, ot->fp);
		break;
	case 16:
		fputc(iv & 0xff, ot->fp);
		fputc((iv >> 8) & 0xff, ot->fp);
		break;
	}
}

#define MIDI_CH_N	16
int ch_vol[ MIDI_CH_N ];
int ch_pan[ MIDI_CH_N ];

void
data_out(struct out_rec *ot, double evt_sec)
{
	double v, sec, freq, dsec;
	double vl, vr, pan;
	double release;
	int i;

	release = 0.3;
	while((sec = (double)ot->smp_cnt / ot->smp_freq) < evt_sec){
		vl = vr = 0;
		for(i=0; i<NOTE_BUF_N; i++){
			if(note_buf_is_free(i)) continue;
			freq = note_to_freq(note_buf[i].note);
			note_buf[i].cycle += freq * (sec - note_buf[i].sec);
			note_buf[i].sec = sec;
			v = sin(2 * M_PI * note_buf[i].cycle);
			v *= note_buf[i].velo / 127.0;
			v *= ch_vol[ note_buf[i].ch ] / (double)((1<<14)-1);
			if(note_buf[i].onoff == 0){
				dsec = sec - note_buf[i].off_sec;
				v *= 1 - dsec / release;
				if(dsec >= release) note_buf_free(i);
			}
			if(ot->ch_num == 1){
				vl += v;
			}else{
				pan = ch_pan[ note_buf[i].ch ] / (double)(1<<14);
				vl += (1 - pan) * v;
				vr += pan * v;
			}
		}
		out_do(ot, vl / 16);
		if(ot->ch_num > 1) out_do(ot, vr / 16);
		ot->smp_cnt++;
	}
}

void
note_onoff(int onoff, double evt_sec, int ch, int note, int velo)
{
	int i;

	if(ch == 9) return;

	if(onoff){
		if((i = note_buf_search(-1, -1, -1)) < 0){
			MSG("note_buf full");
			return;
		}
		note_buf[i].note = note;
		note_buf[i].ch = ch;
		note_buf[i].onoff = 1;
		note_buf[i].on_sec = evt_sec;
		note_buf[i].velo = velo;
		note_buf[i].cycle = 0;
		note_buf[i].sec = evt_sec;
	}else{
		if((i = note_buf_search(ch, note, 1)) < 0) return;
		note_buf[i].onoff = 0;
		note_buf[i].off_sec = evt_sec;
	}
}

int
main(int ac, char **av)
{
	int div4, delta_sum;
	int i, n, v, hi, low, note, velo;
	int ch, type;
	double sec;
	struct out_rec otr;
	int tempo, tempo_delta_sum;
	double tempo_sec;

	out_init(&otr, ac, av);
	note_buf_init();
	for(i=0; i<MIDI_CH_N; i++){
		ch_vol[i] = 0;
		ch_pan[i] = 1<<(14-1);
	}
	tempo = 500000;
	tempo_delta_sum = 0;
	tempo_sec = 0;

	div4 = header();

	if(!rd_str_chk(4, "MTrk")) ERR("track id");
	v = rd_int(4); /* skip */

	hi = low = 0;
	delta_sum = 0;
	while((v = rd_delta()) != EOF){
		delta_sum += v;
		sec = tempo_sec + (double)(delta_sum - tempo_delta_sum) / div4 * tempo * 0.000001;
		
		if((v = rd()) & 0x80){
			hi = (v >> 4) & 0xf;
			low  = v & 0xf;
		}else bk(v);

		data_out(&otr, sec);

		ch = low;
		switch(hi){
		case 8:
		case 9:
			note = rd();
			velo = rd();
			note_onoff(hi == 9, sec, ch, note, velo);
			break;
		case 0xb: /* control change */
			type = rd();
			v = rd();
			switch(type){
			case 7: /* channel volume msb */
				ch_vol[ch] &= ~(127<<7);
				ch_vol[ch] |= v<<7;
				break;
			case 39: /* channel volume lsb */
				ch_vol[ch] &= ~127;
				ch_vol[ch] |= v;
				break;
			case 10: /* pan msb */
				ch_pan[ch] &= ~(127<<7);
				ch_pan[ch] |= v<<7;
				break;
			case 42: /* pan lsb */
				ch_pan[ch] &= ~127;
				ch_pan[ch] |= v;
				break;
			}
			break;
		case 0xa:
		case 0xe:
			rd();
			rd();
			break;
		case 0xc:		
		case 0xd:
			rd();
			break;
		case 0xf:
			type = rd();
			switch(low){
			case 0:
				while(rd() != 0xf7);
				break;
			case 1:
			case 3:
				rd();
				break;
			case 2:
				rd();
				rd();
				break;
			case 0xf: /* meta */
				n = rd();
				switch(type){
				case 0x51: /* set tempo */
					v = rd_int(n);
					tempo = v;
					tempo_delta_sum = delta_sum;
					tempo_sec = sec;
					break;
				default:
					for(i=0; i<n; i++) rd();
					break;
				}
				break;
			default:
				break;
			}
			break;
		}
	}
	if(otr.fp != stdout) pclose(otr.fp);
	return 0;
}

/* EOF */


#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <math.h>

#define MSG(s) fprintf(stderr, "%s() %s L%d : %s\n", __func__, __FILE__, __LINE__, s)
#define ERR(s) do{ fprintf(stderr, "ERR "); MSG(s); exit(1); }while(0)

int bk_buf = -1;

int
rd(void)
{
	int v;

	if((v = bk_buf) < 0) return getchar();
	bk_buf = -1;
	return v;
}

void
bk(int v)
{
	if(bk_buf >= 0) ERR("give up");
	bk_buf = v;
}

void
rd_str(int n, char *s)
{
	int i;

	for(i=0; i<n; i++) s[i] = rd();
	s[i] = '\0';
}

int
rd_str_chk(int n, char *s)
{
	char buf[256];

	rd_str(n, buf);
	return strcmp(buf, s) == 0;
}

int
rd_int(int n) /* big endian */
{
	int i, v;

	v = 0;
	for(i=0; i<n; i++) v = (v << 8) | rd();
	return v;
}

int
rd_delta(void)
{
	int v, c;

	v = 0;
	do{
		if((c = rd()) == EOF) return EOF;
		v = (v << 7) | (c & 0x7f);
	}while(c & 0x80);
	return v;
}


#define NOTE_BUF_N	256

struct note_rec{
	int ch;
	int note;
	int onoff;
	double on_sec;
	double off_sec;
	int velo;
	double cycle, sec;
	// 最後に出力したサイクルと時刻
	
} note_buf[NOTE_BUF_N];

int
note_buf_is_free(int i)
{
	return note_buf[i].ch < 0;
}

void
note_buf_free(int i)
{
	note_buf[i].ch = -1;
}

void
note_buf_init(void)
{
	int i;

	for(i=0; i<NOTE_BUF_N; i++) note_buf_free(i);
}

int
note_buf_search(int ch, int note, int onoff)
{
	int i;

	for(i=0; i<NOTE_BUF_N; i++) {
		if( (ch < 0 && note_buf[i].ch < 0) ||
		    (note_buf[i].ch == ch &&
		     note_buf[i].note == note &&
		     note_buf[i].onoff == onoff) ) return i;
	}
	return -1;
}

int
header(void)
{
	int v;

	if(!rd_str_chk(4, "MThd")) ERR("header id");
	if(rd_int(4) != 6) ERR("header size");
	if(rd_int(2) != 0) ERR("header format type");
	if(rd_int(2) != 1) ERR("header track num");
	if((v = rd_int(2)) & 0x8000) ERR("header division");
	return v; /* div4 */
}

double
note_to_freq(int note)
{
	return 440 * pow(2, (note - 69) / 12.0);
}

int
opt_idx(char *key, int ac, char **av)
{
	int i;

	for(i=1; i<ac; i++) if(strcmp(av[i], key) == 0) return i;
	return -1;
}

char *
opt_str(char *key, int ac, char **av, char *def)
{
	int i;

	i = opt_idx(key, ac, av);
	if(i < 0 || i+1 >= ac) return def;
	return av[i+1];
}

int
opt_int(char *key, int ac, char **av, int def)
{
	char *s;

	if((s = opt_str(key, ac, av, NULL)) == NULL) return def;
	return strtol(s, NULL, 0);
}

struct out_rec{
	int smp_freq, smp_cnt;
	int bit_len;
	int sign;
	int ch_num;
	FILE *fp;

	int base;
	int amp;
	int iv_min;
	int iv_max;
};

void
out_init(struct out_rec *ot, int ac, char **av)
{
	char cmd[1024], *fn;

	ot->smp_freq = opt_int("-r", ac, av, 8000);
	ot->smp_cnt = 0;
	ot->bit_len = opt_int("-b", ac, av, 8);
	if(ot->bit_len != 8 && ot->bit_len != 16) ERR("bit_len");
	ot->sign = (opt_idx("-s", ac, av) >= 0);
	ot->ch_num = opt_int("-c", ac, av, 1);

	ot->fp = stdout;
	cmd[0] = '\0';
	fn = "";
	if(opt_idx("-play", ac, av) >= 0){
		strcat(cmd, "play");
	}else if(opt_idx("-sox", ac, av) >= 0){
		strcat(cmd, "sox");
		fn = opt_str("-sox", ac, av, "-d");
	}
	if(cmd[0]){
		sprintf(cmd + strlen(cmd), " -t raw -r %d -b %d %s -c %d - %s",
			ot->smp_freq, ot->bit_len,
			ot->sign ? "-s" : "-u",
			ot->ch_num, fn);
		if((ot->fp = popen(cmd, "w")) == NULL) ERR("popen");
	}
	ot->amp = ot->bit_len == 8 ? 127 : 32767;
	ot->base = ot->sign ? 0 : ot->amp + 1;
	ot->iv_min = ot->base - (ot->amp + 1);
	ot->iv_max = ot->base + ot->amp;
}

void
out_do(struct out_rec *ot, double v)
{
	int iv;

	iv = ot->base + (int)(v *ot->amp);
	if(iv > ot->iv_max) iv = ot->iv_max;
	if(iv < ot->iv_min) iv = ot->iv_min;
	switch(ot->bit_len){
	case 8:
		fputc(iv, ot->fp);
		break;
	case 16:
		fputc(iv & 0xff, ot->fp);
		fputc((iv >> 8) & 0xff, ot->fp);
		break;
	}
}

#define MIDI_CH_N	16
int ch_vol[ MIDI_CH_N ];
int ch_pan[ MIDI_CH_N ];

void
data_out(struct out_rec *ot, double evt_sec)
{
	double v, sec, freq, dsec;
	double vl, vr, pan;
	double release;
	int i;

	release = 0.3;
	while((sec = (double)ot->smp_cnt / ot->smp_freq) < evt_sec){
		vl = vr = 0;
		for(i=0; i<NOTE_BUF_N; i++){
			if(note_buf_is_free(i)) continue;
			freq = note_to_freq(note_buf[i].note);
			note_buf[i].cycle += freq * (sec - note_buf[i].sec);
			// サイクルの増分 = 音の周波数 × 音の経過時間
			// として最後に出力したサイクルを更新
			
			note_buf[i].sec = sec;
			// 最後の出力時刻を更新
			
			v = sin(2 * M_PI * note_buf[i].cycle);
			// SIN波形の値 = SIN( 2π × サイクル )
			// として計算
			
			v *= note_buf[i].velo / 127.0;
			v *= ch_vol[ note_buf[i].ch ] / (double)((1<<14)-1);
			if(note_buf[i].onoff == 0){
				dsec = sec - note_buf[i].off_sec;
				v *= 1 - dsec / release;
				if(dsec >= release) note_buf_free(i);
			}
			if(ot->ch_num == 1){
				vl += v;
			}else{
				pan = ch_pan[ note_buf[i].ch ] / (double)(1<<14);
				vl += (1 - pan) * v;
				vr += pan * v;
			}
		}
		out_do(ot, vl / 16);
		if(ot->ch_num > 1) out_do(ot, vr / 16);
		ot->smp_cnt++;
	}
}

void
note_onoff(int onoff, double evt_sec, int ch, int note, int velo)
{
	int i;

	if(ch == 9) return;

	if(onoff){
		if((i = note_buf_search(-1, -1, -1)) < 0){
			MSG("note_buf full");
			return;
		}
		note_buf[i].note = note;
		note_buf[i].ch = ch;
		note_buf[i].onoff = 1;
		note_buf[i].on_sec = evt_sec;
		note_buf[i].velo = velo;
		note_buf[i].cycle = 0;
		note_buf[i].sec = evt_sec;
		// 最後に出力したサイクルと時刻を初期化
		
	}else{
		if((i = note_buf_search(ch, note, 1)) < 0) return;
		note_buf[i].onoff = 0;
		note_buf[i].off_sec = evt_sec;
	}
}

int
main(int ac, char **av)
{
	int div4, delta_sum;
	int i, n, v, hi, low, note, velo;
	int ch, type;
	double sec;
	struct out_rec otr;
	int tempo, tempo_delta_sum;
	double tempo_sec;

	out_init(&otr, ac, av);
	note_buf_init();
	for(i=0; i<MIDI_CH_N; i++){
		ch_vol[i] = 0;
		ch_pan[i] = 1<<(14-1);
	}
	tempo = 500000;
	tempo_delta_sum = 0;
	tempo_sec = 0;

	div4 = header();

	if(!rd_str_chk(4, "MTrk")) ERR("track id");
	v = rd_int(4); /* skip */

	hi = low = 0;
	delta_sum = 0;
	while((v = rd_delta()) != EOF){
		delta_sum += v;
		sec = tempo_sec + (double)(delta_sum - tempo_delta_sum) / div4 * tempo * 0.000001;
		
		if((v = rd()) & 0x80){
			hi = (v >> 4) & 0xf;
			low  = v & 0xf;
		}else bk(v);

		data_out(&otr, sec);

		ch = low;
		switch(hi){
		case 8:
		case 9:
			note = rd();
			velo = rd();
			note_onoff(hi == 9, sec, ch, note, velo);
			break;
		case 0xb: /* control change */
			type = rd();
			v = rd();
			switch(type){
			case 7: /* channel volume msb */
				ch_vol[ch] &= ~(127<<7);
				ch_vol[ch] |= v<<7;
				break;
			case 39: /* channel volume lsb */
				ch_vol[ch] &= ~127;
				ch_vol[ch] |= v;
				break;
			case 10: /* pan msb */
				ch_pan[ch] &= ~(127<<7);
				ch_pan[ch] |= v<<7;
				break;
			case 42: /* pan lsb */
				ch_pan[ch] &= ~127;
				ch_pan[ch] |= v;
				break;
			}
			break;
		case 0xa:
		case 0xe:
			rd();
			rd();
			break;
		case 0xc:		
		case 0xd:
			rd();
			break;
		case 0xf:
			type = rd();
			switch(low){
			case 0:
				while(rd() != 0xf7);
				break;
			case 1:
			case 3:
				rd();
				break;
			case 2:
				rd();
				rd();
				break;
			case 0xf: /* meta */
				n = rd();
				switch(type){
				case 0x51: /* set tempo */
					v = rd_int(n);
					tempo = v;
					tempo_delta_sum = delta_sum;
					tempo_sec = sec;
					break;
				default:
					for(i=0; i<n; i++) rd();
					break;
				}
				break;
			default:
				break;
			}
			break;
		}
	}
	if(otr.fp != stdout) pclose(otr.fp);
	return 0;
}

/* EOF */


prog5.c 解説

prog4.c からの変更箇所のみ

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <math.h>

#define MSG(s) fprintf(stderr, "%s() %s L%d : %s\n", __func__, __FILE__, __LINE__, s)
#define ERR(s) do{ fprintf(stderr, "ERR "); MSG(s); exit(1); }while(0)

int bk_buf = -1;

int
rd(void)
{
	int v;

	if((v = bk_buf) < 0) return getchar();
	bk_buf = -1;
	return v;
}

void
bk(int v)
{
	if(bk_buf >= 0) ERR("give up");
	bk_buf = v;
}

void
rd_str(int n, char *s)
{
	int i;

	for(i=0; i<n; i++) s[i] = rd();
	s[i] = '\0';
}

int
rd_str_chk(int n, char *s)
{
	char buf[256];

	rd_str(n, buf);
	return strcmp(buf, s) == 0;
}

int
rd_int(int n) /* big endian */
{
	int i, v;

	v = 0;
	for(i=0; i<n; i++) v = (v << 8) | rd();
	return v;
}

int
rd_delta(void)
{
	int v, c;

	v = 0;
	do{
		if((c = rd()) == EOF) return EOF;
		v = (v << 7) | (c & 0x7f);
	}while(c & 0x80);
	return v;
}


#define NOTE_BUF_N	256

struct note_rec{
	int ch;
	int note;
	int onoff;
	double on_sec;
	double off_sec;
	int velo;
	double cycle, sec;
} note_buf[NOTE_BUF_N];

int
note_buf_is_free(int i)
{
	return note_buf[i].ch < 0;
}

void
note_buf_free(int i)
{
	note_buf[i].ch = -1;
}

void
note_buf_init(void)
{
	int i;

	for(i=0; i<NOTE_BUF_N; i++) note_buf_free(i);
}

int
note_buf_search(int ch, int note, int onoff)
{
	int i;

	for(i=0; i<NOTE_BUF_N; i++) {
		if( (ch < 0 && note_buf[i].ch < 0) ||
		    (note_buf[i].ch == ch &&
		     note_buf[i].note == note &&
		     note_buf[i].onoff == onoff) ) return i;
	}
	return -1;
}

int
header(void)
{
	int v;

	if(!rd_str_chk(4, "MThd")) ERR("header id");
	if(rd_int(4) != 6) ERR("header size");
	if(rd_int(2) != 0) ERR("header format type");
	if(rd_int(2) != 1) ERR("header track num");
	if((v = rd_int(2)) & 0x8000) ERR("header division");
	return v; /* div4 */
}

double
note_to_freq(int note)
{
	return 440 * pow(2, (note - 69) / 12.0);
}

int
opt_idx(char *key, int ac, char **av)
{
	int i;

	for(i=1; i<ac; i++) if(strcmp(av[i], key) == 0) return i;
	return -1;
}

char *
opt_str(char *key, int ac, char **av, char *def)
{
	int i;

	i = opt_idx(key, ac, av);
	if(i < 0 || i+1 >= ac) return def;
	return av[i+1];
}

int
opt_int(char *key, int ac, char **av, int def)
{
	char *s;

	if((s = opt_str(key, ac, av, NULL)) == NULL) return def;
	return strtol(s, NULL, 0);
}

struct out_rec{
	int smp_freq, smp_cnt;
	int bit_len;
	int sign;
	int ch_num;
	FILE *fp;

	int base;
	int amp;
	int iv_min;
	int iv_max;
};

void
out_init(struct out_rec *ot, int ac, char **av)
{
	char cmd[1024], *fn;

	ot->smp_freq = opt_int("-r", ac, av, 8000);
	ot->smp_cnt = 0;
	ot->bit_len = opt_int("-b", ac, av, 8);
	if(ot->bit_len != 8 && ot->bit_len != 16) ERR("bit_len");
	ot->sign = (opt_idx("-s", ac, av) >= 0);
	ot->ch_num = opt_int("-c", ac, av, 1);

	ot->fp = stdout;
	cmd[0] = '\0';
	fn = "";
	if(opt_idx("-play", ac, av) >= 0){
		strcat(cmd, "play");
	}else if(opt_idx("-sox", ac, av) >= 0){
		strcat(cmd, "sox");
		fn = opt_str("-sox", ac, av, "-d");
	}
	if(cmd[0]){
		sprintf(cmd + strlen(cmd), " -t raw -r %d -b %d %s -c %d - %s",
			ot->smp_freq, ot->bit_len,
			ot->sign ? "-s" : "-u",
			ot->ch_num, fn);
		if((ot->fp = popen(cmd, "w")) == NULL) ERR("popen");
	}
	ot->amp = ot->bit_len == 8 ? 127 : 32767;
	ot->base = ot->sign ? 0 : ot->amp + 1;
	ot->iv_min = ot->base - (ot->amp + 1);
	ot->iv_max = ot->base + ot->amp;
}

void
out_do(struct out_rec *ot, double v)
{
	int iv;

	iv = ot->base + (int)(v *ot->amp);
	if(iv > ot->iv_max) iv = ot->iv_max;
	if(iv < ot->iv_min) iv = ot->iv_min;
	switch(ot->bit_len){
	case 8:
		fputc(iv, ot->fp);
		break;
	case 16:
		fputc(iv & 0xff, ot->fp);
		fputc((iv >> 8) & 0xff, ot->fp);
		break;
	}
}

#define MIDI_CH_N	16
int ch_vol[ MIDI_CH_N ];
int ch_pan[ MIDI_CH_N ];

void
data_out(struct out_rec *ot, double evt_sec)
{
	double v, sec, freq, dsec;
	double vl, vr, pan;
	double release;
	int i;

	release = 0.3;
	while((sec = (double)ot->smp_cnt / ot->smp_freq) < evt_sec){
		vl = vr = 0;
		for(i=0; i<NOTE_BUF_N; i++){
			if(note_buf_is_free(i)) continue;
			freq = note_to_freq(note_buf[i].note);
			dsec = sec - note_buf[i].on_sec;
			if(dsec > 0.3) freq *= pow(2, sin(2 * M_PI * 6 * dsec) / (12 * 4) );
			note_buf[i].cycle += freq * (sec - note_buf[i].sec);
			note_buf[i].sec = sec;
			v = sin(2 * M_PI * note_buf[i].cycle);
			v *= note_buf[i].velo / 127.0;
			v *= ch_vol[ note_buf[i].ch ] / (double)((1<<14)-1);
			if(note_buf[i].onoff == 0){
				dsec = sec - note_buf[i].off_sec;
				v *= 1 - dsec / release;
				if(dsec >= release) note_buf_free(i);
			}
			if(ot->ch_num == 1){
				vl += v;
			}else{
				pan = ch_pan[ note_buf[i].ch ] / (double)(1<<14);
				vl += (1 - pan) * v;
				vr += pan * v;
			}
		}
		out_do(ot, vl / 16);
		if(ot->ch_num > 1) out_do(ot, vr / 16);
		ot->smp_cnt++;
	}
}

void
note_onoff(int onoff, double evt_sec, int ch, int note, int velo)
{
	int i;

	if(ch == 9) return;

	if(onoff){
		if((i = note_buf_search(-1, -1, -1)) < 0){
			MSG("note_buf full");
			return;
		}
		note_buf[i].note = note;
		note_buf[i].ch = ch;
		note_buf[i].onoff = 1;
		note_buf[i].on_sec = evt_sec;
		note_buf[i].velo = velo;
		note_buf[i].cycle = 0;
		note_buf[i].sec = evt_sec;
	}else{
		if((i = note_buf_search(ch, note, 1)) < 0) return;
		note_buf[i].onoff = 0;
		note_buf[i].off_sec = evt_sec;
	}
}

int
main(int ac, char **av)
{
	int div4, delta_sum;
	int i, n, v, hi, low, note, velo;
	int ch, type;
	double sec;
	struct out_rec otr;
	int tempo, tempo_delta_sum;
	double tempo_sec;

	out_init(&otr, ac, av);
	note_buf_init();
	for(i=0; i<MIDI_CH_N; i++){
		ch_vol[i] = 0;
		ch_pan[i] = 1<<(14-1);
	}
	tempo = 500000;
	tempo_delta_sum = 0;
	tempo_sec = 0;

	div4 = header();

	if(!rd_str_chk(4, "MTrk")) ERR("track id");
	v = rd_int(4); /* skip */

	hi = low = 0;
	delta_sum = 0;
	while((v = rd_delta()) != EOF){
		delta_sum += v;
		sec = tempo_sec + (double)(delta_sum - tempo_delta_sum) / div4 * tempo * 0.000001;
		
		if((v = rd()) & 0x80){
			hi = (v >> 4) & 0xf;
			low  = v & 0xf;
		}else bk(v);

		data_out(&otr, sec);

		ch = low;
		switch(hi){
		case 8:
		case 9:
			note = rd();
			velo = rd();
			note_onoff(hi == 9, sec, ch, note, velo);
			break;
		case 0xb: /* control change */
			type = rd();
			v = rd();
			switch(type){
			case 7: /* channel volume msb */
				ch_vol[ch] &= ~(127<<7);
				ch_vol[ch] |= v<<7;
				break;
			case 39: /* channel volume lsb */
				ch_vol[ch] &= ~127;
				ch_vol[ch] |= v;
				break;
			case 10: /* pan msb */
				ch_pan[ch] &= ~(127<<7);
				ch_pan[ch] |= v<<7;
				break;
			case 42: /* pan lsb */
				ch_pan[ch] &= ~127;
				ch_pan[ch] |= v;
				break;
			}
			break;
		case 0xa:
		case 0xe:
			rd();
			rd();
			break;
		case 0xc:		
		case 0xd:
			rd();
			break;
		case 0xf:
			type = rd();
			switch(low){
			case 0:
				while(rd() != 0xf7);
				break;
			case 1:
			case 3:
				rd();
				break;
			case 2:
				rd();
				rd();
				break;
			case 0xf: /* meta */
				n = rd();
				switch(type){
				case 0x51: /* set tempo */
					v = rd_int(n);
					tempo = v;
					tempo_delta_sum = delta_sum;
					tempo_sec = sec;
					break;
				default:
					for(i=0; i<n; i++) rd();
					break;
				}
				break;
			default:
				break;
			}
			break;
		}
	}
	if(otr.fp != stdout) pclose(otr.fp);
	return 0;
}

/* EOF */


#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <math.h>

#define MSG(s) fprintf(stderr, "%s() %s L%d : %s\n", __func__, __FILE__, __LINE__, s)
#define ERR(s) do{ fprintf(stderr, "ERR "); MSG(s); exit(1); }while(0)

int bk_buf = -1;

int
rd(void)
{
	int v;

	if((v = bk_buf) < 0) return getchar();
	bk_buf = -1;
	return v;
}

void
bk(int v)
{
	if(bk_buf >= 0) ERR("give up");
	bk_buf = v;
}

void
rd_str(int n, char *s)
{
	int i;

	for(i=0; i<n; i++) s[i] = rd();
	s[i] = '\0';
}

int
rd_str_chk(int n, char *s)
{
	char buf[256];

	rd_str(n, buf);
	return strcmp(buf, s) == 0;
}

int
rd_int(int n) /* big endian */
{
	int i, v;

	v = 0;
	for(i=0; i<n; i++) v = (v << 8) | rd();
	return v;
}

int
rd_delta(void)
{
	int v, c;

	v = 0;
	do{
		if((c = rd()) == EOF) return EOF;
		v = (v << 7) | (c & 0x7f);
	}while(c & 0x80);
	return v;
}


#define NOTE_BUF_N	256

struct note_rec{
	int ch;
	int note;
	int onoff;
	double on_sec;
	double off_sec;
	int velo;
	double cycle, sec;
} note_buf[NOTE_BUF_N];

int
note_buf_is_free(int i)
{
	return note_buf[i].ch < 0;
}

void
note_buf_free(int i)
{
	note_buf[i].ch = -1;
}

void
note_buf_init(void)
{
	int i;

	for(i=0; i<NOTE_BUF_N; i++) note_buf_free(i);
}

int
note_buf_search(int ch, int note, int onoff)
{
	int i;

	for(i=0; i<NOTE_BUF_N; i++) {
		if( (ch < 0 && note_buf[i].ch < 0) ||
		    (note_buf[i].ch == ch &&
		     note_buf[i].note == note &&
		     note_buf[i].onoff == onoff) ) return i;
	}
	return -1;
}

int
header(void)
{
	int v;

	if(!rd_str_chk(4, "MThd")) ERR("header id");
	if(rd_int(4) != 6) ERR("header size");
	if(rd_int(2) != 0) ERR("header format type");
	if(rd_int(2) != 1) ERR("header track num");
	if((v = rd_int(2)) & 0x8000) ERR("header division");
	return v; /* div4 */
}

double
note_to_freq(int note)
{
	return 440 * pow(2, (note - 69) / 12.0);
}

int
opt_idx(char *key, int ac, char **av)
{
	int i;

	for(i=1; i<ac; i++) if(strcmp(av[i], key) == 0) return i;
	return -1;
}

char *
opt_str(char *key, int ac, char **av, char *def)
{
	int i;

	i = opt_idx(key, ac, av);
	if(i < 0 || i+1 >= ac) return def;
	return av[i+1];
}

int
opt_int(char *key, int ac, char **av, int def)
{
	char *s;

	if((s = opt_str(key, ac, av, NULL)) == NULL) return def;
	return strtol(s, NULL, 0);
}

struct out_rec{
	int smp_freq, smp_cnt;
	int bit_len;
	int sign;
	int ch_num;
	FILE *fp;

	int base;
	int amp;
	int iv_min;
	int iv_max;
};

void
out_init(struct out_rec *ot, int ac, char **av)
{
	char cmd[1024], *fn;

	ot->smp_freq = opt_int("-r", ac, av, 8000);
	ot->smp_cnt = 0;
	ot->bit_len = opt_int("-b", ac, av, 8);
	if(ot->bit_len != 8 && ot->bit_len != 16) ERR("bit_len");
	ot->sign = (opt_idx("-s", ac, av) >= 0);
	ot->ch_num = opt_int("-c", ac, av, 1);

	ot->fp = stdout;
	cmd[0] = '\0';
	fn = "";
	if(opt_idx("-play", ac, av) >= 0){
		strcat(cmd, "play");
	}else if(opt_idx("-sox", ac, av) >= 0){
		strcat(cmd, "sox");
		fn = opt_str("-sox", ac, av, "-d");
	}
	if(cmd[0]){
		sprintf(cmd + strlen(cmd), " -t raw -r %d -b %d %s -c %d - %s",
			ot->smp_freq, ot->bit_len,
			ot->sign ? "-s" : "-u",
			ot->ch_num, fn);
		if((ot->fp = popen(cmd, "w")) == NULL) ERR("popen");
	}
	ot->amp = ot->bit_len == 8 ? 127 : 32767;
	ot->base = ot->sign ? 0 : ot->amp + 1;
	ot->iv_min = ot->base - (ot->amp + 1);
	ot->iv_max = ot->base + ot->amp;
}

void
out_do(struct out_rec *ot, double v)
{
	int iv;

	iv = ot->base + (int)(v *ot->amp);
	if(iv > ot->iv_max) iv = ot->iv_max;
	if(iv < ot->iv_min) iv = ot->iv_min;
	switch(ot->bit_len){
	case 8:
		fputc(iv, ot->fp);
		break;
	case 16:
		fputc(iv & 0xff, ot->fp);
		fputc((iv >> 8) & 0xff, ot->fp);
		break;
	}
}

#define MIDI_CH_N	16
int ch_vol[ MIDI_CH_N ];
int ch_pan[ MIDI_CH_N ];

void
data_out(struct out_rec *ot, double evt_sec)
{
	double v, sec, freq, dsec;
	double vl, vr, pan;
	double release;
	int i;

	release = 0.3;
	while((sec = (double)ot->smp_cnt / ot->smp_freq) < evt_sec){
		vl = vr = 0;
		for(i=0; i<NOTE_BUF_N; i++){
			if(note_buf_is_free(i)) continue;
			freq = note_to_freq(note_buf[i].note);
			dsec = sec - note_buf[i].on_sec;
			if(dsec > 0.3) freq *= pow(2, sin(2 * M_PI * 6 * dsec) / (12 * 4) );
			// 鍵盤オンから0.3秒経過してたらビブラートをかける
			// 揺さぶる周波数は 6 Hz
			// 揺さぶる幅は、上下それぞれ鍵盤の半音の1/4の幅で
			
			note_buf[i].cycle += freq * (sec - note_buf[i].sec);
			note_buf[i].sec = sec;
			v = sin(2 * M_PI * note_buf[i].cycle);
			v *= note_buf[i].velo / 127.0;
			v *= ch_vol[ note_buf[i].ch ] / (double)((1<<14)-1);
			if(note_buf[i].onoff == 0){
				dsec = sec - note_buf[i].off_sec;
				v *= 1 - dsec / release;
				if(dsec >= release) note_buf_free(i);
			}
			if(ot->ch_num == 1){
				vl += v;
			}else{
				pan = ch_pan[ note_buf[i].ch ] / (double)(1<<14);
				vl += (1 - pan) * v;
				vr += pan * v;
			}
		}
		out_do(ot, vl / 16);
		if(ot->ch_num > 1) out_do(ot, vr / 16);
		ot->smp_cnt++;
	}
}

void
note_onoff(int onoff, double evt_sec, int ch, int note, int velo)
{
	int i;

	if(ch == 9) return;

	if(onoff){
		if((i = note_buf_search(-1, -1, -1)) < 0){
			MSG("note_buf full");
			return;
		}
		note_buf[i].note = note;
		note_buf[i].ch = ch;
		note_buf[i].onoff = 1;
		note_buf[i].on_sec = evt_sec;
		note_buf[i].velo = velo;
		note_buf[i].cycle = 0;
		note_buf[i].sec = evt_sec;
	}else{
		if((i = note_buf_search(ch, note, 1)) < 0) return;
		note_buf[i].onoff = 0;
		note_buf[i].off_sec = evt_sec;
	}
}

int
main(int ac, char **av)
{
	int div4, delta_sum;
	int i, n, v, hi, low, note, velo;
	int ch, type;
	double sec;
	struct out_rec otr;
	int tempo, tempo_delta_sum;
	double tempo_sec;

	out_init(&otr, ac, av);
	note_buf_init();
	for(i=0; i<MIDI_CH_N; i++){
		ch_vol[i] = 0;
		ch_pan[i] = 1<<(14-1);
	}
	tempo = 500000;
	tempo_delta_sum = 0;
	tempo_sec = 0;

	div4 = header();

	if(!rd_str_chk(4, "MTrk")) ERR("track id");
	v = rd_int(4); /* skip */

	hi = low = 0;
	delta_sum = 0;
	while((v = rd_delta()) != EOF){
		delta_sum += v;
		sec = tempo_sec + (double)(delta_sum - tempo_delta_sum) / div4 * tempo * 0.000001;
		
		if((v = rd()) & 0x80){
			hi = (v >> 4) & 0xf;
			low  = v & 0xf;
		}else bk(v);

		data_out(&otr, sec);

		ch = low;
		switch(hi){
		case 8:
		case 9:
			note = rd();
			velo = rd();
			note_onoff(hi == 9, sec, ch, note, velo);
			break;
		case 0xb: /* control change */
			type = rd();
			v = rd();
			switch(type){
			case 7: /* channel volume msb */
				ch_vol[ch] &= ~(127<<7);
				ch_vol[ch] |= v<<7;
				break;
			case 39: /* channel volume lsb */
				ch_vol[ch] &= ~127;
				ch_vol[ch] |= v;
				break;
			case 10: /* pan msb */
				ch_pan[ch] &= ~(127<<7);
				ch_pan[ch] |= v<<7;
				break;
			case 42: /* pan lsb */
				ch_pan[ch] &= ~127;
				ch_pan[ch] |= v;
				break;
			}
			break;
		case 0xa:
		case 0xe:
			rd();
			rd();
			break;
		case 0xc:		
		case 0xd:
			rd();
			break;
		case 0xf:
			type = rd();
			switch(low){
			case 0:
				while(rd() != 0xf7);
				break;
			case 1:
			case 3:
				rd();
				break;
			case 2:
				rd();
				rd();
				break;
			case 0xf: /* meta */
				n = rd();
				switch(type){
				case 0x51: /* set tempo */
					v = rd_int(n);
					tempo = v;
					tempo_delta_sum = delta_sum;
					tempo_sec = sec;
					break;
				default:
					for(i=0; i<n; i++) rd();
					break;
				}
				break;
			default:
				break;
			}
			break;
		}
	}
	if(otr.fp != stdout) pclose(otr.fp);
	return 0;
}

/* EOF */


prog6.c 解説

prog5.c からの変更箇所のみ

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <math.h>

#define MSG(s) fprintf(stderr, "%s() %s L%d : %s\n", __func__, __FILE__, __LINE__, s)
#define ERR(s) do{ fprintf(stderr, "ERR "); MSG(s); exit(1); }while(0)

int bk_buf = -1;

int
rd(void)
{
	int v;

	if((v = bk_buf) < 0) return getchar();
	bk_buf = -1;
	return v;
}

void
bk(int v)
{
	if(bk_buf >= 0) ERR("give up");
	bk_buf = v;
}

void
rd_str(int n, char *s)
{
	int i;

	for(i=0; i<n; i++) s[i] = rd();
	s[i] = '\0';
}

int
rd_str_chk(int n, char *s)
{
	char buf[256];

	rd_str(n, buf);
	return strcmp(buf, s) == 0;
}

int
rd_int(int n) /* big endian */
{
	int i, v;

	v = 0;
	for(i=0; i<n; i++) v = (v << 8) | rd();
	return v;
}

int
rd_delta(void)
{
	int v, c;

	v = 0;
	do{
		if((c = rd()) == EOF) return EOF;
		v = (v << 7) | (c & 0x7f);
	}while(c & 0x80);
	return v;
}


#define NOTE_BUF_N	256

struct note_rec{
	int ch;
	int note;
	int onoff;
	double on_sec;
	double off_sec;
	int velo;
	double cycle, sec, freq;
} note_buf[NOTE_BUF_N];

int
note_buf_is_free(int i)
{
	return note_buf[i].ch < 0;
}

void
note_buf_free(int i)
{
	note_buf[i].ch = -1;
}

void
note_buf_init(void)
{
	int i;

	for(i=0; i<NOTE_BUF_N; i++) note_buf_free(i);
}

int
note_buf_search(int ch, int note, int onoff)
{
	int i;

	for(i=0; i<NOTE_BUF_N; i++) {
		if( (ch < 0 && note_buf[i].ch < 0) ||
		    (note_buf[i].ch == ch &&
		     note_buf[i].note == note &&
		     note_buf[i].onoff == onoff) ) return i;
	}
	return -1;
}

int
header(void)
{
	int v;

	if(!rd_str_chk(4, "MThd")) ERR("header id");
	if(rd_int(4) != 6) ERR("header size");
	if(rd_int(2) != 0) ERR("header format type");
	if(rd_int(2) != 1) ERR("header track num");
	if((v = rd_int(2)) & 0x8000) ERR("header division");
	return v; /* div4 */
}

double
note_to_freq(int note)
{
	return 440 * pow(2, (note - 69) / 12.0);
}

int
opt_idx(char *key, int ac, char **av)
{
	int i;

	for(i=1; i<ac; i++) if(strcmp(av[i], key) == 0) return i;
	return -1;
}

char *
opt_str(char *key, int ac, char **av, char *def)
{
	int i;

	i = opt_idx(key, ac, av);
	if(i < 0 || i+1 >= ac) return def;
	return av[i+1];
}

int
opt_int(char *key, int ac, char **av, int def)
{
	char *s;

	if((s = opt_str(key, ac, av, NULL)) == NULL) return def;
	return strtol(s, NULL, 0);
}

struct out_rec{
	int smp_freq, smp_cnt;
	int bit_len;
	int sign;
	int ch_num;
	FILE *fp;

	int base;
	int amp;
	int iv_min;
	int iv_max;
};

void
out_init(struct out_rec *ot, int ac, char **av)
{
	char cmd[1024], *fn;

	ot->smp_freq = opt_int("-r", ac, av, 8000);
	ot->smp_cnt = 0;
	ot->bit_len = opt_int("-b", ac, av, 8);
	if(ot->bit_len != 8 && ot->bit_len != 16) ERR("bit_len");
	ot->sign = (opt_idx("-s", ac, av) >= 0);
	ot->ch_num = opt_int("-c", ac, av, 1);

	ot->fp = stdout;
	cmd[0] = '\0';
	fn = "";
	if(opt_idx("-play", ac, av) >= 0){
		strcat(cmd, "play");
	}else if(opt_idx("-sox", ac, av) >= 0){
		strcat(cmd, "sox");
		fn = opt_str("-sox", ac, av, "-d");
	}
	if(cmd[0]){
		sprintf(cmd + strlen(cmd), " -t raw -r %d -b %d %s -c %d - %s",
			ot->smp_freq, ot->bit_len,
			ot->sign ? "-s" : "-u",
			ot->ch_num, fn);
		if((ot->fp = popen(cmd, "w")) == NULL) ERR("popen");
	}
	ot->amp = ot->bit_len == 8 ? 127 : 32767;
	ot->base = ot->sign ? 0 : ot->amp + 1;
	ot->iv_min = ot->base - (ot->amp + 1);
	ot->iv_max = ot->base + ot->amp;
}

void
out_do(struct out_rec *ot, double v)
{
	int iv;

	iv = ot->base + (int)(v *ot->amp);
	if(iv > ot->iv_max) iv = ot->iv_max;
	if(iv < ot->iv_min) iv = ot->iv_min;
	switch(ot->bit_len){
	case 8:
		fputc(iv, ot->fp);
		break;
	case 16:
		fputc(iv & 0xff, ot->fp);
		fputc((iv >> 8) & 0xff, ot->fp);
		break;
	}
}

#define MIDI_CH_N	16
int ch_vol[ MIDI_CH_N ];
int ch_pan[ MIDI_CH_N ];
int ch_bend[ MIDI_CH_N ];
int ch_rpn[ MIDI_CH_N ];
int ch_bend_range[ MIDI_CH_N ];

void
data_out(struct out_rec *ot, double evt_sec)
{
	double v, sec, freq, dsec;
	double vl, vr, pan;
	double release;
	int i, nch;

	release = 0.3;
	while((sec = (double)ot->smp_cnt / ot->smp_freq) < evt_sec){
		vl = vr = 0;
		for(i=0; i<NOTE_BUF_N; i++){
			if(note_buf_is_free(i)) continue;
			nch = note_buf[i].ch;
			freq = note_to_freq(note_buf[i].note);
			if(ch_bend[nch] != 0) freq *= pow(2, ch_bend[nch] / 8192.0 * ch_bend_range[nch] / 12);
			dsec = sec - note_buf[i].on_sec;
			if(dsec > 0.3) freq *= pow(2, sin(2 * M_PI * 6 * dsec) / (12 * 4) );
			note_buf[i].cycle += freq * (sec - note_buf[i].sec);
			note_buf[i].sec = sec;
			note_buf[i].freq = freq;
			v = sin(2 * M_PI * note_buf[i].cycle);
			v *= note_buf[i].velo / 127.0;
			v *= ch_vol[nch] / (double)((1<<14)-1);
			if(note_buf[i].onoff == 0){
				dsec = sec - note_buf[i].off_sec;
				v *= 1 - dsec / release;
				if(dsec >= release) note_buf_free(i);
			}
			if(ot->ch_num == 1){
				vl += v;
			}else{
				pan = ch_pan[nch] / (double)(1<<14);
				vl += (1 - pan) * v;
				vr += pan * v;
			}
		}
		out_do(ot, vl / 16);
		if(ot->ch_num > 1) out_do(ot, vr / 16);
		ot->smp_cnt++;
	}
}

void
note_onoff(int onoff, double evt_sec, int ch, int note, int velo)
{
	int i;

	if(ch == 9) return;

	if(onoff){
		if((i = note_buf_search(-1, -1, -1)) < 0){
			MSG("note_buf full");
			return;
		}
		note_buf[i].note = note;
		note_buf[i].ch = ch;
		note_buf[i].onoff = 1;
		note_buf[i].on_sec = evt_sec;
		note_buf[i].velo = velo;
		note_buf[i].cycle = 0;
		note_buf[i].sec = evt_sec;
	}else{
		if((i = note_buf_search(ch, note, 1)) < 0) return;
		note_buf[i].onoff = 0;
		note_buf[i].off_sec = evt_sec;
	}
}

void
bend_note_update(int ch, double sec)
{
	int i;

	for(i=0; i<NOTE_BUF_N; i++){
		if(note_buf_is_free(i)) continue;
		if(note_buf[i].ch != ch) continue;
		note_buf[i].cycle += note_buf[i].freq * (sec - note_buf[i].sec);
		note_buf[i].sec = sec;
	}
}

int
main(int ac, char **av)
{
	int div4, delta_sum;
	int i, n, v, hi, low, note, velo;
	int ch, type;
	double sec;
	struct out_rec otr;
	int tempo, tempo_delta_sum;
	double tempo_sec;

	out_init(&otr, ac, av);
	note_buf_init();
	for(i=0; i<MIDI_CH_N; i++){
		ch_vol[i] = 0;
		ch_pan[i] = 1<<(14-1);
		ch_bend[i] = 0;
		ch_rpn[i] = 0;
		ch_bend_range[i] = 2;
	}
	tempo = 500000;
	tempo_delta_sum = 0;
	tempo_sec = 0;

	div4 = header();

	if(!rd_str_chk(4, "MTrk")) ERR("track id");
	v = rd_int(4); /* skip */

	hi = low = 0;
	delta_sum = 0;
	while((v = rd_delta()) != EOF){
		delta_sum += v;
		sec = tempo_sec + (double)(delta_sum - tempo_delta_sum) / div4 * tempo * 0.000001;
		
		if((v = rd()) & 0x80){
			hi = (v >> 4) & 0xf;
			low  = v & 0xf;
		}else bk(v);

		data_out(&otr, sec);

		ch = low;
		switch(hi){
		case 8:
		case 9:
			note = rd();
			velo = rd();
			note_onoff(hi == 9, sec, ch, note, velo);
			break;
		case 0xb: /* control change */
			type = rd();
			v = rd();
			switch(type){
			case 7: /* channel volume msb */
				ch_vol[ch] &= ~(127<<7);
				ch_vol[ch] |= v<<7;
				break;
			case 39: /* channel volume lsb */
				ch_vol[ch] &= ~127;
				ch_vol[ch] |= v;
				break;
			case 10: /* pan msb */
				ch_pan[ch] &= ~(127<<7);
				ch_pan[ch] |= v<<7;
				break;
			case 42: /* pan lsb */
				ch_pan[ch] &= ~127;
				ch_pan[ch] |= v;
				break;
			case 100: /* rpn lsb */
				ch_rpn[ch] &= ~127;
				ch_rpn[ch] |= v;
				break;
			case 101: /* rpn msb */
				ch_rpn[ch] &= ~(127<<7);
				ch_rpn[ch] |= v<<7;
				break;
			case 6: /* data entry msb */
				switch(ch_rpn[ch]){
				case 0: /* pitch bend range */
					ch_bend_range[ch] = v;
					break;
				}
				break;
			}
			break;
		case 0xa:
			rd();
			rd();
			break;
		case 0xe: /* pitch wheel change */
			bend_note_update(ch, sec);
			v = rd();
			v |= rd() << 7;
			ch_bend[ch] = v - 8192;
			break;
		case 0xc:		
		case 0xd:
			rd();
			break;
		case 0xf:
			type = rd();
			switch(low){
			case 0:
				while(rd() != 0xf7);
				break;
			case 1:
			case 3:
				rd();
				break;
			case 2:
				rd();
				rd();
				break;
			case 0xf: /* meta */
				n = rd();
				switch(type){
				case 0x51: /* set tempo */
					v = rd_int(n);
					tempo = v;
					tempo_delta_sum = delta_sum;
					tempo_sec = sec;
					break;
				default:
					for(i=0; i<n; i++) rd();
					break;
				}
				break;
			default:
				break;
			}
			break;
		}
	}
	if(otr.fp != stdout) pclose(otr.fp);
	return 0;
}

/* EOF */


#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <math.h>

#define MSG(s) fprintf(stderr, "%s() %s L%d : %s\n", __func__, __FILE__, __LINE__, s)
#define ERR(s) do{ fprintf(stderr, "ERR "); MSG(s); exit(1); }while(0)

int bk_buf = -1;

int
rd(void)
{
	int v;

	if((v = bk_buf) < 0) return getchar();
	bk_buf = -1;
	return v;
}

void
bk(int v)
{
	if(bk_buf >= 0) ERR("give up");
	bk_buf = v;
}

void
rd_str(int n, char *s)
{
	int i;

	for(i=0; i<n; i++) s[i] = rd();
	s[i] = '\0';
}

int
rd_str_chk(int n, char *s)
{
	char buf[256];

	rd_str(n, buf);
	return strcmp(buf, s) == 0;
}

int
rd_int(int n) /* big endian */
{
	int i, v;

	v = 0;
	for(i=0; i<n; i++) v = (v << 8) | rd();
	return v;
}

int
rd_delta(void)
{
	int v, c;

	v = 0;
	do{
		if((c = rd()) == EOF) return EOF;
		v = (v << 7) | (c & 0x7f);
	}while(c & 0x80);
	return v;
}


#define NOTE_BUF_N	256

struct note_rec{
	int ch;
	int note;
	int onoff;
	double on_sec;
	double off_sec;
	int velo;
	double cycle, sec, freq;
	// 急遽 freq 追加 ...
	
} note_buf[NOTE_BUF_N];

int
note_buf_is_free(int i)
{
	return note_buf[i].ch < 0;
}

void
note_buf_free(int i)
{
	note_buf[i].ch = -1;
}

void
note_buf_init(void)
{
	int i;

	for(i=0; i<NOTE_BUF_N; i++) note_buf_free(i);
}

int
note_buf_search(int ch, int note, int onoff)
{
	int i;

	for(i=0; i<NOTE_BUF_N; i++) {
		if( (ch < 0 && note_buf[i].ch < 0) ||
		    (note_buf[i].ch == ch &&
		     note_buf[i].note == note &&
		     note_buf[i].onoff == onoff) ) return i;
	}
	return -1;
}

int
header(void)
{
	int v;

	if(!rd_str_chk(4, "MThd")) ERR("header id");
	if(rd_int(4) != 6) ERR("header size");
	if(rd_int(2) != 0) ERR("header format type");
	if(rd_int(2) != 1) ERR("header track num");
	if((v = rd_int(2)) & 0x8000) ERR("header division");
	return v; /* div4 */
}

double
note_to_freq(int note)
{
	return 440 * pow(2, (note - 69) / 12.0);
}

int
opt_idx(char *key, int ac, char **av)
{
	int i;

	for(i=1; i<ac; i++) if(strcmp(av[i], key) == 0) return i;
	return -1;
}

char *
opt_str(char *key, int ac, char **av, char *def)
{
	int i;

	i = opt_idx(key, ac, av);
	if(i < 0 || i+1 >= ac) return def;
	return av[i+1];
}

int
opt_int(char *key, int ac, char **av, int def)
{
	char *s;

	if((s = opt_str(key, ac, av, NULL)) == NULL) return def;
	return strtol(s, NULL, 0);
}

struct out_rec{
	int smp_freq, smp_cnt;
	int bit_len;
	int sign;
	int ch_num;
	FILE *fp;

	int base;
	int amp;
	int iv_min;
	int iv_max;
};

void
out_init(struct out_rec *ot, int ac, char **av)
{
	char cmd[1024], *fn;

	ot->smp_freq = opt_int("-r", ac, av, 8000);
	ot->smp_cnt = 0;
	ot->bit_len = opt_int("-b", ac, av, 8);
	if(ot->bit_len != 8 && ot->bit_len != 16) ERR("bit_len");
	ot->sign = (opt_idx("-s", ac, av) >= 0);
	ot->ch_num = opt_int("-c", ac, av, 1);

	ot->fp = stdout;
	cmd[0] = '\0';
	fn = "";
	if(opt_idx("-play", ac, av) >= 0){
		strcat(cmd, "play");
	}else if(opt_idx("-sox", ac, av) >= 0){
		strcat(cmd, "sox");
		fn = opt_str("-sox", ac, av, "-d");
	}
	if(cmd[0]){
		sprintf(cmd + strlen(cmd), " -t raw -r %d -b %d %s -c %d - %s",
			ot->smp_freq, ot->bit_len,
			ot->sign ? "-s" : "-u",
			ot->ch_num, fn);
		if((ot->fp = popen(cmd, "w")) == NULL) ERR("popen");
	}
	ot->amp = ot->bit_len == 8 ? 127 : 32767;
	ot->base = ot->sign ? 0 : ot->amp + 1;
	ot->iv_min = ot->base - (ot->amp + 1);
	ot->iv_max = ot->base + ot->amp;
}

void
out_do(struct out_rec *ot, double v)
{
	int iv;

	iv = ot->base + (int)(v *ot->amp);
	if(iv > ot->iv_max) iv = ot->iv_max;
	if(iv < ot->iv_min) iv = ot->iv_min;
	switch(ot->bit_len){
	case 8:
		fputc(iv, ot->fp);
		break;
	case 16:
		fputc(iv & 0xff, ot->fp);
		fputc((iv >> 8) & 0xff, ot->fp);
		break;
	}
}

#define MIDI_CH_N	16
int ch_vol[ MIDI_CH_N ];
int ch_pan[ MIDI_CH_N ];
int ch_bend[ MIDI_CH_N ];
int ch_rpn[ MIDI_CH_N ];
int ch_bend_range[ MIDI_CH_N ];
// ch_bend は、ベンドの値 (-8192〜8191)
// ch_rpn は、RPN の値 ( MSB 7ビット, LSB 7ビット)
// ch_bend_range は、ベンド・レンジ (整数、ベンド値を最高にしたときの半音の数)

void
data_out(struct out_rec *ot, double evt_sec)
{
	double v, sec, freq, dsec;
	double vl, vr, pan;
	double release;
	int i, nch;
	// 変数 nch を追加
	// nch は 鍵盤情報の MIDIチャンネルを保持する
	// (forループ中の note_buf[i].ch)
	
	release = 0.3;
	while((sec = (double)ot->smp_cnt / ot->smp_freq) < evt_sec){
		vl = vr = 0;
		for(i=0; i<NOTE_BUF_N; i++){
			if(note_buf_is_free(i)) continue;
			nch = note_buf[i].ch;
			// 鍵盤情報のMIDIチャンネルを追加した変数 nch へ
			
			freq = note_to_freq(note_buf[i].note);
			if(ch_bend[nch] != 0) freq *= pow(2, ch_bend[nch] / 8192.0 * ch_bend_range[nch] / 12);
			// ピッチ・ベンド処理で、周波数を変更
			//
			// ch_bend[nch] が 0 のときは、何もしない
			// ch_bend[nch], ch_bend_range[nch] を参照し、
			// freq の値に変更をかける
			
			dsec = sec - note_buf[i].on_sec;
			if(dsec > 0.3) freq *= pow(2, sin(2 * M_PI * 6 * dsec) / (12 * 4) );
			note_buf[i].cycle += freq * (sec - note_buf[i].sec);
			note_buf[i].sec = sec;
			note_buf[i].freq = freq;
			// 急遽 freq 追加 ...
			
			v = sin(2 * M_PI * note_buf[i].cycle);
			v *= note_buf[i].velo / 127.0;
			v *= ch_vol[nch] / (double)((1<<14)-1);
			// 変数 nch を追加したので、使用するように修正
			
			if(note_buf[i].onoff == 0){
				dsec = sec - note_buf[i].off_sec;
				v *= 1 - dsec / release;
				if(dsec >= release) note_buf_free(i);
			}
			if(ot->ch_num == 1){
				vl += v;
			}else{
				pan = ch_pan[nch] / (double)(1<<14);
				// 変数 nch を追加したので、使用するように修正
				
				vl += (1 - pan) * v;
				vr += pan * v;
			}
		}
		out_do(ot, vl / 16);
		if(ot->ch_num > 1) out_do(ot, vr / 16);
		ot->smp_cnt++;
	}
}

void
note_onoff(int onoff, double evt_sec, int ch, int note, int velo)
{
	int i;

	if(ch == 9) return;

	if(onoff){
		if((i = note_buf_search(-1, -1, -1)) < 0){
			MSG("note_buf full");
			return;
		}
		note_buf[i].note = note;
		note_buf[i].ch = ch;
		note_buf[i].onoff = 1;
		note_buf[i].on_sec = evt_sec;
		note_buf[i].velo = velo;
		note_buf[i].cycle = 0;
		note_buf[i].sec = evt_sec;
	}else{
		if((i = note_buf_search(ch, note, 1)) < 0) return;
		note_buf[i].onoff = 0;
		note_buf[i].off_sec = evt_sec;
	}
}

void
bend_note_update(int ch, double sec)
{
	int i;

	for(i=0; i<NOTE_BUF_N; i++){
		if(note_buf_is_free(i)) continue;
		if(note_buf[i].ch != ch) continue;
		note_buf[i].cycle += note_buf[i].freq * (sec - note_buf[i].sec);
		note_buf[i].sec = sec;
	}
}
// pitch wheel changeイベントの際に呼び出される
// 鍵盤情報のバッファから、イベントのMIDIチャンネルの情報を更新する
// 
// 更新する情報は、サイクルと時間
// 時間をイベントの時刻まで進め、
// サイクルもその時刻の値を算出して設定する


int
main(int ac, char **av)
{
	int div4, delta_sum;
	int i, n, v, hi, low, note, velo;
	int ch, type;
	double sec;
	struct out_rec otr;
	int tempo, tempo_delta_sum;
	double tempo_sec;

	out_init(&otr, ac, av);
	note_buf_init();
	for(i=0; i<MIDI_CH_N; i++){
		ch_vol[i] = 0;
		ch_pan[i] = 1<<(14-1);
		ch_bend[i] = 0;
		ch_rpn[i] = 0;
		ch_bend_range[i] = 2;
		// MIDIチャンネル毎の情報として追加した
		// ch_bend[], ch_rpn[], ch_bend_range[] を初期化
		// ch_bend_range[] の初期値は 2 (全音)
		
	}
	tempo = 500000;
	tempo_delta_sum = 0;
	tempo_sec = 0;

	div4 = header();

	if(!rd_str_chk(4, "MTrk")) ERR("track id");
	v = rd_int(4); /* skip */

	hi = low = 0;
	delta_sum = 0;
	while((v = rd_delta()) != EOF){
		delta_sum += v;
		sec = tempo_sec + (double)(delta_sum - tempo_delta_sum) / div4 * tempo * 0.000001;
		
		if((v = rd()) & 0x80){
			hi = (v >> 4) & 0xf;
			low  = v & 0xf;
		}else bk(v);

		data_out(&otr, sec);

		ch = low;
		switch(hi){
		case 8:
		case 9:
			note = rd();
			velo = rd();
			note_onoff(hi == 9, sec, ch, note, velo);
			break;
		case 0xb: /* control change */
			type = rd();
			v = rd();
			switch(type){
			case 7: /* channel volume msb */
				ch_vol[ch] &= ~(127<<7);
				ch_vol[ch] |= v<<7;
				break;
			case 39: /* channel volume lsb */
				ch_vol[ch] &= ~127;
				ch_vol[ch] |= v;
				break;
			case 10: /* pan msb */
				ch_pan[ch] &= ~(127<<7);
				ch_pan[ch] |= v<<7;
				break;
			case 42: /* pan lsb */
				ch_pan[ch] &= ~127;
				ch_pan[ch] |= v;
				break;
			case 100: /* rpn lsb */
			// コントロール・チェンジのタイプ100ならば
			
				ch_rpn[ch] &= ~127;
				ch_rpn[ch] |= v;
				// 該当チャンネルの ch_rpn[] の LSB 7 ビットを設定
				
				break;
			case 101: /* rpn msb */
			// コントロール・チェンジのタイプ101ならば
			
				ch_rpn[ch] &= ~(127<<7);
				ch_rpn[ch] |= v<<7;
				// 該当チャンネルの ch_rpn[] の MSB 7 ビットを設定
				
				break;
			case 6: /* data entry msb */
			// コントロール・チェンジのタイプ106ならば
			
				switch(ch_rpn[ch]){
				case 0: /* pitch bend range */
					ch_bend_range[ch] = v;
					break;
				}
				// 該当チャンネルの ch_rpn[] を参照し
				// 値が 0 のときだけ、
				// コントロール・チェンジの値 v を、
				// 該当チャンネルの ch_bend_range[] へと設定する
				
				break;
			}
			break;
		case 0xa:
			rd();
			rd();
			break;
		case 0xe: /* pitch wheel change */
		// pitch wheel changeイベントならば
		
			bend_note_update(ch, sec);
			v = rd();
			v |= rd() << 7;
			ch_bend[ch] = v - 8192;
			// 該当チャンネルの鍵盤情報を、
			// イベント時刻まで更新
			//
			// イベントの2バイト目を 下位7ビット
			// イベントの3バイト目を 上位7ビット
			// とした整数を v に算出
			// v の値 (0〜16383) から 8192 をひいて、
			// -8192〜8191 の範囲の値に変換し ch_bend[] へ設定する
			
			break;
		case 0xc:		
		case 0xd:
			rd();
			break;
		case 0xf:
			type = rd();
			switch(low){
			case 0:
				while(rd() != 0xf7);
				break;
			case 1:
			case 3:
				rd();
				break;
			case 2:
				rd();
				rd();
				break;
			case 0xf: /* meta */
				n = rd();
				switch(type){
				case 0x51: /* set tempo */
					v = rd_int(n);
					tempo = v;
					tempo_delta_sum = delta_sum;
					tempo_sec = sec;
					break;
				default:
					for(i=0; i<n; i++) rd();
					break;
				}
				break;
			default:
				break;
			}
			break;
		}
	}
	if(otr.fp != stdout) pclose(otr.fp);
	return 0;
}

/* EOF */


prog7.c 解説

prog6.c からの変更箇所のみ

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <math.h>

#define MSG(s) fprintf(stderr, "%s() %s L%d : %s\n", __func__, __FILE__, __LINE__, s)
#define ERR(s) do{ fprintf(stderr, "ERR "); MSG(s); exit(1); }while(0)

int bk_buf = -1;

int
rd(void)
{
	int v;

	if((v = bk_buf) < 0) return getchar();
	bk_buf = -1;
	return v;
}

void
bk(int v)
{
	if(bk_buf >= 0) ERR("give up");
	bk_buf = v;
}

void
rd_str(int n, char *s)
{
	int i;

	for(i=0; i<n; i++) s[i] = rd();
	s[i] = '\0';
}

int
rd_str_chk(int n, char *s)
{
	char buf[256];

	rd_str(n, buf);
	return strcmp(buf, s) == 0;
}

int
rd_int(int n) /* big endian */
{
	int i, v;

	v = 0;
	for(i=0; i<n; i++) v = (v << 8) | rd();
	return v;
}

int
rd_delta(void)
{
	int v, c;

	v = 0;
	do{
		if((c = rd()) == EOF) return EOF;
		v = (v << 7) | (c & 0x7f);
	}while(c & 0x80);
	return v;
}


#define NOTE_BUF_N	256

struct note_rec{
	int ch;
	int note;
	int onoff;
	double on_sec;
	double off_sec;
	int velo;
	double cycle, sec, freq;
} note_buf[NOTE_BUF_N];

int
note_buf_is_free(int i)
{
	return note_buf[i].ch < 0;
}

void
note_buf_free(int i)
{
	note_buf[i].ch = -1;
}

void
note_buf_init(void)
{
	int i;

	for(i=0; i<NOTE_BUF_N; i++) note_buf_free(i);
}

int
note_buf_search(int ch, int note, int onoff)
{
	int i;

	for(i=0; i<NOTE_BUF_N; i++) {
		if( (ch < 0 && note_buf[i].ch < 0) ||
		    (note_buf[i].ch == ch &&
		     note_buf[i].note == note &&
		     note_buf[i].onoff == onoff) ) return i;
	}
	return -1;
}

int
header(void)
{
	int v;

	if(!rd_str_chk(4, "MThd")) ERR("header id");
	if(rd_int(4) != 6) ERR("header size");
	if(rd_int(2) != 0) ERR("header format type");
	if(rd_int(2) != 1) ERR("header track num");
	if((v = rd_int(2)) & 0x8000) ERR("header division");
	return v; /* div4 */
}

double
note_to_freq(int note)
{
	return 440 * pow(2, (note - 69) / 12.0);
}

int
opt_idx(char *key, int ac, char **av)
{
	int i;

	for(i=1; i<ac; i++) if(strcmp(av[i], key) == 0) return i;
	return -1;
}

char *
opt_str(char *key, int ac, char **av, char *def)
{
	int i;

	i = opt_idx(key, ac, av);
	if(i < 0 || i+1 >= ac) return def;
	return av[i+1];
}

int
opt_int(char *key, int ac, char **av, int def)
{
	char *s;

	if((s = opt_str(key, ac, av, NULL)) == NULL) return def;
	return strtol(s, NULL, 0);
}

struct out_rec{
	int smp_freq, smp_cnt;
	int bit_len;
	int sign;
	int ch_num;
	FILE *fp;

	int base;
	int amp;
	int iv_min;
	int iv_max;
};

void
out_init(struct out_rec *ot, int ac, char **av)
{
	char cmd[1024], *fn;

	ot->smp_freq = opt_int("-r", ac, av, 8000);
	ot->smp_cnt = 0;
	ot->bit_len = opt_int("-b", ac, av, 8);
	if(ot->bit_len != 8 && ot->bit_len != 16) ERR("bit_len");
	ot->sign = (opt_idx("-s", ac, av) >= 0);
	ot->ch_num = opt_int("-c", ac, av, 1);

	ot->fp = stdout;
	cmd[0] = '\0';
	fn = "";
	if(opt_idx("-play", ac, av) >= 0){
		strcat(cmd, "play");
	}else if(opt_idx("-sox", ac, av) >= 0){
		strcat(cmd, "sox");
		fn = opt_str("-sox", ac, av, "-d");
	}
	if(cmd[0]){
		sprintf(cmd + strlen(cmd), " -t raw -r %d -b %d %s -c %d - %s",
			ot->smp_freq, ot->bit_len,
			ot->sign ? "-s" : "-u",
			ot->ch_num, fn);
		if((ot->fp = popen(cmd, "w")) == NULL) ERR("popen");
	}
	ot->amp = ot->bit_len == 8 ? 127 : 32767;
	ot->base = ot->sign ? 0 : ot->amp + 1;
	ot->iv_min = ot->base - (ot->amp + 1);
	ot->iv_max = ot->base + ot->amp;
}

void
out_do(struct out_rec *ot, double v)
{
	int iv;

	iv = ot->base + (int)(v *ot->amp);
	if(iv > ot->iv_max) iv = ot->iv_max;
	if(iv < ot->iv_min) iv = ot->iv_min;
	switch(ot->bit_len){
	case 8:
		fputc(iv, ot->fp);
		break;
	case 16:
		fputc(iv & 0xff, ot->fp);
		fputc((iv >> 8) & 0xff, ot->fp);
		break;
	}
}

#define MIDI_CH_N	16
struct ch_rec{
	int vol;
	int pan;
	int bend;
	int rpn;
	int bend_range;
} ch_inf[ MIDI_CH_N ];

void
data_out(struct out_rec *ot, double evt_sec)
{
	double v, sec, freq, dsec;
	double vl, vr, pan;
	double release;
	int i, nch;
	struct note_rec *nt;

	release = 0.3;
	while((sec = (double)ot->smp_cnt / ot->smp_freq) < evt_sec){
		vl = vr = 0;
		for(i=0; i<NOTE_BUF_N; i++){
			if(note_buf_is_free(i)) continue;
			nt = &note_buf[i];
			nch = nt->ch;
			freq = note_to_freq(nt->note);
			if(ch_inf[nch].bend != 0) freq *= pow(2, ch_inf[nch].bend / 8192.0 * ch_inf[nch].bend_range / 12);
			dsec = sec - nt->on_sec;
			if(dsec > 0.3) freq *= pow(2, sin(2 * M_PI * 6 * dsec) / (12 * 4) );
			nt->cycle += freq * (sec - nt->sec);
			nt->sec = sec;
			nt->freq = freq;
			v = sin(2 * M_PI * nt->cycle);
			v *= nt->velo / 127.0;
			v *= ch_inf[nch].vol / (double)((1<<14)-1);
			if(nt->onoff == 0){
				dsec = sec - nt->off_sec;
				v *= 1 - dsec / release;
				if(dsec >= release) note_buf_free(i);
			}
			if(ot->ch_num == 1){
				vl += v;
			}else{
				pan = ch_inf[nch].pan / (double)(1<<14);
				vl += (1 - pan) * v;
				vr += pan * v;
			}
		}
		out_do(ot, vl / 16);
		if(ot->ch_num > 1) out_do(ot, vr / 16);
		ot->smp_cnt++;
	}
}

void
note_onoff(int onoff, double evt_sec, int ch, int note, int velo)
{
	int i;

	if(ch == 9) return;

	if(onoff){
		if((i = note_buf_search(-1, -1, -1)) < 0){
			MSG("note_buf full");
			return;
		}
		note_buf[i].note = note;
		note_buf[i].ch = ch;
		note_buf[i].onoff = 1;
		note_buf[i].on_sec = evt_sec;
		note_buf[i].velo = velo;
		note_buf[i].cycle = 0;
		note_buf[i].sec = evt_sec;
	}else{
		if((i = note_buf_search(ch, note, 1)) < 0) return;
		note_buf[i].onoff = 0;
		note_buf[i].off_sec = evt_sec;
	}
}

void
msb_set(int *vp, int v)
{
	*vp &= ~(127<<7);
	*vp |= v<<7;
}

void
lsb_set(int *vp, int v)
{
	*vp &= ~127;
	*vp |= v;
}

void
bend_note_update(int ch, double sec)
{
	int i;
	struct note_rec *nt;

	for(i=0; ich != ch) continue;
		nt->cycle += nt->freq * (sec - nt->sec);
		nt->sec = sec;
	}
}

int
main(int ac, char **av)
{
	int div4, delta_sum;
	int i, n, v, hi, low, note, velo;
	int ch, type;
	double sec;
	struct out_rec otr;
	int tempo, tempo_delta_sum;
	double tempo_sec;

	out_init(&otr, ac, av);
	note_buf_init();
	for(i=0; i<MIDI_CH_N; i++){
		ch_inf[i].vol = 0;
		ch_inf[i].pan = 1<<(14-1);
		ch_inf[i].bend = 0;
		ch_inf[i].rpn = 0;
		ch_inf[i].bend_range = 2;
	}
	tempo = 500000;
	tempo_delta_sum = 0;
	tempo_sec = 0;

	div4 = header();

	if(!rd_str_chk(4, "MTrk")) ERR("track id");
	v = rd_int(4); /* skip */

	hi = low = 0;
	delta_sum = 0;
	while((v = rd_delta()) != EOF){
		delta_sum += v;
		sec = tempo_sec + (double)(delta_sum - tempo_delta_sum) / div4 * tempo * 0.000001;
		
		if((v = rd()) & 0x80){
			hi = (v >> 4) & 0xf;
			low  = v & 0xf;
		}else bk(v);

		data_out(&otr, sec);

		ch = low;
		switch(hi){
		case 8:
		case 9:
			note = rd();
			velo = rd();
			note_onoff(hi == 9, sec, ch, note, velo);
			break;
		case 0xb: /* control change */
			type = rd();
			v = rd();
			switch(type){
			case 7: /* channel volume msb */
				msb_set(&ch_inf[ch].vol, v);
				break;
			case 39: /* channel volume lsb */
				lsb_set(&ch_inf[ch].vol, v);
				break;
			case 10: /* pan msb */
				msb_set(&ch_inf[ch].pan, v);
				break;
			case 42: /* pan lsb */
				lsb_set(&ch_inf[ch].pan, v);
				break;
			case 100: /* rpn lsb */
				lsb_set(&ch_inf[ch].rpn, v);
				break;
			case 101: /* rpn msb */
				msb_set(&ch_inf[ch].rpn, v);
				break;
			case 6: /* data entry msb */
				switch(ch_inf[ch].rpn){
				case 0: /* pitch bend range */
					ch_inf[ch].bend_range = v;
					break;
				}
				break;
			}
			break;
		case 0xa:
			rd();
			rd();
			break;
		case 0xe: /* pitch wheel change */
			bend_note_update(ch, sec);
			v = rd();
			v |= rd() << 7;
			ch_inf[ch].bend = v - 8192;
			break;
		case 0xc:		
		case 0xd:
			rd();
			break;
		case 0xf:
			type = rd();
			switch(low){
			case 0:
				while(rd() != 0xf7);
				break;
			case 1:
			case 3:
				rd();
				break;
			case 2:
				rd();
				rd();
				break;
			case 0xf: /* meta */
				n = rd();
				switch(type){
				case 0x51: /* set tempo */
					v = rd_int(n);
					tempo = v;
					tempo_delta_sum = delta_sum;
					tempo_sec = sec;
					break;
				default:
					for(i=0; i<n; i++) rd();
					break;
				}
				break;
			default:
				break;
			}
			break;
		}
	}
	if(otr.fp != stdout) pclose(otr.fp);
	return 0;
}

/* EOF */


#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <math.h>

#define MSG(s) fprintf(stderr, "%s() %s L%d : %s\n", __func__, __FILE__, __LINE__, s)
#define ERR(s) do{ fprintf(stderr, "ERR "); MSG(s); exit(1); }while(0)

int bk_buf = -1;

int
rd(void)
{
	int v;

	if((v = bk_buf) < 0) return getchar();
	bk_buf = -1;
	return v;
}

void
bk(int v)
{
	if(bk_buf >= 0) ERR("give up");
	bk_buf = v;
}

void
rd_str(int n, char *s)
{
	int i;

	for(i=0; i<n; i++) s[i] = rd();
	s[i] = '\0';
}

int
rd_str_chk(int n, char *s)
{
	char buf[256];

	rd_str(n, buf);
	return strcmp(buf, s) == 0;
}

int
rd_int(int n) /* big endian */
{
	int i, v;

	v = 0;
	for(i=0; i<n; i++) v = (v << 8) | rd();
	return v;
}

int
rd_delta(void)
{
	int v, c;

	v = 0;
	do{
		if((c = rd()) == EOF) return EOF;
		v = (v << 7) | (c & 0x7f);
	}while(c & 0x80);
	return v;
}


#define NOTE_BUF_N	256

struct note_rec{
	int ch;
	int note;
	int onoff;
	double on_sec;
	double off_sec;
	int velo;
	double cycle, sec, freq;
} note_buf[NOTE_BUF_N];

int
note_buf_is_free(int i)
{
	return note_buf[i].ch < 0;
}

void
note_buf_free(int i)
{
	note_buf[i].ch = -1;
}

void
note_buf_init(void)
{
	int i;

	for(i=0; i<NOTE_BUF_N; i++) note_buf_free(i);
}

int
note_buf_search(int ch, int note, int onoff)
{
	int i;

	for(i=0; i<NOTE_BUF_N; i++) {
		if( (ch < 0 && note_buf[i].ch < 0) ||
		    (note_buf[i].ch == ch &&
		     note_buf[i].note == note &&
		     note_buf[i].onoff == onoff) ) return i;
	}
	return -1;
}

int
header(void)
{
	int v;

	if(!rd_str_chk(4, "MThd")) ERR("header id");
	if(rd_int(4) != 6) ERR("header size");
	if(rd_int(2) != 0) ERR("header format type");
	if(rd_int(2) != 1) ERR("header track num");
	if((v = rd_int(2)) & 0x8000) ERR("header division");
	return v; /* div4 */
}

double
note_to_freq(int note)
{
	return 440 * pow(2, (note - 69) / 12.0);
}

int
opt_idx(char *key, int ac, char **av)
{
	int i;

	for(i=1; i<ac; i++) if(strcmp(av[i], key) == 0) return i;
	return -1;
}

char *
opt_str(char *key, int ac, char **av, char *def)
{
	int i;

	i = opt_idx(key, ac, av);
	if(i < 0 || i+1 >= ac) return def;
	return av[i+1];
}

int
opt_int(char *key, int ac, char **av, int def)
{
	char *s;

	if((s = opt_str(key, ac, av, NULL)) == NULL) return def;
	return strtol(s, NULL, 0);
}

struct out_rec{
	int smp_freq, smp_cnt;
	int bit_len;
	int sign;
	int ch_num;
	FILE *fp;

	int base;
	int amp;
	int iv_min;
	int iv_max;
};

void
out_init(struct out_rec *ot, int ac, char **av)
{
	char cmd[1024], *fn;

	ot->smp_freq = opt_int("-r", ac, av, 8000);
	ot->smp_cnt = 0;
	ot->bit_len = opt_int("-b", ac, av, 8);
	if(ot->bit_len != 8 && ot->bit_len != 16) ERR("bit_len");
	ot->sign = (opt_idx("-s", ac, av) >= 0);
	ot->ch_num = opt_int("-c", ac, av, 1);

	ot->fp = stdout;
	cmd[0] = '\0';
	fn = "";
	if(opt_idx("-play", ac, av) >= 0){
		strcat(cmd, "play");
	}else if(opt_idx("-sox", ac, av) >= 0){
		strcat(cmd, "sox");
		fn = opt_str("-sox", ac, av, "-d");
	}
	if(cmd[0]){
		sprintf(cmd + strlen(cmd), " -t raw -r %d -b %d %s -c %d - %s",
			ot->smp_freq, ot->bit_len,
			ot->sign ? "-s" : "-u",
			ot->ch_num, fn);
		if((ot->fp = popen(cmd, "w")) == NULL) ERR("popen");
	}
	ot->amp = ot->bit_len == 8 ? 127 : 32767;
	ot->base = ot->sign ? 0 : ot->amp + 1;
	ot->iv_min = ot->base - (ot->amp + 1);
	ot->iv_max = ot->base + ot->amp;
}

void
out_do(struct out_rec *ot, double v)
{
	int iv;

	iv = ot->base + (int)(v *ot->amp);
	if(iv > ot->iv_max) iv = ot->iv_max;
	if(iv < ot->iv_min) iv = ot->iv_min;
	switch(ot->bit_len){
	case 8:
		fputc(iv, ot->fp);
		break;
	case 16:
		fputc(iv & 0xff, ot->fp);
		fputc((iv >> 8) & 0xff, ot->fp);
		break;
	}
}

#define MIDI_CH_N	16
struct ch_rec{
	int vol;
	int pan;
	int bend;
	int rpn;
	int bend_range;
} ch_inf[ MIDI_CH_N ];
// MIDIチャンネルごとの情報を構造体にまとめた
//
// vol は、ボリューム (14 bit 音量)
// pan は、Panpot (14 bit 左右のバランス)
// bend は、ピッチ・ベンドの値 (-8192〜8191)
// rpn は、RPN の値 ( MSB 7ビット, LSB 7ビット)
// bend_range は、ベンド・レンジ (整数、ピッチ・ベンド値を最高にしたときの半音の数)

void
data_out(struct out_rec *ot, double evt_sec)
{
	double v, sec, freq, dsec;
	double vl, vr, pan;
	double release;
	int i, nch;
	struct note_rec *nt;
	// 鍵盤情報用の構造体の変数を追加
	
	release = 0.3;
	while((sec = (double)ot->smp_cnt / ot->smp_freq) < evt_sec){
		vl = vr = 0;
		for(i=0; i<NOTE_BUF_N; i++){
			if(note_buf_is_free(i)) continue;
			nt = &note_buf[i];
			// 追加した鍵盤情報の変数 nt を設定
			//
			// 以降、この for ループ内から
			// note_buf[i]. としてアクセスしてた箇所は
			// nt-> のアクセスに置き換える
			
			nch = nt->ch;
			freq = note_to_freq(nt->note);
			if(ch_inf[nch].bend != 0) freq *= pow(2, ch_inf[nch].bend / 8192.0 * ch_inf[nch].bend_range / 12);
			// ch_rec 構造体を使うように変更
			
			dsec = sec - nt->on_sec;
			if(dsec > 0.3) freq *= pow(2, sin(2 * M_PI * 6 * dsec) / (12 * 4) );
			nt->cycle += freq * (sec - nt->sec);
			nt->sec = sec;
			nt->freq = freq;
			v = sin(2 * M_PI * nt->cycle);
			v *= nt->velo / 127.0;
			v *= ch_inf[nch].vol / (double)((1<<14)-1);
			// ch_rec 構造体を使うように変更
			
			if(nt->onoff == 0){
				dsec = sec - nt->off_sec;
				v *= 1 - dsec / release;
				if(dsec >= release) note_buf_free(i);
			}
			if(ot->ch_num == 1){
				vl += v;
			}else{
				pan = ch_inf[nch].pan / (double)(1<<14);
				// ch_rec 構造体を使うように変更
				
				vl += (1 - pan) * v;
				vr += pan * v;
			}
		}
		out_do(ot, vl / 16);
		if(ot->ch_num > 1) out_do(ot, vr / 16);
		ot->smp_cnt++;
	}
}

void
note_onoff(int onoff, double evt_sec, int ch, int note, int velo)
{
	int i;

	if(ch == 9) return;

	if(onoff){
		if((i = note_buf_search(-1, -1, -1)) < 0){
			MSG("note_buf full");
			return;
		}
		note_buf[i].note = note;
		note_buf[i].ch = ch;
		note_buf[i].onoff = 1;
		note_buf[i].on_sec = evt_sec;
		note_buf[i].velo = velo;
		note_buf[i].cycle = 0;
		note_buf[i].sec = evt_sec;
	}else{
		if((i = note_buf_search(ch, note, 1)) < 0) return;
		note_buf[i].onoff = 0;
		note_buf[i].off_sec = evt_sec;
	}
}

void
msb_set(int *vp, int v)
{
	// MSB設定用
	//
	// 引数 vp は、設定する変数のポインタ
	// 引数 v は、上位 7 ビットの値
	
	*vp &= ~(127<<7);
	*vp |= v<<7;
}

void
lsb_set(int *vp, int v)
{
	// LSB設定用
	//
	// 引数 vp は、設定する変数のポインタ
	// 引数 v は、下位 7 ビットの値
	
	*vp &= ~127;
	*vp |= v;
}

void
bend_note_update(int ch, double sec)
{
	int i;
	struct note_rec *nt;

	for(i=0; ich != ch) continue;
		nt->cycle += nt->freq * (sec - nt->sec);
		nt->sec = sec;
	}
}

int
main(int ac, char **av)
{
	int div4, delta_sum;
	int i, n, v, hi, low, note, velo;
	int ch, type;
	double sec;
	struct out_rec otr;
	int tempo, tempo_delta_sum;
	double tempo_sec;

	out_init(&otr, ac, av);
	note_buf_init();
	for(i=0; i<MIDI_CH_N; i++){
		ch_inf[i].vol = 0;
		ch_inf[i].pan = 1<<(14-1);
		ch_inf[i].bend = 0;
		ch_inf[i].rpn = 0;
		ch_inf[i].bend_range = 2;
		// ch_rec 構造体を初期化
		
	}
	tempo = 500000;
	tempo_delta_sum = 0;
	tempo_sec = 0;

	div4 = header();

	if(!rd_str_chk(4, "MTrk")) ERR("track id");
	v = rd_int(4); /* skip */

	hi = low = 0;
	delta_sum = 0;
	while((v = rd_delta()) != EOF){
		delta_sum += v;
		sec = tempo_sec + (double)(delta_sum - tempo_delta_sum) / div4 * tempo * 0.000001;
		
		if((v = rd()) & 0x80){
			hi = (v >> 4) & 0xf;
			low  = v & 0xf;
		}else bk(v);

		data_out(&otr, sec);

		ch = low;
		switch(hi){
		case 8:
		case 9:
			note = rd();
			velo = rd();
			note_onoff(hi == 9, sec, ch, note, velo);
			break;
		case 0xb: /* control change */
			type = rd();
			v = rd();
			switch(type){
			case 7: /* channel volume msb */
				msb_set(&ch_inf[ch].vol, v);
				// ch_rec 構造体を使うように変更
				// 追加した msb_set() 関数を使うように変更
				
				break;
			case 39: /* channel volume lsb */
				lsb_set(&ch_inf[ch].vol, v);
				// ch_rec 構造体を使うように変更
				// 追加した lsb_set() 関数を使うように変更
				
				break;
			case 10: /* pan msb */
				msb_set(&ch_inf[ch].pan, v);
				// ch_rec 構造体を使うように変更
				// 追加した msb_set() 関数を使うように変更
				
				break;
			case 42: /* pan lsb */
				lsb_set(&ch_inf[ch].pan, v);
				// ch_rec 構造体を使うように変更
				// 追加した lsb_set() 関数を使うように変更
				
				break;
			case 100: /* rpn lsb */
				lsb_set(&ch_inf[ch].rpn, v);
				// ch_rec 構造体を使うように変更
				// 追加した lsb_set() 関数を使うように変更
				
				break;
			case 101: /* rpn msb */
				msb_set(&ch_inf[ch].rpn, v);
				// ch_rec 構造体を使うように変更
				// 追加した msb_set() 関数を使うように変更
				
				break;
			case 6: /* data entry msb */
				switch(ch_inf[ch].rpn){
				case 0: /* pitch bend range */
					ch_inf[ch].bend_range = v;
					break;
				}
				// ch_rec 構造体を使うように変更
				
				break;
			}
			break;
		case 0xa:
			rd();
			rd();
			break;
		case 0xe: /* pitch wheel change */
			bend_note_update(ch, sec);
			v = rd();
			v |= rd() << 7;
			ch_inf[ch].bend = v - 8192;
			// ch_rec 構造体を使うように変更
			
			break;
		case 0xc:		
		case 0xd:
			rd();
			break;
		case 0xf:
			type = rd();
			switch(low){
			case 0:
				while(rd() != 0xf7);
				break;
			case 1:
			case 3:
				rd();
				break;
			case 2:
				rd();
				rd();
				break;
			case 0xf: /* meta */
				n = rd();
				switch(type){
				case 0x51: /* set tempo */
					v = rd_int(n);
					tempo = v;
					tempo_delta_sum = delta_sum;
					tempo_sec = sec;
					break;
				default:
					for(i=0; i<n; i++) rd();
					break;
				}
				break;
			default:
				break;
			}
			break;
		}
	}
	if(otr.fp != stdout) pclose(otr.fp);
	return 0;
}

/* EOF */


prog8.c 解説

prog7.c からの変更箇所のみ

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <math.h>

#define MSG(s) fprintf(stderr, "%s() %s L%d : %s\n", __func__, __FILE__, __LINE__, s)
#define ERR(s) do{ fprintf(stderr, "ERR "); MSG(s); exit(1); }while(0)

int bk_buf = -1;

int
rd(void)
{
	int v;

	if((v = bk_buf) < 0) return getchar();
	bk_buf = -1;
	return v;
}

void
bk(int v)
{
	if(bk_buf >= 0) ERR("give up");
	bk_buf = v;
}

void
rd_str(int n, char *s)
{
	int i;

	for(i=0; i<n; i++) s[i] = rd();
	s[i] = '\0';
}

int
rd_str_chk(int n, char *s)
{
	char buf[256];

	rd_str(n, buf);
	return strcmp(buf, s) == 0;
}

int
rd_int(int n) /* big endian */
{
	int i, v;

	v = 0;
	for(i=0; i<n; i++) v = (v << 8) | rd();
	return v;
}

int
rd_delta(void)
{
	int v, c;

	v = 0;
	do{
		if((c = rd()) == EOF) return EOF;
		v = (v << 7) | (c & 0x7f);
	}while(c & 0x80);
	return v;
}


#define NOTE_BUF_N	256

struct note_rec{
	int ch;
	int note;
	int onoff;
	double on_sec;
	double off_sec;
	int velo;
	double cycle, sec, freq;
	double off_v;
} note_buf[NOTE_BUF_N];

int
note_buf_is_free(int i)
{
	return note_buf[i].ch < 0;
}

void
note_buf_free(int i)
{
	note_buf[i].ch = -1;
}

void
note_buf_init(void)
{
	int i;

	for(i=0; i<NOTE_BUF_N; i++) note_buf_free(i);
}

int
note_buf_search(int ch, int note, int onoff)
{
	int i;

	for(i=0; i<NOTE_BUF_N; i++) {
		if( (ch < 0 && note_buf[i].ch < 0) ||
		    (note_buf[i].ch == ch &&
		     note_buf[i].note == note &&
		     note_buf[i].onoff == onoff) ) return i;
	}
	return -1;
}

int
header(void)
{
	int v;

	if(!rd_str_chk(4, "MThd")) ERR("header id");
	if(rd_int(4) != 6) ERR("header size");
	if(rd_int(2) != 0) ERR("header format type");
	if(rd_int(2) != 1) ERR("header track num");
	if((v = rd_int(2)) & 0x8000) ERR("header division");
	return v; /* div4 */
}

double
note_to_freq(int note)
{
	return 440 * pow(2, (note - 69) / 12.0);
}

int
opt_idx(char *key, int ac, char **av)
{
	int i;

	for(i=1; i<ac; i++) if(strcmp(av[i], key) == 0) return i;
	return -1;
}

char *
opt_str(char *key, int ac, char **av, char *def)
{
	int i;

	i = opt_idx(key, ac, av);
	if(i < 0 || i+1 >= ac) return def;
	return av[i+1];
}

int
opt_int(char *key, int ac, char **av, int def)
{
	char *s;

	if((s = opt_str(key, ac, av, NULL)) == NULL) return def;
	return strtol(s, NULL, 0);
}

struct out_rec{
	int smp_freq, smp_cnt;
	int bit_len;
	int sign;
	int ch_num;
	FILE *fp;

	int base;
	int amp;
	int iv_min;
	int iv_max;
};

void
out_init(struct out_rec *ot, int ac, char **av)
{
	char cmd[1024], *fn;

	ot->smp_freq = opt_int("-r", ac, av, 8000);
	ot->smp_cnt = 0;
	ot->bit_len = opt_int("-b", ac, av, 8);
	if(ot->bit_len != 8 && ot->bit_len != 16) ERR("bit_len");
	ot->sign = (opt_idx("-s", ac, av) >= 0);
	ot->ch_num = opt_int("-c", ac, av, 1);

	ot->fp = stdout;
	cmd[0] = '\0';
	fn = "";
	if(opt_idx("-play", ac, av) >= 0){
		strcat(cmd, "play");
	}else if(opt_idx("-sox", ac, av) >= 0){
		strcat(cmd, "sox");
		fn = opt_str("-sox", ac, av, "-d");
	}
	if(cmd[0]){
		sprintf(cmd + strlen(cmd), " -t raw -r %d -b %d %s -c %d - %s",
			ot->smp_freq, ot->bit_len,
			ot->sign ? "-s" : "-u",
			ot->ch_num, fn);
		if((ot->fp = popen(cmd, "w")) == NULL) ERR("popen");
	}
	ot->amp = ot->bit_len == 8 ? 127 : 32767;
	ot->base = ot->sign ? 0 : ot->amp + 1;
	ot->iv_min = ot->base - (ot->amp + 1);
	ot->iv_max = ot->base + ot->amp;
}

void
out_do(struct out_rec *ot, double v)
{
	int iv;

	iv = ot->base + (int)(v *ot->amp);
	if(iv > ot->iv_max) iv = ot->iv_max;
	if(iv < ot->iv_min) iv = ot->iv_min;
	switch(ot->bit_len){
	case 8:
		fputc(iv, ot->fp);
		break;
	case 16:
		fputc(iv & 0xff, ot->fp);
		fputc((iv >> 8) & 0xff, ot->fp);
		break;
	}
}

struct env_rec{
	double attack;	/* sec */
	double decay;	/* sec */
	double sustain;	/* 0..1 */
	double release;	/* sec */
};

void
env_set(struct env_rec *e, double a, double d, double s, double r)
{
	e->attack = a;
	e->decay = d;
	e->sustain = s;
	e->release = r;
}

#define MIDI_CH_N	16
struct ch_rec{
	int vol;
	int pan;
	int bend;
	int rpn;
	int bend_range;
	struct env_rec env;
} ch_inf[ MIDI_CH_N ];

double
env_out(struct note_rec *nt)
{
	struct env_rec *e;
	double sec, v;

	sec = nt->sec;
	e = &ch_inf[nt->ch].env;
	if(nt->onoff){
		sec -= nt->on_sec;
		if(sec < e->attack){
			v = sec / e->attack;
			return log10(1 + v * 9);
		}
		sec -= e->attack;
		if(sec < e->decay){
			v = sec / e->decay;
			v = log10(1 + v * 9);
			return 1 - v * (1 - e->sustain);
		}
		return e->sustain;
	}
	sec -= nt->off_sec;
	if(sec < e->release){
		v = sec / e->release;
		v = log10(1 + v * 9);
		return (1 - v) * nt->off_v;
	}
	return 0;
}

void
data_out(struct out_rec *ot, double evt_sec)
{
	double v, sec, freq, dsec;
	double vl, vr, pan;
	int i, nch;
	struct note_rec *nt;

	while((sec = (double)ot->smp_cnt / ot->smp_freq) < evt_sec){
		vl = vr = 0;
		for(i=0; i<NOTE_BUF_N; i++){
			if(note_buf_is_free(i)) continue;
			nt = &note_buf[i];
			nch = nt->ch;
			freq = note_to_freq(nt->note);
			if(ch_inf[nch].bend != 0) freq *= pow(2, ch_inf[nch].bend / 8192.0 * ch_inf[nch].bend_range / 12);
			dsec = sec - nt->on_sec;
			if(dsec > 0.3) freq *= pow(2, sin(2 * M_PI * 6 * dsec) / (12 * 4) );
			nt->cycle += freq * (sec - nt->sec);
			nt->sec = sec;
			nt->freq = freq;
			v = sin(2 * M_PI * nt->cycle);
			v *= env_out(&note_buf[i]);
			v *= nt->velo / 127.0;
			v *= ch_inf[nch].vol / (double)((1<<14)-1);
			if(ot->ch_num == 1){
				vl += v;
			}else{
				pan = ch_inf[nch].pan / (double)(1<<14);
				vl += (1 - pan) * v;
				vr += pan * v;
			}
			if(nt->onoff == 0 && sec - nt->off_sec >= ch_inf[nch].env.release) note_buf_free(i);
		}
		out_do(ot, vl / 16);
		if(ot->ch_num > 1) out_do(ot, vr / 16);
		ot->smp_cnt++;
	}
}

void
note_onoff(int onoff, double evt_sec, int ch, int note, int velo)
{
	int i;

	if(ch == 9) return;

	if(onoff){
		if((i = note_buf_search(-1, -1, -1)) < 0){
			MSG("note_buf full");
			return;
		}
		note_buf[i].note = note;
		note_buf[i].ch = ch;
		note_buf[i].onoff = 1;
		note_buf[i].on_sec = evt_sec;
		note_buf[i].velo = velo;
		note_buf[i].cycle = 0;
		note_buf[i].sec = evt_sec;
	}else{
		if((i = note_buf_search(ch, note, 1)) < 0) return;
		note_buf[i].off_v = env_out(&note_buf[i]);
		note_buf[i].onoff = 0;
		note_buf[i].off_sec = evt_sec;
	}
}

void
msb_set(int *vp, int v)
{
	*vp &= ~(127<<7);
	*vp |= v<<7;
}

void
lsb_set(int *vp, int v)
{
	*vp &= ~127;
	*vp |= v;
}

void
bend_note_update(int ch, double sec)
{
	int i;
	struct note_rec *nt;

	for(i=0; ich != ch) continue;
		nt->cycle += nt->freq * (sec - nt->sec);
		nt->sec = sec;
	}
}

int
main(int ac, char **av)
{
	int div4, delta_sum;
	int i, n, v, hi, low, note, velo;
	int ch, type;
	double sec;
	struct out_rec otr;
	int tempo, tempo_delta_sum;
	double tempo_sec;

	out_init(&otr, ac, av);
	note_buf_init();
	for(i=0; i<MIDI_CH_N; i++){
		ch_inf[i].vol = 0;
		ch_inf[i].pan = 1<<(14-1);
		ch_inf[i].bend = 0;
		ch_inf[i].rpn = 0;
		ch_inf[i].bend_range = 2;
		env_set(&ch_inf[i].env, 0.1, 0.2, 0.8, 1);
	}
	tempo = 500000;
	tempo_delta_sum = 0;
	tempo_sec = 0;

	div4 = header();

	if(!rd_str_chk(4, "MTrk")) ERR("track id");
	v = rd_int(4); /* skip */

	hi = low = 0;
	delta_sum = 0;
	while((v = rd_delta()) != EOF){
		delta_sum += v;
		sec = tempo_sec + (double)(delta_sum - tempo_delta_sum) / div4 * tempo * 0.000001;
		
		if((v = rd()) & 0x80){
			hi = (v >> 4) & 0xf;
			low  = v & 0xf;
		}else bk(v);

		data_out(&otr, sec);

		ch = low;
		switch(hi){
		case 8:
		case 9:
			note = rd();
			velo = rd();
			note_onoff(hi == 9, sec, ch, note, velo);
			break;
		case 0xb: /* control change */
			type = rd();
			v = rd();
			switch(type){
			case 7: /* channel volume msb */
				msb_set(&ch_inf[ch].vol, v);
				break;
			case 39: /* channel volume lsb */
				lsb_set(&ch_inf[ch].vol, v);
				break;
			case 10: /* pan msb */
				msb_set(&ch_inf[ch].pan, v);
				break;
			case 42: /* pan lsb */
				lsb_set(&ch_inf[ch].pan, v);
				break;
			case 100: /* rpn lsb */
				lsb_set(&ch_inf[ch].rpn, v);
				break;
			case 101: /* rpn msb */
				msb_set(&ch_inf[ch].rpn, v);
				break;
			case 6: /* data entry msb */
				switch(ch_inf[ch].rpn){
				case 0: /* pitch bend range */
					ch_inf[ch].bend_range = v;
					break;
				}
				break;
			}
			break;
		case 0xa:
			rd();
			rd();
			break;
		case 0xe: /* pitch wheel change */
			bend_note_update(ch, sec);
			v = rd();
			v |= rd() << 7;
			ch_inf[ch].bend = v - 8192;
			break;
		case 0xc:		
		case 0xd:
			rd();
			break;
		case 0xf:
			type = rd();
			switch(low){
			case 0:
				while(rd() != 0xf7);
				break;
			case 1:
			case 3:
				rd();
				break;
			case 2:
				rd();
				rd();
				break;
			case 0xf: /* meta */
				n = rd();
				switch(type){
				case 0x51: /* set tempo */
					v = rd_int(n);
					tempo = v;
					tempo_delta_sum = delta_sum;
					tempo_sec = sec;
					break;
				default:
					for(i=0; i<n; i++) rd();
					break;
				}
				break;
			default:
				break;
			}
			break;
		}
	}
	if(otr.fp != stdout) pclose(otr.fp);
	return 0;
}

/* EOF */


#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <math.h>

#define MSG(s) fprintf(stderr, "%s() %s L%d : %s\n", __func__, __FILE__, __LINE__, s)
#define ERR(s) do{ fprintf(stderr, "ERR "); MSG(s); exit(1); }while(0)

int bk_buf = -1;

int
rd(void)
{
	int v;

	if((v = bk_buf) < 0) return getchar();
	bk_buf = -1;
	return v;
}

void
bk(int v)
{
	if(bk_buf >= 0) ERR("give up");
	bk_buf = v;
}

void
rd_str(int n, char *s)
{
	int i;

	for(i=0; i<n; i++) s[i] = rd();
	s[i] = '\0';
}

int
rd_str_chk(int n, char *s)
{
	char buf[256];

	rd_str(n, buf);
	return strcmp(buf, s) == 0;
}

int
rd_int(int n) /* big endian */
{
	int i, v;

	v = 0;
	for(i=0; i<n; i++) v = (v << 8) | rd();
	return v;
}

int
rd_delta(void)
{
	int v, c;

	v = 0;
	do{
		if((c = rd()) == EOF) return EOF;
		v = (v << 7) | (c & 0x7f);
	}while(c & 0x80);
	return v;
}


#define NOTE_BUF_N	256

struct note_rec{
	int ch;
	int note;
	int onoff;
	double on_sec;
	double off_sec;
	int velo;
	double cycle, sec, freq;
	double off_v;
	// 鍵盤オフ時の振幅を記録する
	// エンベロープ処理で使用する
	
} note_buf[NOTE_BUF_N];

int
note_buf_is_free(int i)
{
	return note_buf[i].ch < 0;
}

void
note_buf_free(int i)
{
	note_buf[i].ch = -1;
}

void
note_buf_init(void)
{
	int i;

	for(i=0; i<NOTE_BUF_N; i++) note_buf_free(i);
}

int
note_buf_search(int ch, int note, int onoff)
{
	int i;

	for(i=0; i<NOTE_BUF_N; i++) {
		if( (ch < 0 && note_buf[i].ch < 0) ||
		    (note_buf[i].ch == ch &&
		     note_buf[i].note == note &&
		     note_buf[i].onoff == onoff) ) return i;
	}
	return -1;
}

int
header(void)
{
	int v;

	if(!rd_str_chk(4, "MThd")) ERR("header id");
	if(rd_int(4) != 6) ERR("header size");
	if(rd_int(2) != 0) ERR("header format type");
	if(rd_int(2) != 1) ERR("header track num");
	if((v = rd_int(2)) & 0x8000) ERR("header division");
	return v; /* div4 */
}

double
note_to_freq(int note)
{
	return 440 * pow(2, (note - 69) / 12.0);
}

int
opt_idx(char *key, int ac, char **av)
{
	int i;

	for(i=1; i<ac; i++) if(strcmp(av[i], key) == 0) return i;
	return -1;
}

char *
opt_str(char *key, int ac, char **av, char *def)
{
	int i;

	i = opt_idx(key, ac, av);
	if(i < 0 || i+1 >= ac) return def;
	return av[i+1];
}

int
opt_int(char *key, int ac, char **av, int def)
{
	char *s;

	if((s = opt_str(key, ac, av, NULL)) == NULL) return def;
	return strtol(s, NULL, 0);
}

struct out_rec{
	int smp_freq, smp_cnt;
	int bit_len;
	int sign;
	int ch_num;
	FILE *fp;

	int base;
	int amp;
	int iv_min;
	int iv_max;
};

void
out_init(struct out_rec *ot, int ac, char **av)
{
	char cmd[1024], *fn;

	ot->smp_freq = opt_int("-r", ac, av, 8000);
	ot->smp_cnt = 0;
	ot->bit_len = opt_int("-b", ac, av, 8);
	if(ot->bit_len != 8 && ot->bit_len != 16) ERR("bit_len");
	ot->sign = (opt_idx("-s", ac, av) >= 0);
	ot->ch_num = opt_int("-c", ac, av, 1);

	ot->fp = stdout;
	cmd[0] = '\0';
	fn = "";
	if(opt_idx("-play", ac, av) >= 0){
		strcat(cmd, "play");
	}else if(opt_idx("-sox", ac, av) >= 0){
		strcat(cmd, "sox");
		fn = opt_str("-sox", ac, av, "-d");
	}
	if(cmd[0]){
		sprintf(cmd + strlen(cmd), " -t raw -r %d -b %d %s -c %d - %s",
			ot->smp_freq, ot->bit_len,
			ot->sign ? "-s" : "-u",
			ot->ch_num, fn);
		if((ot->fp = popen(cmd, "w")) == NULL) ERR("popen");
	}
	ot->amp = ot->bit_len == 8 ? 127 : 32767;
	ot->base = ot->sign ? 0 : ot->amp + 1;
	ot->iv_min = ot->base - (ot->amp + 1);
	ot->iv_max = ot->base + ot->amp;
}

void
out_do(struct out_rec *ot, double v)
{
	int iv;

	iv = ot->base + (int)(v *ot->amp);
	if(iv > ot->iv_max) iv = ot->iv_max;
	if(iv < ot->iv_min) iv = ot->iv_min;
	switch(ot->bit_len){
	case 8:
		fputc(iv, ot->fp);
		break;
	case 16:
		fputc(iv & 0xff, ot->fp);
		fputc((iv >> 8) & 0xff, ot->fp);
		break;
	}
}

struct env_rec{
	double attack;	/* sec */
	double decay;	/* sec */
	double sustain;	/* 0..1 */
	double release;	/* sec */
};
// env_rec構造体の定義 (エンベロープ用)
//
// attack は、鍵盤オン時に、振幅 0.0 から1.0 まで立ち上がる秒数
// decay は、振幅 1.0 から sustain で設定したレベルまで減衰する秒数
// sustain は、attack + decacy秒後に、おちつく振幅のレベル
// 0.0 かr 1.0 の値で指定
// release は、鍵盤オフから、振幅が 0.0 に至るまでの秒数

void
env_set(struct env_rec *e, double a, double d, double s, double r)
{
	e->attack = a;
	e->decay = d;
	e->sustain = s;
	e->release = r;
}
// env_rec構造体に値を設定する

#define MIDI_CH_N	16
struct ch_rec{
	int vol;
	int pan;
	int bend;
	int rpn;
	int bend_range;
	struct env_rec env;
	// エンベロープ用に、env_rec構造体を追加
	
} ch_inf[ MIDI_CH_N ];

double
env_out(struct note_rec *nt)
{
	// エンベロープ出力 (振幅) を返す
	// 
	// nt は 鍵盤情報の構造体
	// 参照するメンバは次の通り
	//   メンバ ch      : MIDIチャンネル --> ch_inf[] 経由で
	//                    env_rec構造体を取得する
	//   メンバ onoff   : 鍵盤の状態 (1 : オン 0: オフ)
	//   メンバ on_sec  : 鍵盤オンの時刻
	//   メンバ off_sec : 鍵盤オフの時刻
	//   メンバ off_v   : 鍵盤オフ時の振幅
	
	struct env_rec *e;
	double sec, v;

	sec = nt->sec;
	e = &ch_inf[nt->ch].env;
	if(nt->onoff){
		sec -= nt->on_sec;
		if(sec < e->attack){
			v = sec / e->attack;
			return log10(1 + v * 9);
		}
		sec -= e->attack;
		if(sec < e->decay){
			v = sec / e->decay;
			v = log10(1 + v * 9);
			return 1 - v * (1 - e->sustain);
		}
		return e->sustain;
	}
	sec -= nt->off_sec;
	if(sec < e->release){
		v = sec / e->release;
		v = log10(1 + v * 9);
		return (1 - v) * nt->off_v;
	}
	return 0;
}

void
data_out(struct out_rec *ot, double evt_sec)
{
	// 変数 release と、リリース用の処理を削除
	// 代わりにエンベロープ用の処理を追加
	
	double v, sec, freq, dsec;
	double vl, vr, pan;
	int i, nch;
	struct note_rec *nt;

	while((sec = (double)ot->smp_cnt / ot->smp_freq) < evt_sec){
		vl = vr = 0;
		for(i=0; i<NOTE_BUF_N; i++){
			if(note_buf_is_free(i)) continue;
			nt = &note_buf[i];
			nch = nt->ch;
			freq = note_to_freq(nt->note);
			if(ch_inf[nch].bend != 0) freq *= pow(2, ch_inf[nch].bend / 8192.0 * ch_inf[nch].bend_range / 12);
			dsec = sec - nt->on_sec;
			if(dsec > 0.3) freq *= pow(2, sin(2 * M_PI * 6 * dsec) / (12 * 4) );
			nt->cycle += freq * (sec - nt->sec);
			nt->sec = sec;
			nt->freq = freq;
			v = sin(2 * M_PI * nt->cycle);
			v *= env_out(&note_buf[i]);
			// エンベロープ用の処理を追加
			
			v *= nt->velo / 127.0;
			v *= ch_inf[nch].vol / (double)((1<<14)-1);
			if(ot->ch_num == 1){
				vl += v;
			}else{
				pan = ch_inf[nch].pan / (double)(1<<14);
				vl += (1 - pan) * v;
				vr += pan * v;
			}
			if(nt->onoff == 0 && sec - nt->off_sec >= ch_inf[nch].env.release) note_buf_free(i);
			// 鍵盤オフ後、リリース時間を判定し、
			// 鍵盤情報のバッファを解放
			
		}
		out_do(ot, vl / 16);
		if(ot->ch_num > 1) out_do(ot, vr / 16);
		ot->smp_cnt++;
	}
}

void
note_onoff(int onoff, double evt_sec, int ch, int note, int velo)
{
	int i;

	if(ch == 9) return;

	if(onoff){
		if((i = note_buf_search(-1, -1, -1)) < 0){
			MSG("note_buf full");
			return;
		}
		note_buf[i].note = note;
		note_buf[i].ch = ch;
		note_buf[i].onoff = 1;
		note_buf[i].on_sec = evt_sec;
		note_buf[i].velo = velo;
		note_buf[i].cycle = 0;
		note_buf[i].sec = evt_sec;
	}else{
		if((i = note_buf_search(ch, note, 1)) < 0) return;
		note_buf[i].off_v = env_out(&note_buf[i]);
		// 鍵盤オンの設定のままで、今の振幅を取得して
		// 鍵盤オフ時の振幅として記録
		
		note_buf[i].onoff = 0;
		// 鍵盤オフの状態に設定を変更
		
		note_buf[i].off_sec = evt_sec;
		// 鍵盤オフ時の時刻を記録
		
	}
}

void
msb_set(int *vp, int v)
{
	*vp &= ~(127<<7);
	*vp |= v<<7;
}

void
lsb_set(int *vp, int v)
{
	*vp &= ~127;
	*vp |= v;
}

void
bend_note_update(int ch, double sec)
{
	int i;
	struct note_rec *nt;

	for(i=0; ich != ch) continue;
		nt->cycle += nt->freq * (sec - nt->sec);
		nt->sec = sec;
	}
}

int
main(int ac, char **av)
{
	int div4, delta_sum;
	int i, n, v, hi, low, note, velo;
	int ch, type;
	double sec;
	struct out_rec otr;
	int tempo, tempo_delta_sum;
	double tempo_sec;

	out_init(&otr, ac, av);
	note_buf_init();
	for(i=0; i<MIDI_CH_N; i++){
		ch_inf[i].vol = 0;
		ch_inf[i].pan = 1<<(14-1);
		ch_inf[i].bend = 0;
		ch_inf[i].rpn = 0;
		ch_inf[i].bend_range = 2;
		env_set(&ch_inf[i].env, 0.1, 0.2, 0.8, 1);
		// エンベロープ用の env_rec構造体への設定を追加
		// とりあえず、全チャンネル同じ設定に
		
	}
	tempo = 500000;
	tempo_delta_sum = 0;
	tempo_sec = 0;

	div4 = header();

	if(!rd_str_chk(4, "MTrk")) ERR("track id");
	v = rd_int(4); /* skip */

	hi = low = 0;
	delta_sum = 0;
	while((v = rd_delta()) != EOF){
		delta_sum += v;
		sec = tempo_sec + (double)(delta_sum - tempo_delta_sum) / div4 * tempo * 0.000001;
		
		if((v = rd()) & 0x80){
			hi = (v >> 4) & 0xf;
			low  = v & 0xf;
		}else bk(v);

		data_out(&otr, sec);

		ch = low;
		switch(hi){
		case 8:
		case 9:
			note = rd();
			velo = rd();
			note_onoff(hi == 9, sec, ch, note, velo);
			break;
		case 0xb: /* control change */
			type = rd();
			v = rd();
			switch(type){
			case 7: /* channel volume msb */
				msb_set(&ch_inf[ch].vol, v);
				break;
			case 39: /* channel volume lsb */
				lsb_set(&ch_inf[ch].vol, v);
				break;
			case 10: /* pan msb */
				msb_set(&ch_inf[ch].pan, v);
				break;
			case 42: /* pan lsb */
				lsb_set(&ch_inf[ch].pan, v);
				break;
			case 100: /* rpn lsb */
				lsb_set(&ch_inf[ch].rpn, v);
				break;
			case 101: /* rpn msb */
				msb_set(&ch_inf[ch].rpn, v);
				break;
			case 6: /* data entry msb */
				switch(ch_inf[ch].rpn){
				case 0: /* pitch bend range */
					ch_inf[ch].bend_range = v;
					break;
				}
				break;
			}
			break;
		case 0xa:
			rd();
			rd();
			break;
		case 0xe: /* pitch wheel change */
			bend_note_update(ch, sec);
			v = rd();
			v |= rd() << 7;
			ch_inf[ch].bend = v - 8192;
			break;
		case 0xc:		
		case 0xd:
			rd();
			break;
		case 0xf:
			type = rd();
			switch(low){
			case 0:
				while(rd() != 0xf7);
				break;
			case 1:
			case 3:
				rd();
				break;
			case 2:
				rd();
				rd();
				break;
			case 0xf: /* meta */
				n = rd();
				switch(type){
				case 0x51: /* set tempo */
					v = rd_int(n);
					tempo = v;
					tempo_delta_sum = delta_sum;
					tempo_sec = sec;
					break;
				default:
					for(i=0; i<n; i++) rd();
					break;
				}
				break;
			default:
				break;
			}
			break;
		}
	}
	if(otr.fp != stdout) pclose(otr.fp);
	return 0;
}

/* EOF */


prog9.c 解説

prog8.c からの変更箇所のみ

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <math.h>

#define MSG(s) fprintf(stderr, "%s() %s L%d : %s\n", __func__, __FILE__, __LINE__, s)
#define ERR(s) do{ fprintf(stderr, "ERR "); MSG(s); exit(1); }while(0)

int bk_buf = -1;

int
rd(void)
{
	int v;

	if((v = bk_buf) < 0) return getchar();
	bk_buf = -1;
	return v;
}

void
bk(int v)
{
	if(bk_buf >= 0) ERR("give up");
	bk_buf = v;
}

void
rd_str(int n, char *s)
{
	int i;

	for(i=0; i<n; i++) s[i] = rd();
	s[i] = '\0';
}

int
rd_str_chk(int n, char *s)
{
	char buf[256];

	rd_str(n, buf);
	return strcmp(buf, s) == 0;
}

int
rd_int(int n) /* big endian */
{
	int i, v;

	v = 0;
	for(i=0; i<n; i++) v = (v << 8) | rd();
	return v;
}

int
rd_delta(void)
{
	int v, c;

	v = 0;
	do{
		if((c = rd()) == EOF) return EOF;
		v = (v << 7) | (c & 0x7f);
	}while(c & 0x80);
	return v;
}


#define NOTE_BUF_N	256

struct note_rec{
	int ch;
	int note;
	int onoff;
	double on_sec;
	double off_sec;
	int velo;
	double cycle, sec, freq;
	double off_v;
} note_buf[NOTE_BUF_N];

int
note_buf_is_free(int i)
{
	return note_buf[i].ch < 0;
}

void
note_buf_free(int i)
{
	note_buf[i].ch = -1;
}

void
note_buf_init(void)
{
	int i;

	for(i=0; i<NOTE_BUF_N; i++) note_buf_free(i);
}

int
note_buf_search(int ch, int note, int onoff)
{
	int i;

	for(i=0; i<NOTE_BUF_N; i++) {
		if( (ch < 0 && note_buf[i].ch < 0) ||
		    (note_buf[i].ch == ch &&
		     note_buf[i].note == note &&
		     note_buf[i].onoff == onoff) ) return i;
	}
	return -1;
}

int
header(void)
{
	int v;

	if(!rd_str_chk(4, "MThd")) ERR("header id");
	if(rd_int(4) != 6) ERR("header size");
	if(rd_int(2) != 0) ERR("header format type");
	if(rd_int(2) != 1) ERR("header track num");
	if((v = rd_int(2)) & 0x8000) ERR("header division");
	return v; /* div4 */
}

double
note_to_freq(int note)
{
	return 440 * pow(2, (note - 69) / 12.0);
}

int
opt_idx(char *key, int ac, char **av)
{
	int i;

	for(i=1; i<ac; i++) if(strcmp(av[i], key) == 0) return i;
	return -1;
}

char *
opt_str(char *key, int ac, char **av, char *def)
{
	int i;

	i = opt_idx(key, ac, av);
	if(i < 0 || i+1 >= ac) return def;
	return av[i+1];
}

int
opt_int(char *key, int ac, char **av, int def)
{
	char *s;

	if((s = opt_str(key, ac, av, NULL)) == NULL) return def;
	return strtol(s, NULL, 0);
}

struct out_rec{
	int smp_freq, smp_cnt;
	int bit_len;
	int sign;
	int ch_num;
	FILE *fp;

	int base;
	int amp;
	int iv_min;
	int iv_max;
};

void
out_init(struct out_rec *ot, int ac, char **av)
{
	char cmd[1024], *fn;

	ot->smp_freq = opt_int("-r", ac, av, 8000);
	ot->smp_cnt = 0;
	ot->bit_len = opt_int("-b", ac, av, 8);
	if(ot->bit_len != 8 && ot->bit_len != 16) ERR("bit_len");
	ot->sign = (opt_idx("-s", ac, av) >= 0);
	ot->ch_num = opt_int("-c", ac, av, 1);

	ot->fp = stdout;
	cmd[0] = '\0';
	fn = "";
	if(opt_idx("-play", ac, av) >= 0){
		strcat(cmd, "play");
	}else if(opt_idx("-sox", ac, av) >= 0){
		strcat(cmd, "sox");
		fn = opt_str("-sox", ac, av, "-d");
	}
	if(cmd[0]){
		sprintf(cmd + strlen(cmd), " -t raw -r %d -b %d %s -c %d - %s",
			ot->smp_freq, ot->bit_len,
			ot->sign ? "-s" : "-u",
			ot->ch_num, fn);
		if((ot->fp = popen(cmd, "w")) == NULL) ERR("popen");
	}
	ot->amp = ot->bit_len == 8 ? 127 : 32767;
	ot->base = ot->sign ? 0 : ot->amp + 1;
	ot->iv_min = ot->base - (ot->amp + 1);
	ot->iv_max = ot->base + ot->amp;
}

void
out_do(struct out_rec *ot, double v)
{
	int iv;

	iv = ot->base + (int)(v *ot->amp);
	if(iv > ot->iv_max) iv = ot->iv_max;
	if(iv < ot->iv_min) iv = ot->iv_min;
	switch(ot->bit_len){
	case 8:
		fputc(iv, ot->fp);
		break;
	case 16:
		fputc(iv & 0xff, ot->fp);
		fputc((iv >> 8) & 0xff, ot->fp);
		break;
	}
}

struct env_rec{
	double attack;	/* sec */
	double decay;	/* sec */
	double sustain;	/* 0..1 */
	double release;	/* sec */
};

void
env_set(struct env_rec *e, double a, double d, double s, double r)
{
	e->attack = a;
	e->decay = d;
	e->sustain = s;
	e->release = r;
}

struct tone_rec{
	struct env_rec env;
} tone_inf[] = {
	{
		{ 0.15, 0.5, 0.8, 0.5 }
	},{
		{ 0.05, 0.2, 0.4, 0.2 }
	},{
		{ 0.01, 0.2, 0.8, 0.3 }
	},{
		{ 0, 0.3, 0.2, 0.3 }
	}
};

struct tone_rec *
tone_get(int prog)
{
	switch(prog){
	case 48: /* timpani */
	case 50: /* strings ensamble 2 */
		return &tone_inf[0];

	case 35: /* electric bass (pick) */
		return &tone_inf[1];

	case 79: /* whistle */
	case 81: /* lead 1 (square) */
	case 87: /* lead 7 (fifths) */
		return &tone_inf[2];

	case 24: /* tango accordion */
	case 67: /* tenor sax */
	default:
		break;
	}
	return &tone_inf[3];
}

#define MIDI_CH_N	16
struct ch_rec{
	int vol;
	int pan;
	int bend;
	int rpn;
	int bend_range;
	int prog;
} ch_inf[ MIDI_CH_N ];

#define CH_ENV(ch)	tone_get(ch_inf[ch].prog)->env

double
env_out(struct note_rec *nt)
{
	struct env_rec *e;
	double sec, v;

	sec = nt->sec;
	e = &CH_ENV(nt->ch);
	if(nt->onoff){
		sec -= nt->on_sec;
		if(sec < e->attack){
			v = sec / e->attack;
			return log10(1 + v * 9);
		}
		sec -= e->attack;
		if(sec < e->decay){
			v = sec / e->decay;
			v = log10(1 + v * 9);
			return 1 - v * (1 - e->sustain);
		}
		return e->sustain;
	}
	sec -= nt->off_sec;
	if(sec < e->release){
		v = sec / e->release;
		v = log10(1 + v * 9);
		return (1 - v) * nt->off_v;
	}
	return 0;
}

void
data_out(struct out_rec *ot, double evt_sec)
{
	double v, sec, freq, dsec;
	double vl, vr, pan;
	int i, nch;
	struct note_rec *nt;

	while((sec = (double)ot->smp_cnt / ot->smp_freq) < evt_sec){
		vl = vr = 0;
		for(i=0; i<NOTE_BUF_N; i++){
			if(note_buf_is_free(i)) continue;
			nt = &note_buf[i];
			nch = nt->ch;
			freq = note_to_freq(nt->note);
			if(ch_inf[nch].bend != 0) freq *= pow(2, ch_inf[nch].bend / 8192.0 * ch_inf[nch].bend_range / 12);
			dsec = sec - nt->on_sec;
			if(dsec > 0.3) freq *= pow(2, sin(2 * M_PI * 6 * dsec) / (12 * 4) );
			nt->cycle += freq * (sec - nt->sec);
			nt->sec = sec;
			nt->freq = freq;
			v = sin(2 * M_PI * nt->cycle);
			v *= env_out(&note_buf[i]);
			v *= nt->velo / 127.0;
			v *= ch_inf[nch].vol / (double)((1<<14)-1);
			if(ot->ch_num == 1){
				vl += v;
			}else{
				pan = ch_inf[nch].pan / (double)(1<<14);
				vl += (1 - pan) * v;
				vr += pan * v;
			}
			if(nt->onoff == 0 && sec - nt->off_sec >= CH_ENV(nch).release) note_buf_free(i);
		}
		out_do(ot, vl / 16);
		if(ot->ch_num > 1) out_do(ot, vr / 16);
		ot->smp_cnt++;
	}
}

void
note_onoff(int onoff, double evt_sec, int ch, int note, int velo)
{
	int i;

	if(ch == 9) return;

	if(onoff){
		if((i = note_buf_search(-1, -1, -1)) < 0){
			MSG("note_buf full");
			return;
		}
		note_buf[i].note = note;
		note_buf[i].ch = ch;
		note_buf[i].onoff = 1;
		note_buf[i].on_sec = evt_sec;
		note_buf[i].velo = velo;
		note_buf[i].cycle = 0;
		note_buf[i].sec = evt_sec;
	}else{
		if((i = note_buf_search(ch, note, 1)) < 0) return;
		note_buf[i].off_v = env_out(&note_buf[i]);
		note_buf[i].onoff = 0;
		note_buf[i].off_sec = evt_sec;
	}
}

void
msb_set(int *vp, int v)
{
	*vp &= ~(127<<7);
	*vp |= v<<7;
}

void
lsb_set(int *vp, int v)
{
	*vp &= ~127;
	*vp |= v;
}

void
bend_note_update(int ch, double sec)
{
	int i;
	struct note_rec *nt;

	for(i=0; ich != ch) continue;
		nt->cycle += nt->freq * (sec - nt->sec);
		nt->sec = sec;
	}
}

int
main(int ac, char **av)
{
	int div4, delta_sum;
	int i, n, v, hi, low, note, velo;
	int ch, type;
	double sec;
	struct out_rec otr;
	int tempo, tempo_delta_sum;
	double tempo_sec;

	out_init(&otr, ac, av);
	note_buf_init();
	for(i=0; i<MIDI_CH_N; i++){
		ch_inf[i].vol = 0;
		ch_inf[i].pan = 1<<(14-1);
		ch_inf[i].bend = 0;
		ch_inf[i].rpn = 0;
		ch_inf[i].bend_range = 2;
		ch_inf[i].prog =-1;
	}
	tempo = 500000;
	tempo_delta_sum = 0;
	tempo_sec = 0;

	div4 = header();

	if(!rd_str_chk(4, "MTrk")) ERR("track id");
	v = rd_int(4); /* skip */

	hi = low = 0;
	delta_sum = 0;
	while((v = rd_delta()) != EOF){
		delta_sum += v;
		sec = tempo_sec + (double)(delta_sum - tempo_delta_sum) / div4 * tempo * 0.000001;
		
		if((v = rd()) & 0x80){
			hi = (v >> 4) & 0xf;
			low  = v & 0xf;
		}else bk(v);

		data_out(&otr, sec);

		ch = low;
		switch(hi){
		case 8:
		case 9:
			note = rd();
			velo = rd();
			note_onoff(hi == 9, sec, ch, note, velo);
			break;
		case 0xb: /* control change */
			type = rd();
			v = rd();
			switch(type){
			case 7: /* channel volume msb */
				msb_set(&ch_inf[ch].vol, v);
				break;
			case 39: /* channel volume lsb */
				lsb_set(&ch_inf[ch].vol, v);
				break;
			case 10: /* pan msb */
				msb_set(&ch_inf[ch].pan, v);
				break;
			case 42: /* pan lsb */
				lsb_set(&ch_inf[ch].pan, v);
				break;
			case 100: /* rpn lsb */
				lsb_set(&ch_inf[ch].rpn, v);
				break;
			case 101: /* rpn msb */
				msb_set(&ch_inf[ch].rpn, v);
				break;
			case 6: /* data entry msb */
				switch(ch_inf[ch].rpn){
				case 0: /* pitch bend range */
					ch_inf[ch].bend_range = v;
					break;
				}
				break;
			}
			break;
		case 0xa:
			rd();
			rd();
			break;
		case 0xe: /* pitch wheel change */
			bend_note_update(ch, sec);
			v = rd();
			v |= rd() << 7;
			ch_inf[ch].bend = v - 8192;
			break;
		case 0xc: /* program number */
			v = rd();
			ch_inf[ch].prog = v;
			break;
		case 0xd:
			rd();
			break;
		case 0xf:
			type = rd();
			switch(low){
			case 0:
				while(rd() != 0xf7);
				break;
			case 1:
			case 3:
				rd();
				break;
			case 2:
				rd();
				rd();
				break;
			case 0xf: /* meta */
				n = rd();
				switch(type){
				case 0x51: /* set tempo */
					v = rd_int(n);
					tempo = v;
					tempo_delta_sum = delta_sum;
					tempo_sec = sec;
					break;
				default:
					for(i=0; i<n; i++) rd();
					break;
				}
				break;
			default:
				break;
			}
			break;
		}
	}
	if(otr.fp != stdout) pclose(otr.fp);
	return 0;
}

/* EOF */


#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <math.h>

#define MSG(s) fprintf(stderr, "%s() %s L%d : %s\n", __func__, __FILE__, __LINE__, s)
#define ERR(s) do{ fprintf(stderr, "ERR "); MSG(s); exit(1); }while(0)

int bk_buf = -1;

int
rd(void)
{
	int v;

	if((v = bk_buf) < 0) return getchar();
	bk_buf = -1;
	return v;
}

void
bk(int v)
{
	if(bk_buf >= 0) ERR("give up");
	bk_buf = v;
}

void
rd_str(int n, char *s)
{
	int i;

	for(i=0; i<n; i++) s[i] = rd();
	s[i] = '\0';
}

int
rd_str_chk(int n, char *s)
{
	char buf[256];

	rd_str(n, buf);
	return strcmp(buf, s) == 0;
}

int
rd_int(int n) /* big endian */
{
	int i, v;

	v = 0;
	for(i=0; i<n; i++) v = (v << 8) | rd();
	return v;
}

int
rd_delta(void)
{
	int v, c;

	v = 0;
	do{
		if((c = rd()) == EOF) return EOF;
		v = (v << 7) | (c & 0x7f);
	}while(c & 0x80);
	return v;
}


#define NOTE_BUF_N	256

struct note_rec{
	int ch;
	int note;
	int onoff;
	double on_sec;
	double off_sec;
	int velo;
	double cycle, sec, freq;
	double off_v;
} note_buf[NOTE_BUF_N];

int
note_buf_is_free(int i)
{
	return note_buf[i].ch < 0;
}

void
note_buf_free(int i)
{
	note_buf[i].ch = -1;
}

void
note_buf_init(void)
{
	int i;

	for(i=0; i<NOTE_BUF_N; i++) note_buf_free(i);
}

int
note_buf_search(int ch, int note, int onoff)
{
	int i;

	for(i=0; i<NOTE_BUF_N; i++) {
		if( (ch < 0 && note_buf[i].ch < 0) ||
		    (note_buf[i].ch == ch &&
		     note_buf[i].note == note &&
		     note_buf[i].onoff == onoff) ) return i;
	}
	return -1;
}

int
header(void)
{
	int v;

	if(!rd_str_chk(4, "MThd")) ERR("header id");
	if(rd_int(4) != 6) ERR("header size");
	if(rd_int(2) != 0) ERR("header format type");
	if(rd_int(2) != 1) ERR("header track num");
	if((v = rd_int(2)) & 0x8000) ERR("header division");
	return v; /* div4 */
}

double
note_to_freq(int note)
{
	return 440 * pow(2, (note - 69) / 12.0);
}

int
opt_idx(char *key, int ac, char **av)
{
	int i;

	for(i=1; i<ac; i++) if(strcmp(av[i], key) == 0) return i;
	return -1;
}

char *
opt_str(char *key, int ac, char **av, char *def)
{
	int i;

	i = opt_idx(key, ac, av);
	if(i < 0 || i+1 >= ac) return def;
	return av[i+1];
}

int
opt_int(char *key, int ac, char **av, int def)
{
	char *s;

	if((s = opt_str(key, ac, av, NULL)) == NULL) return def;
	return strtol(s, NULL, 0);
}

struct out_rec{
	int smp_freq, smp_cnt;
	int bit_len;
	int sign;
	int ch_num;
	FILE *fp;

	int base;
	int amp;
	int iv_min;
	int iv_max;
};

void
out_init(struct out_rec *ot, int ac, char **av)
{
	char cmd[1024], *fn;

	ot->smp_freq = opt_int("-r", ac, av, 8000);
	ot->smp_cnt = 0;
	ot->bit_len = opt_int("-b", ac, av, 8);
	if(ot->bit_len != 8 && ot->bit_len != 16) ERR("bit_len");
	ot->sign = (opt_idx("-s", ac, av) >= 0);
	ot->ch_num = opt_int("-c", ac, av, 1);

	ot->fp = stdout;
	cmd[0] = '\0';
	fn = "";
	if(opt_idx("-play", ac, av) >= 0){
		strcat(cmd, "play");
	}else if(opt_idx("-sox", ac, av) >= 0){
		strcat(cmd, "sox");
		fn = opt_str("-sox", ac, av, "-d");
	}
	if(cmd[0]){
		sprintf(cmd + strlen(cmd), " -t raw -r %d -b %d %s -c %d - %s",
			ot->smp_freq, ot->bit_len,
			ot->sign ? "-s" : "-u",
			ot->ch_num, fn);
		if((ot->fp = popen(cmd, "w")) == NULL) ERR("popen");
	}
	ot->amp = ot->bit_len == 8 ? 127 : 32767;
	ot->base = ot->sign ? 0 : ot->amp + 1;
	ot->iv_min = ot->base - (ot->amp + 1);
	ot->iv_max = ot->base + ot->amp;
}

void
out_do(struct out_rec *ot, double v)
{
	int iv;

	iv = ot->base + (int)(v *ot->amp);
	if(iv > ot->iv_max) iv = ot->iv_max;
	if(iv < ot->iv_min) iv = ot->iv_min;
	switch(ot->bit_len){
	case 8:
		fputc(iv, ot->fp);
		break;
	case 16:
		fputc(iv & 0xff, ot->fp);
		fputc((iv >> 8) & 0xff, ot->fp);
		break;
	}
}

struct env_rec{
	double attack;	/* sec */
	double decay;	/* sec */
	double sustain;	/* 0..1 */
	double release;	/* sec */
};

void
env_set(struct env_rec *e, double a, double d, double s, double r)
{
	e->attack = a;
	e->decay = d;
	e->sustain = s;
	e->release = r;
}

struct tone_rec{
	struct env_rec env;
} tone_inf[] = {
	{
		{ 0.15, 0.5, 0.8, 0.5 }
	},{
		{ 0.05, 0.2, 0.4, 0.2 }
	},{
		{ 0.01, 0.2, 0.8, 0.3 }
	},{
		{ 0, 0.3, 0.2, 0.3 }
	}
};
// 音色の構造体を定義
// 今は、エンベロープの情報だけ

struct tone_rec *
tone_get(int prog)
{
	// プログラム番号から
	// 音色の構造体を取得する
	
	switch(prog){
	case 48: /* timpani */
	case 50: /* strings ensamble 2 */
		return &tone_inf[0];

	case 35: /* electric bass (pick) */
		return &tone_inf[1];

	case 79: /* whistle */
	case 81: /* lead 1 (square) */
	case 87: /* lead 7 (fifths) */
		return &tone_inf[2];

	case 24: /* tango accordion */
	case 67: /* tenor sax */
	default:
		break;
	}
	return &tone_inf[3];
}

#define MIDI_CH_N	16
struct ch_rec{
	int vol;
	int pan;
	int bend;
	int rpn;
	int bend_range;
	int prog;
	// エンベロープの情報を削除し、
	// プログラム番号を追加
	
} ch_inf[ MIDI_CH_N ];

#define CH_ENV(ch)	tone_get(ch_inf[ch].prog)->env
// 指定チャンネルのエンベロープ情報を取り出すマクロ定義を追加

double
env_out(struct note_rec *nt)
{
	struct env_rec *e;
	double sec, v;

	sec = nt->sec;
	e = &CH_ENV(nt->ch);
	// 追加したマクロを使い、チャンネルから
	// エンベロープ情報を取得するように変更
	
	if(nt->onoff){
		sec -= nt->on_sec;
		if(sec < e->attack){
			v = sec / e->attack;
			return log10(1 + v * 9);
		}
		sec -= e->attack;
		if(sec < e->decay){
			v = sec / e->decay;
			v = log10(1 + v * 9);
			return 1 - v * (1 - e->sustain);
		}
		return e->sustain;
	}
	sec -= nt->off_sec;
	if(sec < e->release){
		v = sec / e->release;
		v = log10(1 + v * 9);
		return (1 - v) * nt->off_v;
	}
	return 0;
}

void
data_out(struct out_rec *ot, double evt_sec)
{
	double v, sec, freq, dsec;
	double vl, vr, pan;
	int i, nch;
	struct note_rec *nt;

	while((sec = (double)ot->smp_cnt / ot->smp_freq) < evt_sec){
		vl = vr = 0;
		for(i=0; i<NOTE_BUF_N; i++){
			if(note_buf_is_free(i)) continue;
			nt = &note_buf[i];
			nch = nt->ch;
			freq = note_to_freq(nt->note);
			if(ch_inf[nch].bend != 0) freq *= pow(2, ch_inf[nch].bend / 8192.0 * ch_inf[nch].bend_range / 12);
			dsec = sec - nt->on_sec;
			if(dsec > 0.3) freq *= pow(2, sin(2 * M_PI * 6 * dsec) / (12 * 4) );
			nt->cycle += freq * (sec - nt->sec);
			nt->sec = sec;
			nt->freq = freq;
			v = sin(2 * M_PI * nt->cycle);
			v *= env_out(&note_buf[i]);
			v *= nt->velo / 127.0;
			v *= ch_inf[nch].vol / (double)((1<<14)-1);
			if(ot->ch_num == 1){
				vl += v;
			}else{
				pan = ch_inf[nch].pan / (double)(1<<14);
				vl += (1 - pan) * v;
				vr += pan * v;
			}
			if(nt->onoff == 0 && sec - nt->off_sec >= CH_ENV(nch).release) note_buf_free(i);
			// 追加したマクロを使い、チャンネルから
			// エンベロープ情報を取得するように変更
			
		}
		out_do(ot, vl / 16);
		if(ot->ch_num > 1) out_do(ot, vr / 16);
		ot->smp_cnt++;
	}
}

void
note_onoff(int onoff, double evt_sec, int ch, int note, int velo)
{
	int i;

	if(ch == 9) return;

	if(onoff){
		if((i = note_buf_search(-1, -1, -1)) < 0){
			MSG("note_buf full");
			return;
		}
		note_buf[i].note = note;
		note_buf[i].ch = ch;
		note_buf[i].onoff = 1;
		note_buf[i].on_sec = evt_sec;
		note_buf[i].velo = velo;
		note_buf[i].cycle = 0;
		note_buf[i].sec = evt_sec;
	}else{
		if((i = note_buf_search(ch, note, 1)) < 0) return;
		note_buf[i].off_v = env_out(&note_buf[i]);
		note_buf[i].onoff = 0;
		note_buf[i].off_sec = evt_sec;
	}
}

void
msb_set(int *vp, int v)
{
	*vp &= ~(127<<7);
	*vp |= v<<7;
}

void
lsb_set(int *vp, int v)
{
	*vp &= ~127;
	*vp |= v;
}

void
bend_note_update(int ch, double sec)
{
	int i;
	struct note_rec *nt;

	for(i=0; ich != ch) continue;
		nt->cycle += nt->freq * (sec - nt->sec);
		nt->sec = sec;
	}
}

int
main(int ac, char **av)
{
	int div4, delta_sum;
	int i, n, v, hi, low, note, velo;
	int ch, type;
	double sec;
	struct out_rec otr;
	int tempo, tempo_delta_sum;
	double tempo_sec;

	out_init(&otr, ac, av);
	note_buf_init();
	for(i=0; i<MIDI_CH_N; i++){
		ch_inf[i].vol = 0;
		ch_inf[i].pan = 1<<(14-1);
		ch_inf[i].bend = 0;
		ch_inf[i].rpn = 0;
		ch_inf[i].bend_range = 2;
		ch_inf[i].prog =-1;
		// エンベロープ情報の設定を削除
		// プログラム番号を -1 で初期化
		//
		// イベントで上書きされず -1 のままの場合、
		// tone_get() 関数の switch文で
		// default の 音色の構造体が返る事になる	
		
	}
	tempo = 500000;
	tempo_delta_sum = 0;
	tempo_sec = 0;

	div4 = header();

	if(!rd_str_chk(4, "MTrk")) ERR("track id");
	v = rd_int(4); /* skip */

	hi = low = 0;
	delta_sum = 0;
	while((v = rd_delta()) != EOF){
		delta_sum += v;
		sec = tempo_sec + (double)(delta_sum - tempo_delta_sum) / div4 * tempo * 0.000001;
		
		if((v = rd()) & 0x80){
			hi = (v >> 4) & 0xf;
			low  = v & 0xf;
		}else bk(v);

		data_out(&otr, sec);

		ch = low;
		switch(hi){
		case 8:
		case 9:
			note = rd();
			velo = rd();
			note_onoff(hi == 9, sec, ch, note, velo);
			break;
		case 0xb: /* control change */
			type = rd();
			v = rd();
			switch(type){
			case 7: /* channel volume msb */
				msb_set(&ch_inf[ch].vol, v);
				break;
			case 39: /* channel volume lsb */
				lsb_set(&ch_inf[ch].vol, v);
				break;
			case 10: /* pan msb */
				msb_set(&ch_inf[ch].pan, v);
				break;
			case 42: /* pan lsb */
				lsb_set(&ch_inf[ch].pan, v);
				break;
			case 100: /* rpn lsb */
				lsb_set(&ch_inf[ch].rpn, v);
				break;
			case 101: /* rpn msb */
				msb_set(&ch_inf[ch].rpn, v);
				break;
			case 6: /* data entry msb */
				switch(ch_inf[ch].rpn){
				case 0: /* pitch bend range */
					ch_inf[ch].bend_range = v;
					break;
				}
				break;
			}
			break;
		case 0xa:
			rd();
			rd();
			break;
		case 0xe: /* pitch wheel change */
			bend_note_update(ch, sec);
			v = rd();
			v |= rd() << 7;
			ch_inf[ch].bend = v - 8192;
			break;
		case 0xc: /* program number */
		// 1バイト目の上位4ビットが 0xc の場合
		
			v = rd();
			ch_inf[ch].prog = v;
			// イベントの2バイト目のプログラム番号を読み込み
			// チャンネル情報の構造体に設定
			
			break;
		case 0xd:
			rd();
			break;
		case 0xf:
			type = rd();
			switch(low){
			case 0:
				while(rd() != 0xf7);
				break;
			case 1:
			case 3:
				rd();
				break;
			case 2:
				rd();
				rd();
				break;
			case 0xf: /* meta */
				n = rd();
				switch(type){
				case 0x51: /* set tempo */
					v = rd_int(n);
					tempo = v;
					tempo_delta_sum = delta_sum;
					tempo_sec = sec;
					break;
				default:
					for(i=0; i<n; i++) rd();
					break;
				}
				break;
			default:
				break;
			}
			break;
		}
	}
	if(otr.fp != stdout) pclose(otr.fp);
	return 0;
}

/* EOF */


prog10.c 解説

prog9.c からの変更箇所のみ

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <math.h>

#define MSG(s) fprintf(stderr, "%s() %s L%d : %s\n", __func__, __FILE__, __LINE__, s)
#define ERR(s) do{ fprintf(stderr, "ERR "); MSG(s); exit(1); }while(0)

int bk_buf = -1;

int
rd(void)
{
	int v;

	if((v = bk_buf) < 0) return getchar();
	bk_buf = -1;
	return v;
}

void
bk(int v)
{
	if(bk_buf >= 0) ERR("give up");
	bk_buf = v;
}

void
rd_str(int n, char *s)
{
	int i;

	for(i=0; i<n; i++) s[i] = rd();
	s[i] = '\0';
}

int
rd_str_chk(int n, char *s)
{
	char buf[256];

	rd_str(n, buf);
	return strcmp(buf, s) == 0;
}

int
rd_int(int n) /* big endian */
{
	int i, v;

	v = 0;
	for(i=0; i<n; i++) v = (v << 8) | rd();
	return v;
}

int
rd_delta(void)
{
	int v, c;

	v = 0;
	do{
		if((c = rd()) == EOF) return EOF;
		v = (v << 7) | (c & 0x7f);
	}while(c & 0x80);
	return v;
}


#define NOTE_BUF_N	256

struct note_rec{
	int ch;
	int note;
	int onoff;
	double on_sec;
	double off_sec;
	int velo;
	double cycle, sec, freq;
	double off_v;
} note_buf[NOTE_BUF_N];

int
note_buf_is_free(int i)
{
	return note_buf[i].ch < 0;
}

void
note_buf_free(int i)
{
	note_buf[i].ch = -1;
}

void
note_buf_init(void)
{
	int i;

	for(i=0; i<NOTE_BUF_N; i++) note_buf_free(i);
}

int
note_buf_search(int ch, int note, int onoff)
{
	int i;

	for(i=0; i<NOTE_BUF_N; i++) {
		if( (ch < 0 && note_buf[i].ch < 0) ||
		    (note_buf[i].ch == ch &&
		     note_buf[i].note == note &&
		     note_buf[i].onoff == onoff) ) return i;
	}
	return -1;
}

int
header(void)
{
	int v;

	if(!rd_str_chk(4, "MThd")) ERR("header id");
	if(rd_int(4) != 6) ERR("header size");
	if(rd_int(2) != 0) ERR("header format type");
	if(rd_int(2) != 1) ERR("header track num");
	if((v = rd_int(2)) & 0x8000) ERR("header division");
	return v; /* div4 */
}

double
note_to_freq(int note)
{
	return 440 * pow(2, (note - 69) / 12.0);
}

int
opt_idx(char *key, int ac, char **av)
{
	int i;

	for(i=1; i<ac; i++) if(strcmp(av[i], key) == 0) return i;
	return -1;
}

char *
opt_str(char *key, int ac, char **av, char *def)
{
	int i;

	i = opt_idx(key, ac, av);
	if(i < 0 || i+1 >= ac) return def;
	return av[i+1];
}

int
opt_int(char *key, int ac, char **av, int def)
{
	char *s;

	if((s = opt_str(key, ac, av, NULL)) == NULL) return def;
	return strtol(s, NULL, 0);
}

struct out_rec{
	int smp_freq, smp_cnt;
	int bit_len;
	int sign;
	int ch_num;
	FILE *fp;

	int base;
	int amp;
	int iv_min;
	int iv_max;
};

void
out_init(struct out_rec *ot, int ac, char **av)
{
	char cmd[1024], *fn;

	ot->smp_freq = opt_int("-r", ac, av, 8000);
	ot->smp_cnt = 0;
	ot->bit_len = opt_int("-b", ac, av, 8);
	if(ot->bit_len != 8 && ot->bit_len != 16) ERR("bit_len");
	ot->sign = (opt_idx("-s", ac, av) >= 0);
	ot->ch_num = opt_int("-c", ac, av, 1);

	ot->fp = stdout;
	cmd[0] = '\0';
	fn = "";
	if(opt_idx("-play", ac, av) >= 0){
		strcat(cmd, "play");
	}else if(opt_idx("-sox", ac, av) >= 0){
		strcat(cmd, "sox");
		fn = opt_str("-sox", ac, av, "-d");
	}
	if(cmd[0]){
		sprintf(cmd + strlen(cmd), " -t raw -r %d -b %d %s -c %d - %s",
			ot->smp_freq, ot->bit_len,
			ot->sign ? "-s" : "-u",
			ot->ch_num, fn);
		if((ot->fp = popen(cmd, "w")) == NULL) ERR("popen");
	}
	ot->amp = ot->bit_len == 8 ? 127 : 32767;
	ot->base = ot->sign ? 0 : ot->amp + 1;
	ot->iv_min = ot->base - (ot->amp + 1);
	ot->iv_max = ot->base + ot->amp;
}

void
out_do(struct out_rec *ot, double v)
{
	int iv;

	iv = ot->base + (int)(v *ot->amp);
	if(iv > ot->iv_max) iv = ot->iv_max;
	if(iv < ot->iv_min) iv = ot->iv_min;
	switch(ot->bit_len){
	case 8:
		fputc(iv, ot->fp);
		break;
	case 16:
		fputc(iv & 0xff, ot->fp);
		fputc((iv >> 8) & 0xff, ot->fp);
		break;
	}
}

#define WAVE_SIN	0
#define WAVE_SAW	1
#define WAVE_SQUARE	2
#define WAVE_NOISE	3

double
wave_out(int wave, double cycle)
{
	cycle -= (int)cycle;

	switch(wave){
	case WAVE_SIN:
		return sin(2 * M_PI * cycle);
	case WAVE_SAW:
		cycle *= 2;
		if(cycle > 1) cycle -= 2;
		return cycle;
	case WAVE_SQUARE:
		return cycle < 0.5 ? 1 : -1;
	case WAVE_NOISE:
		return ((double)rand() / RAND_MAX) * 2 - 1;
	}
	return 0;
}

struct env_rec{
	double attack;	/* sec */
	double decay;	/* sec */
	double sustain;	/* 0..1 */
	double release;	/* sec */
};

void
env_set(struct env_rec *e, double a, double d, double s, double r)
{
	e->attack = a;
	e->decay = d;
	e->sustain = s;
	e->release = r;
}

struct tone_rec{
	int wave;
	struct env_rec env;
	double level;
} tone_inf[] = {
	{
		WAVE_SAW,
		{ 0.15, 0.5, 0.8, 0.5 },
		0.7
	},{
		WAVE_SAW,
		{ 0.05, 0.2, 0.4, 0.2 },
		0.7
	},{
		WAVE_SQUARE,
		{ 0.01, 0.2, 0.8, 0.3 },
		0.7
	},{
		WAVE_SIN,
		{ 0, 0.3, 0.2, 0.3 },
		1.0
	}
};

struct tone_rec *
tone_get(int prog)
{
	switch(prog){
	case 48: /* timpani */
	case 50: /* strings ensamble 2 */
		return &tone_inf[0];

	case 35: /* electric bass (pick) */
		return &tone_inf[1];

	case 79: /* whistle */
	case 81: /* lead 1 (square) */
	case 87: /* lead 7 (fifths) */
		return &tone_inf[2];

	case 24: /* tango accordion */
	case 67: /* tenor sax */
	default:
		break;
	}
	return &tone_inf[3];
}

#define MIDI_CH_N	16
struct ch_rec{
	int vol;
	int pan;
	int bend;
	int rpn;
	int bend_range;
	int prog;
} ch_inf[ MIDI_CH_N ];

#define CH_ENV(ch)	tone_get(ch_inf[ch].prog)->env

double
env_out(struct note_rec *nt)
{
	struct env_rec *e;
	double sec, v;

	sec = nt->sec;
	e = &CH_ENV(nt->ch);
	if(nt->onoff){
		sec -= nt->on_sec;
		if(sec < e->attack){
			v = sec / e->attack;
			return log10(1 + v * 9);
		}
		sec -= e->attack;
		if(sec < e->decay){
			v = sec / e->decay;
			v = log10(1 + v * 9);
			return 1 - v * (1 - e->sustain);
		}
		return e->sustain;
	}
	sec -= nt->off_sec;
	if(sec < e->release){
		v = sec / e->release;
		v = log10(1 + v * 9);
		return (1 - v) * nt->off_v;
	}
	return 0;
}

void
data_out(struct out_rec *ot, double evt_sec)
{
	double v, sec, freq, dsec;
	double vl, vr, pan;
	int i, nch;
	struct note_rec *nt;
	struct tone_rec *tn;

	while((sec = (double)ot->smp_cnt / ot->smp_freq) < evt_sec){
		vl = vr = 0;
		for(i=0; i<NOTE_BUF_N; i++){
			if(note_buf_is_free(i)) continue;
			nt = &note_buf[i];
			nch = nt->ch;
			freq = note_to_freq(nt->note);
			if(ch_inf[nch].bend != 0) freq *= pow(2, ch_inf[nch].bend / 8192.0 * ch_inf[nch].bend_range / 12);
			dsec = sec - nt->on_sec;
			if(dsec > 0.3) freq *= pow(2, sin(2 * M_PI * 6 * dsec) / (12 * 4) );
			nt->cycle += freq * (sec - nt->sec);
			nt->sec = sec;
			nt->freq = freq;
			tn = tone_get(ch_inf[nch].prog);
			v = wave_out(tn->wave, nt->cycle);
			v *= env_out(&note_buf[i]) * tn->level;
			v *= nt->velo / 127.0;
			v *= ch_inf[nch].vol / (double)((1<<14)-1);
			if(ot->ch_num == 1){
				vl += v;
			}else{
				pan = ch_inf[nch].pan / (double)(1<<14);
				vl += (1 - pan) * v;
				vr += pan * v;
			}
			if(nt->onoff == 0 && sec - nt->off_sec >= tn->env.release) note_buf_free(i);
		}
		out_do(ot, vl / 16);
		if(ot->ch_num > 1) out_do(ot, vr / 16);
		ot->smp_cnt++;
	}
}

void
note_onoff(int onoff, double evt_sec, int ch, int note, int velo)
{
	int i;

	if(ch == 9) return;

	if(onoff){
		if((i = note_buf_search(-1, -1, -1)) < 0){
			MSG("note_buf full");
			return;
		}
		note_buf[i].note = note;
		note_buf[i].ch = ch;
		note_buf[i].onoff = 1;
		note_buf[i].on_sec = evt_sec;
		note_buf[i].velo = velo;
		note_buf[i].cycle = 0;
		note_buf[i].sec = evt_sec;
	}else{
		if((i = note_buf_search(ch, note, 1)) < 0) return;
		note_buf[i].off_v = env_out(&note_buf[i]);
		note_buf[i].onoff = 0;
		note_buf[i].off_sec = evt_sec;
	}
}

void
msb_set(int *vp, int v)
{
	*vp &= ~(127<<7);
	*vp |= v<<7;
}

void
lsb_set(int *vp, int v)
{
	*vp &= ~127;
	*vp |= v;
}

void
bend_note_update(int ch, double sec)
{
	int i;
	struct note_rec *nt;

	for(i=0; ich != ch) continue;
		nt->cycle += nt->freq * (sec - nt->sec);
		nt->sec = sec;
	}
}

int
main(int ac, char **av)
{
	int div4, delta_sum;
	int i, n, v, hi, low, note, velo;
	int ch, type;
	double sec;
	struct out_rec otr;
	int tempo, tempo_delta_sum;
	double tempo_sec;

	out_init(&otr, ac, av);
	note_buf_init();
	for(i=0; i<MIDI_CH_N; i++){
		ch_inf[i].vol = 0;
		ch_inf[i].pan = 1<<(14-1);
		ch_inf[i].bend = 0;
		ch_inf[i].rpn = 0;
		ch_inf[i].bend_range = 2;
		ch_inf[i].prog =-1;
	}
	tempo = 500000;
	tempo_delta_sum = 0;
	tempo_sec = 0;

	div4 = header();

	if(!rd_str_chk(4, "MTrk")) ERR("track id");
	v = rd_int(4); /* skip */

	hi = low = 0;
	delta_sum = 0;
	while((v = rd_delta()) != EOF){
		delta_sum += v;
		sec = tempo_sec + (double)(delta_sum - tempo_delta_sum) / div4 * tempo * 0.000001;
		
		if((v = rd()) & 0x80){
			hi = (v >> 4) & 0xf;
			low  = v & 0xf;
		}else bk(v);

		data_out(&otr, sec);

		ch = low;
		switch(hi){
		case 8:
		case 9:
			note = rd();
			velo = rd();
			note_onoff(hi == 9, sec, ch, note, velo);
			break;
		case 0xb: /* control change */
			type = rd();
			v = rd();
			switch(type){
			case 7: /* channel volume msb */
				msb_set(&ch_inf[ch].vol, v);
				break;
			case 39: /* channel volume lsb */
				lsb_set(&ch_inf[ch].vol, v);
				break;
			case 10: /* pan msb */
				msb_set(&ch_inf[ch].pan, v);
				break;
			case 42: /* pan lsb */
				lsb_set(&ch_inf[ch].pan, v);
				break;
			case 100: /* rpn lsb */
				lsb_set(&ch_inf[ch].rpn, v);
				break;
			case 101: /* rpn msb */
				msb_set(&ch_inf[ch].rpn, v);
				break;
			case 6: /* data entry msb */
				switch(ch_inf[ch].rpn){
				case 0: /* pitch bend range */
					ch_inf[ch].bend_range = v;
					break;
				}
				break;
			}
			break;
		case 0xa:
			rd();
			rd();
			break;
		case 0xe: /* pitch wheel change */
			bend_note_update(ch, sec);
			v = rd();
			v |= rd() << 7;
			ch_inf[ch].bend = v - 8192;
			break;
		case 0xc: /* program number */
			v = rd();
			ch_inf[ch].prog = v;
			break;
		case 0xd:
			rd();
			break;
		case 0xf:
			type = rd();
			switch(low){
			case 0:
				while(rd() != 0xf7);
				break;
			case 1:
			case 3:
				rd();
				break;
			case 2:
				rd();
				rd();
				break;
			case 0xf: /* meta */
				n = rd();
				switch(type){
				case 0x51: /* set tempo */
					v = rd_int(n);
					tempo = v;
					tempo_delta_sum = delta_sum;
					tempo_sec = sec;
					break;
				default:
					for(i=0; i<n; i++) rd();
					break;
				}
				break;
			default:
				break;
			}
			break;
		}
	}
	if(otr.fp != stdout) pclose(otr.fp);
	return 0;
}

/* EOF */


#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <math.h>

#define MSG(s) fprintf(stderr, "%s() %s L%d : %s\n", __func__, __FILE__, __LINE__, s)
#define ERR(s) do{ fprintf(stderr, "ERR "); MSG(s); exit(1); }while(0)

int bk_buf = -1;

int
rd(void)
{
	int v;

	if((v = bk_buf) < 0) return getchar();
	bk_buf = -1;
	return v;
}

void
bk(int v)
{
	if(bk_buf >= 0) ERR("give up");
	bk_buf = v;
}

void
rd_str(int n, char *s)
{
	int i;

	for(i=0; i<n; i++) s[i] = rd();
	s[i] = '\0';
}

int
rd_str_chk(int n, char *s)
{
	char buf[256];

	rd_str(n, buf);
	return strcmp(buf, s) == 0;
}

int
rd_int(int n) /* big endian */
{
	int i, v;

	v = 0;
	for(i=0; i<n; i++) v = (v << 8) | rd();
	return v;
}

int
rd_delta(void)
{
	int v, c;

	v = 0;
	do{
		if((c = rd()) == EOF) return EOF;
		v = (v << 7) | (c & 0x7f);
	}while(c & 0x80);
	return v;
}


#define NOTE_BUF_N	256

struct note_rec{
	int ch;
	int note;
	int onoff;
	double on_sec;
	double off_sec;
	int velo;
	double cycle, sec, freq;
	double off_v;
} note_buf[NOTE_BUF_N];

int
note_buf_is_free(int i)
{
	return note_buf[i].ch < 0;
}

void
note_buf_free(int i)
{
	note_buf[i].ch = -1;
}

void
note_buf_init(void)
{
	int i;

	for(i=0; i<NOTE_BUF_N; i++) note_buf_free(i);
}

int
note_buf_search(int ch, int note, int onoff)
{
	int i;

	for(i=0; i<NOTE_BUF_N; i++) {
		if( (ch < 0 && note_buf[i].ch < 0) ||
		    (note_buf[i].ch == ch &&
		     note_buf[i].note == note &&
		     note_buf[i].onoff == onoff) ) return i;
	}
	return -1;
}

int
header(void)
{
	int v;

	if(!rd_str_chk(4, "MThd")) ERR("header id");
	if(rd_int(4) != 6) ERR("header size");
	if(rd_int(2) != 0) ERR("header format type");
	if(rd_int(2) != 1) ERR("header track num");
	if((v = rd_int(2)) & 0x8000) ERR("header division");
	return v; /* div4 */
}

double
note_to_freq(int note)
{
	return 440 * pow(2, (note - 69) / 12.0);
}

int
opt_idx(char *key, int ac, char **av)
{
	int i;

	for(i=1; i<ac; i++) if(strcmp(av[i], key) == 0) return i;
	return -1;
}

char *
opt_str(char *key, int ac, char **av, char *def)
{
	int i;

	i = opt_idx(key, ac, av);
	if(i < 0 || i+1 >= ac) return def;
	return av[i+1];
}

int
opt_int(char *key, int ac, char **av, int def)
{
	char *s;

	if((s = opt_str(key, ac, av, NULL)) == NULL) return def;
	return strtol(s, NULL, 0);
}

struct out_rec{
	int smp_freq, smp_cnt;
	int bit_len;
	int sign;
	int ch_num;
	FILE *fp;

	int base;
	int amp;
	int iv_min;
	int iv_max;
};

void
out_init(struct out_rec *ot, int ac, char **av)
{
	char cmd[1024], *fn;

	ot->smp_freq = opt_int("-r", ac, av, 8000);
	ot->smp_cnt = 0;
	ot->bit_len = opt_int("-b", ac, av, 8);
	if(ot->bit_len != 8 && ot->bit_len != 16) ERR("bit_len");
	ot->sign = (opt_idx("-s", ac, av) >= 0);
	ot->ch_num = opt_int("-c", ac, av, 1);

	ot->fp = stdout;
	cmd[0] = '\0';
	fn = "";
	if(opt_idx("-play", ac, av) >= 0){
		strcat(cmd, "play");
	}else if(opt_idx("-sox", ac, av) >= 0){
		strcat(cmd, "sox");
		fn = opt_str("-sox", ac, av, "-d");
	}
	if(cmd[0]){
		sprintf(cmd + strlen(cmd), " -t raw -r %d -b %d %s -c %d - %s",
			ot->smp_freq, ot->bit_len,
			ot->sign ? "-s" : "-u",
			ot->ch_num, fn);
		if((ot->fp = popen(cmd, "w")) == NULL) ERR("popen");
	}
	ot->amp = ot->bit_len == 8 ? 127 : 32767;
	ot->base = ot->sign ? 0 : ot->amp + 1;
	ot->iv_min = ot->base - (ot->amp + 1);
	ot->iv_max = ot->base + ot->amp;
}

void
out_do(struct out_rec *ot, double v)
{
	int iv;

	iv = ot->base + (int)(v *ot->amp);
	if(iv > ot->iv_max) iv = ot->iv_max;
	if(iv < ot->iv_min) iv = ot->iv_min;
	switch(ot->bit_len){
	case 8:
		fputc(iv, ot->fp);
		break;
	case 16:
		fputc(iv & 0xff, ot->fp);
		fputc((iv >> 8) & 0xff, ot->fp);
		break;
	}
}

#define WAVE_SIN	0
#define WAVE_SAW	1
#define WAVE_SQUARE	2
#define WAVE_NOISE	3
// 波形のタイプの定義
// SIN波、ノコギリ波、矩形波、ノイズの4種類

double
wave_out(int wave, double cycle)
{
	// 波形のタイプと、サイクルから、波形の値を返す
	//
	// wave は、WAVE_SIN, WAVE_SAW, WAVE_SQUARE, WAVE_NOISE
	// のいずれかを指定
	
	cycle -= (int)cycle;

	switch(wave){
	case WAVE_SIN:
		return sin(2 * M_PI * cycle);
	case WAVE_SAW:
		cycle *= 2;
		if(cycle > 1) cycle -= 2;
		return cycle;
	case WAVE_SQUARE:
		return cycle < 0.5 ? 1 : -1;
	case WAVE_NOISE:
		return ((double)rand() / RAND_MAX) * 2 - 1;
	}
	return 0;
}

struct env_rec{
	double attack;	/* sec */
	double decay;	/* sec */
	double sustain;	/* 0..1 */
	double release;	/* sec */
};

void
env_set(struct env_rec *e, double a, double d, double s, double r)
{
	e->attack = a;
	e->decay = d;
	e->sustain = s;
	e->release = r;
}

struct tone_rec{
	int wave;
	// 波形のタイプを追加
	
	struct env_rec env;
	double level;
	// 音量のレベル (0.0で無音、1.0で等倍) を追加
	
} tone_inf[] = {
	{
		WAVE_SAW,
		{ 0.15, 0.5, 0.8, 0.5 },
		0.7
	},{
		WAVE_SAW,
		{ 0.05, 0.2, 0.4, 0.2 },
		0.7
	},{
		WAVE_SQUARE,
		{ 0.01, 0.2, 0.8, 0.3 },
		0.7
	},{
		WAVE_SIN,
		{ 0, 0.3, 0.2, 0.3 },
		1.0
	}
};

struct tone_rec *
tone_get(int prog)
{
	switch(prog){
	case 48: /* timpani */
	case 50: /* strings ensamble 2 */
		return &tone_inf[0];

	case 35: /* electric bass (pick) */
		return &tone_inf[1];

	case 79: /* whistle */
	case 81: /* lead 1 (square) */
	case 87: /* lead 7 (fifths) */
		return &tone_inf[2];

	case 24: /* tango accordion */
	case 67: /* tenor sax */
	default:
		break;
	}
	return &tone_inf[3];
}

#define MIDI_CH_N	16
struct ch_rec{
	int vol;
	int pan;
	int bend;
	int rpn;
	int bend_range;
	int prog;
} ch_inf[ MIDI_CH_N ];

#define CH_ENV(ch)	tone_get(ch_inf[ch].prog)->env

double
env_out(struct note_rec *nt)
{
	struct env_rec *e;
	double sec, v;

	sec = nt->sec;
	e = &CH_ENV(nt->ch);
	if(nt->onoff){
		sec -= nt->on_sec;
		if(sec < e->attack){
			v = sec / e->attack;
			return log10(1 + v * 9);
		}
		sec -= e->attack;
		if(sec < e->decay){
			v = sec / e->decay;
			v = log10(1 + v * 9);
			return 1 - v * (1 - e->sustain);
		}
		return e->sustain;
	}
	sec -= nt->off_sec;
	if(sec < e->release){
		v = sec / e->release;
		v = log10(1 + v * 9);
		return (1 - v) * nt->off_v;
	}
	return 0;
}

void
data_out(struct out_rec *ot, double evt_sec)
{
	double v, sec, freq, dsec;
	double vl, vr, pan;
	int i, nch;
	struct note_rec *nt;
	struct tone_rec *tn;
	// 音色の構造体保持用に変数を追加
	
	while((sec = (double)ot->smp_cnt / ot->smp_freq) < evt_sec){
		vl = vr = 0;
		for(i=0; i<NOTE_BUF_N; i++){
			if(note_buf_is_free(i)) continue;
			nt = &note_buf[i];
			nch = nt->ch;
			freq = note_to_freq(nt->note);
			if(ch_inf[nch].bend != 0) freq *= pow(2, ch_inf[nch].bend / 8192.0 * ch_inf[nch].bend_range / 12);
			dsec = sec - nt->on_sec;
			if(dsec > 0.3) freq *= pow(2, sin(2 * M_PI * 6 * dsec) / (12 * 4) );
			nt->cycle += freq * (sec - nt->sec);
			nt->sec = sec;
			nt->freq = freq;
			tn = tone_get(ch_inf[nch].prog);
			// 音色の構造体を取得し、追加した変数へ
			
			v = wave_out(tn->wave, nt->cycle);
			// 音色の指定波形と、サイクル数から、
			// 波形の値を算出し、変数 v へ
			
			v *= env_out(&note_buf[i]) * tn->level;
			// エンベロープ出力に加え、
			// 追加した音量のレベルを振幅に加味する
			
			v *= nt->velo / 127.0;
			v *= ch_inf[nch].vol / (double)((1<<14)-1);
			if(ot->ch_num == 1){
				vl += v;
			}else{
				pan = ch_inf[nch].pan / (double)(1<<14);
				vl += (1 - pan) * v;
				vr += pan * v;
			}
			if(nt->onoff == 0 && sec - nt->off_sec >= tn->env.release) note_buf_free(i);
			// 音色の構造体用に変数を追加したので、
			// それを使用するように変更
			
		}
		out_do(ot, vl / 16);
		if(ot->ch_num > 1) out_do(ot, vr / 16);
		ot->smp_cnt++;
	}
}

void
note_onoff(int onoff, double evt_sec, int ch, int note, int velo)
{
	int i;

	if(ch == 9) return;

	if(onoff){
		if((i = note_buf_search(-1, -1, -1)) < 0){
			MSG("note_buf full");
			return;
		}
		note_buf[i].note = note;
		note_buf[i].ch = ch;
		note_buf[i].onoff = 1;
		note_buf[i].on_sec = evt_sec;
		note_buf[i].velo = velo;
		note_buf[i].cycle = 0;
		note_buf[i].sec = evt_sec;
	}else{
		if((i = note_buf_search(ch, note, 1)) < 0) return;
		note_buf[i].off_v = env_out(&note_buf[i]);
		note_buf[i].onoff = 0;
		note_buf[i].off_sec = evt_sec;
	}
}

void
msb_set(int *vp, int v)
{
	*vp &= ~(127<<7);
	*vp |= v<<7;
}

void
lsb_set(int *vp, int v)
{
	*vp &= ~127;
	*vp |= v;
}

void
bend_note_update(int ch, double sec)
{
	int i;
	struct note_rec *nt;

	for(i=0; ich != ch) continue;
		nt->cycle += nt->freq * (sec - nt->sec);
		nt->sec = sec;
	}
}

int
main(int ac, char **av)
{
	int div4, delta_sum;
	int i, n, v, hi, low, note, velo;
	int ch, type;
	double sec;
	struct out_rec otr;
	int tempo, tempo_delta_sum;
	double tempo_sec;

	out_init(&otr, ac, av);
	note_buf_init();
	for(i=0; i<MIDI_CH_N; i++){
		ch_inf[i].vol = 0;
		ch_inf[i].pan = 1<<(14-1);
		ch_inf[i].bend = 0;
		ch_inf[i].rpn = 0;
		ch_inf[i].bend_range = 2;
		ch_inf[i].prog =-1;
	}
	tempo = 500000;
	tempo_delta_sum = 0;
	tempo_sec = 0;

	div4 = header();

	if(!rd_str_chk(4, "MTrk")) ERR("track id");
	v = rd_int(4); /* skip */

	hi = low = 0;
	delta_sum = 0;
	while((v = rd_delta()) != EOF){
		delta_sum += v;
		sec = tempo_sec + (double)(delta_sum - tempo_delta_sum) / div4 * tempo * 0.000001;
		
		if((v = rd()) & 0x80){
			hi = (v >> 4) & 0xf;
			low  = v & 0xf;
		}else bk(v);

		data_out(&otr, sec);

		ch = low;
		switch(hi){
		case 8:
		case 9:
			note = rd();
			velo = rd();
			note_onoff(hi == 9, sec, ch, note, velo);
			break;
		case 0xb: /* control change */
			type = rd();
			v = rd();
			switch(type){
			case 7: /* channel volume msb */
				msb_set(&ch_inf[ch].vol, v);
				break;
			case 39: /* channel volume lsb */
				lsb_set(&ch_inf[ch].vol, v);
				break;
			case 10: /* pan msb */
				msb_set(&ch_inf[ch].pan, v);
				break;
			case 42: /* pan lsb */
				lsb_set(&ch_inf[ch].pan, v);
				break;
			case 100: /* rpn lsb */
				lsb_set(&ch_inf[ch].rpn, v);
				break;
			case 101: /* rpn msb */
				msb_set(&ch_inf[ch].rpn, v);
				break;
			case 6: /* data entry msb */
				switch(ch_inf[ch].rpn){
				case 0: /* pitch bend range */
					ch_inf[ch].bend_range = v;
					break;
				}
				break;
			}
			break;
		case 0xa:
			rd();
			rd();
			break;
		case 0xe: /* pitch wheel change */
			bend_note_update(ch, sec);
			v = rd();
			v |= rd() << 7;
			ch_inf[ch].bend = v - 8192;
			break;
		case 0xc: /* program number */
			v = rd();
			ch_inf[ch].prog = v;
			break;
		case 0xd:
			rd();
			break;
		case 0xf:
			type = rd();
			switch(low){
			case 0:
				while(rd() != 0xf7);
				break;
			case 1:
			case 3:
				rd();
				break;
			case 2:
				rd();
				rd();
				break;
			case 0xf: /* meta */
				n = rd();
				switch(type){
				case 0x51: /* set tempo */
					v = rd_int(n);
					tempo = v;
					tempo_delta_sum = delta_sum;
					tempo_sec = sec;
					break;
				default:
					for(i=0; i<n; i++) rd();
					break;
				}
				break;
			default:
				break;
			}
			break;
		}
	}
	if(otr.fp != stdout) pclose(otr.fp);
	return 0;
}

/* EOF */


prog11.c 解説

prog10.c からの変更箇所のみ

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <math.h>

#define MSG(s) fprintf(stderr, "%s() %s L%d : %s\n", __func__, __FILE__, __LINE__, s)
#define ERR(s) do{ fprintf(stderr, "ERR "); MSG(s); exit(1); }while(0)

int bk_buf = -1;

int
rd(void)
{
	int v;

	if((v = bk_buf) < 0) return getchar();
	bk_buf = -1;
	return v;
}

void
bk(int v)
{
	if(bk_buf >= 0) ERR("give up");
	bk_buf = v;
}

void
rd_str(int n, char *s)
{
	int i;

	for(i=0; i<n; i++) s[i] = rd();
	s[i] = '\0';
}

int
rd_str_chk(int n, char *s)
{
	char buf[256];

	rd_str(n, buf);
	return strcmp(buf, s) == 0;
}

int
rd_int(int n) /* big endian */
{
	int i, v;

	v = 0;
	for(i=0; i<n; i++) v = (v << 8) | rd();
	return v;
}

int
rd_delta(void)
{
	int v, c;

	v = 0;
	do{
		if((c = rd()) == EOF) return EOF;
		v = (v << 7) | (c & 0x7f);
	}while(c & 0x80);
	return v;
}


#define NOTE_BUF_N	256

struct note_rec{
	int ch;
	int note;
	int onoff;
	double on_sec;
	double off_sec;
	int velo;
	double cycle, sec, freq;
	double off_v;
} note_buf[NOTE_BUF_N];

int
note_buf_is_free(int i)
{
	return note_buf[i].ch < 0;
}

void
note_buf_free(int i)
{
	note_buf[i].ch = -1;
}

void
note_buf_init(void)
{
	int i;

	for(i=0; i<NOTE_BUF_N; i++) note_buf_free(i);
}

int
note_buf_search(int ch, int note, int onoff)
{
	int i;

	for(i=0; i<NOTE_BUF_N; i++) {
		if( (ch < 0 && note_buf[i].ch < 0) ||
		    (note_buf[i].ch == ch &&
		     note_buf[i].note == note &&
		     note_buf[i].onoff == onoff) ) return i;
	}
	return -1;
}

int
header(void)
{
	int v;

	if(!rd_str_chk(4, "MThd")) ERR("header id");
	if(rd_int(4) != 6) ERR("header size");
	if(rd_int(2) != 0) ERR("header format type");
	if(rd_int(2) != 1) ERR("header track num");
	if((v = rd_int(2)) & 0x8000) ERR("header division");
	return v; /* div4 */
}

double
note_to_freq(int note)
{
	return 440 * pow(2, (note - 69) / 12.0);
}

int
opt_idx(char *key, int ac, char **av)
{
	int i;

	for(i=1; i<ac; i++) if(strcmp(av[i], key) == 0) return i;
	return -1;
}

char *
opt_str(char *key, int ac, char **av, char *def)
{
	int i;

	i = opt_idx(key, ac, av);
	if(i < 0 || i+1 >= ac) return def;
	return av[i+1];
}

int
opt_int(char *key, int ac, char **av, int def)
{
	char *s;

	if((s = opt_str(key, ac, av, NULL)) == NULL) return def;
	return strtol(s, NULL, 0);
}

struct out_rec{
	int smp_freq, smp_cnt;
	int bit_len;
	int sign;
	int ch_num;
	FILE *fp;

	int base;
	int amp;
	int iv_min;
	int iv_max;
};

void
out_init(struct out_rec *ot, int ac, char **av)
{
	char cmd[1024], *fn;

	ot->smp_freq = opt_int("-r", ac, av, 8000);
	ot->smp_cnt = 0;
	ot->bit_len = opt_int("-b", ac, av, 8);
	if(ot->bit_len != 8 && ot->bit_len != 16) ERR("bit_len");
	ot->sign = (opt_idx("-s", ac, av) >= 0);
	ot->ch_num = opt_int("-c", ac, av, 1);

	ot->fp = stdout;
	cmd[0] = '\0';
	fn = "";
	if(opt_idx("-play", ac, av) >= 0){
		strcat(cmd, "play");
	}else if(opt_idx("-sox", ac, av) >= 0){
		strcat(cmd, "sox");
		fn = opt_str("-sox", ac, av, "-d");
	}
	if(cmd[0]){
		sprintf(cmd + strlen(cmd), " -t raw -r %d -b %d %s -c %d - %s",
			ot->smp_freq, ot->bit_len,
			ot->sign ? "-s" : "-u",
			ot->ch_num, fn);
		if((ot->fp = popen(cmd, "w")) == NULL) ERR("popen");
	}
	ot->amp = ot->bit_len == 8 ? 127 : 32767;
	ot->base = ot->sign ? 0 : ot->amp + 1;
	ot->iv_min = ot->base - (ot->amp + 1);
	ot->iv_max = ot->base + ot->amp;
}

void
out_do(struct out_rec *ot, double v)
{
	int iv;

	iv = ot->base + (int)(v *ot->amp);
	if(iv > ot->iv_max) iv = ot->iv_max;
	if(iv < ot->iv_min) iv = ot->iv_min;
	switch(ot->bit_len){
	case 8:
		fputc(iv, ot->fp);
		break;
	case 16:
		fputc(iv & 0xff, ot->fp);
		fputc((iv >> 8) & 0xff, ot->fp);
		break;
	}
}

#define WAVE_SIN	0
#define WAVE_SAW	1
#define WAVE_SQUARE	2
#define WAVE_NOISE	3

double
wave_out(int wave, double cycle)
{
	cycle -= (int)cycle;

	switch(wave){
	case WAVE_SIN:
		return sin(2 * M_PI * cycle);
	case WAVE_SAW:
		cycle *= 2;
		if(cycle > 1) cycle -= 2;
		return cycle;
	case WAVE_SQUARE:
		return cycle < 0.5 ? 1 : -1;
	case WAVE_NOISE:
		return ((double)rand() / RAND_MAX) * 2 - 1;
	}
	return 0;
}

struct env_rec{
	double attack;	/* sec */
	double decay;	/* sec */
	double sustain;	/* 0..1 */
	double release;	/* sec */
};

void
env_set(struct env_rec *e, double a, double d, double s, double r)
{
	e->attack = a;
	e->decay = d;
	e->sustain = s;
	e->release = r;
}

struct tone_rec{
	int wave;
	struct env_rec env;
	double level;
} tone_inf[] = {
	{	/* strings */
		WAVE_SAW,
		{ 0.15, 0.5, 0.8, 0.5 },
		0.7
	},{	/* bass */
		WAVE_SAW,
		{ 0.05, 0.2, 0.4, 0.2 },
		0.7
	},{	/* lead */
		WAVE_SQUARE,
		{ 0.01, 0.2, 0.8, 0.3 },
		0.7
	},{	/* SIN */
		WAVE_SIN,
		{ 0, 0.3, 0.2, 0.3 },
		1.0
	}
}, drum_tone_inf[] = {
	{	/* bass */
		WAVE_NOISE,
		{ 0.01, 0.18, 0, 0.18 },
		1.0
	},{	/* snare */
		WAVE_NOISE,
		{ 0, 0.3, 0.3, 0.3 },
		1.0
	},{	/* tom */
		WAVE_NOISE,
		{ 0, 0.3, 2, 0.4 },
		1.0
	},{	/* hi-hat close */
		WAVE_NOISE,
		{ 0, 0.1, 0, 0.1 },
		1.0
	},{	/* hi-hat open */
		WAVE_NOISE,
		{ 0, 0, 1, 0.3 },
		1.0
	},{	/* cymbal */
		WAVE_NOISE,
		{ 0, 0.3, 0.3, 1 },
		1.0
	}
};

struct tone_rec *
tone_get(int prog, int note, double *ret_freq)
{
	int idx;
	struct tone_rec *ret;

	idx = -1;
	if(prog <= 0){ /* drum part */
		switch(note){
		case 36: /* bass drum1 */
			idx = 0;
			note = 28;
			break;
		case 37: /* side stick */
		case 40: /* electric snare */
			idx = 1;
			note = 69;
			break;
		case 41: /* low floor tom */
			idx = 2;
			note = 50;
			break;
		case 42: /* closed hi-hat */
			idx = 3;
			note = 115;
			break;
		case 46: /* open hi-hat */
			idx = 4;
			note = 115;
			break;
		case 49: /* crash cymbal 1 */
		case 57: /* crash cymbal 2 */
			idx = 5;
			note = 80;
			break;
		}
		ret = idx < 0 ? NULL : &drum_tone_inf[idx];
	}else{
		switch(prog){
		case 48: /* timpani */
		case 50: /* strings ensamble 2 */
			idx = 0;
			break;
		case 35: /* electric bass (pick) */
			idx = 1;
			break;
		case 79: /* whistle */
		case 81: /* lead 1 (square) */
		case 87: /* lead 7 (fifths) */
			idx = 2;
			break;
		case 24: /* tango accordion */
		case 67: /* tenor sax */
		default:
			idx = 3;
			break;
		}
		ret = &tone_inf[idx];
	}
	if(ret_freq) *ret_freq = note_to_freq(note);
	return ret;
}

#define MIDI_CH_N	16
struct ch_rec{
	int vol;
	int pan;
	int bend;
	int rpn;
	int bend_range;
	int prog;
} ch_inf[ MIDI_CH_N ];

#define CH_PROG(ch)	( (ch) == 9 ? 0 : ch_inf[ch].prog )

double
env_out(struct note_rec *nt)
{
	struct tone_rec *tn;
	struct env_rec *e;
	double sec, v;

	if((tn = tone_get(CH_PROG(nt->ch), nt->note, NULL)) == NULL) return 0;
	e = &tn->env;
	sec = nt->sec;
	if(nt->onoff){
		sec -= nt->on_sec;
		if(sec < e->attack){
			v = sec / e->attack;
			return log10(1 + v * 9);
		}
		sec -= e->attack;
		if(sec < e->decay){
			v = sec / e->decay;
			v = log10(1 + v * 9);
			return 1 - v * (1 - e->sustain);
		}
		return e->sustain;
	}
	sec -= nt->off_sec;
	if(sec < e->release){
		v = sec / e->release;
		v = log10(1 + v * 9);
		return (1 - v) * nt->off_v;
	}
	return 0;
}

void
data_out(struct out_rec *ot, double evt_sec)
{
	double v, sec, freq, dsec;
	double vl, vr, pan;
	int i, nch;
	struct note_rec *nt;
	struct tone_rec *tn;

	while((sec = (double)ot->smp_cnt / ot->smp_freq) < evt_sec){
		vl = vr = 0;
		for(i=0; i<NOTE_BUF_N; i++){
			if(note_buf_is_free(i)) continue;
			nt = &note_buf[i];
			nch = nt->ch;
			tn = tone_get(CH_PROG(nch), nt->note, &freq);
			if(tn == NULL) continue;
			if(ch_inf[nch].bend != 0) freq *= pow(2, ch_inf[nch].bend / 8192.0 * ch_inf[nch].bend_range / 12);
			dsec = sec - nt->on_sec;
			if(dsec > 0.3) freq *= pow(2, sin(2 * M_PI * 6 * dsec) / (12 * 4) );
			nt->cycle += freq * (sec - nt->sec);
			nt->sec = sec;
			nt->freq = freq;
			v = wave_out(tn->wave, nt->cycle);
			v *= env_out(&note_buf[i]) * tn->level;
			v *= nt->velo / 127.0;
			v *= ch_inf[nch].vol / (double)((1<<14)-1);
			if(ot->ch_num == 1){
				vl += v;
			}else{
				pan = ch_inf[nch].pan / (double)(1<<14);
				vl += (1 - pan) * v;
				vr += pan * v;
			}
			if(nt->onoff == 0 && sec - nt->off_sec >= tn->env.release) note_buf_free(i);
		}
		out_do(ot, vl / 16);
		if(ot->ch_num > 1) out_do(ot, vr / 16);
		ot->smp_cnt++;
	}
}

void
note_onoff(int onoff, double evt_sec, int ch, int note, int velo)
{
	int i;

	;

	if(onoff){
		if((i = note_buf_search(-1, -1, -1)) < 0){
			MSG("note_buf full");
			return;
		}
		note_buf[i].note = note;
		note_buf[i].ch = ch;
		note_buf[i].onoff = 1;
		note_buf[i].on_sec = evt_sec;
		note_buf[i].velo = velo;
		note_buf[i].cycle = 0;
		note_buf[i].sec = evt_sec;
	}else{
		if((i = note_buf_search(ch, note, 1)) < 0) return;
		note_buf[i].off_v = env_out(&note_buf[i]);
		note_buf[i].onoff = 0;
		note_buf[i].off_sec = evt_sec;
	}
}

void
msb_set(int *vp, int v)
{
	*vp &= ~(127<<7);
	*vp |= v<<7;
}

void
lsb_set(int *vp, int v)
{
	*vp &= ~127;
	*vp |= v;
}

void
bend_note_update(int ch, double sec)
{
	int i;
	struct note_rec *nt;

	for(i=0; ich != ch) continue;
		nt->cycle += nt->freq * (sec - nt->sec);
		nt->sec = sec;
	}
}

int
main(int ac, char **av)
{
	int div4, delta_sum;
	int i, n, v, hi, low, note, velo;
	int ch, type;
	double sec;
	struct out_rec otr;
	int tempo, tempo_delta_sum;
	double tempo_sec;

	out_init(&otr, ac, av);
	note_buf_init();
	for(i=0; i<MIDI_CH_N; i++){
		ch_inf[i].vol = 0;
		ch_inf[i].pan = 1<<(14-1);
		ch_inf[i].bend = 0;
		ch_inf[i].rpn = 0;
		ch_inf[i].bend_range = 2;
		ch_inf[i].prog =-1;
	}
	tempo = 500000;
	tempo_delta_sum = 0;
	tempo_sec = 0;

	div4 = header();

	if(!rd_str_chk(4, "MTrk")) ERR("track id");
	v = rd_int(4); /* skip */

	hi = low = 0;
	delta_sum = 0;
	while((v = rd_delta()) != EOF){
		delta_sum += v;
		sec = tempo_sec + (double)(delta_sum - tempo_delta_sum) / div4 * tempo * 0.000001;
		
		if((v = rd()) & 0x80){
			hi = (v >> 4) & 0xf;
			low  = v & 0xf;
		}else bk(v);

		data_out(&otr, sec);

		ch = low;
		switch(hi){
		case 8:
		case 9:
			note = rd();
			velo = rd();
			note_onoff(hi == 9, sec, ch, note, velo);
			break;
		case 0xb: /* control change */
			type = rd();
			v = rd();
			switch(type){
			case 7: /* channel volume msb */
				msb_set(&ch_inf[ch].vol, v);
				break;
			case 39: /* channel volume lsb */
				lsb_set(&ch_inf[ch].vol, v);
				break;
			case 10: /* pan msb */
				msb_set(&ch_inf[ch].pan, v);
				break;
			case 42: /* pan lsb */
				lsb_set(&ch_inf[ch].pan, v);
				break;
			case 100: /* rpn lsb */
				lsb_set(&ch_inf[ch].rpn, v);
				break;
			case 101: /* rpn msb */
				msb_set(&ch_inf[ch].rpn, v);
				break;
			case 6: /* data entry msb */
				switch(ch_inf[ch].rpn){
				case 0: /* pitch bend range */
					ch_inf[ch].bend_range = v;
					break;
				}
				break;
			}
			break;
		case 0xa:
			rd();
			rd();
			break;
		case 0xe: /* pitch wheel change */
			bend_note_update(ch, sec);
			v = rd();
			v |= rd() << 7;
			ch_inf[ch].bend = v - 8192;
			break;
		case 0xc: /* program number */
			v = rd();
			ch_inf[ch].prog = v;
			break;
		case 0xd:
			rd();
			break;
		case 0xf:
			type = rd();
			switch(low){
			case 0:
				while(rd() != 0xf7);
				break;
			case 1:
			case 3:
				rd();
				break;
			case 2:
				rd();
				rd();
				break;
			case 0xf: /* meta */
				n = rd();
				switch(type){
				case 0x51: /* set tempo */
					v = rd_int(n);
					tempo = v;
					tempo_delta_sum = delta_sum;
					tempo_sec = sec;
					break;
				default:
					for(i=0; i<n; i++) rd();
					break;
				}
				break;
			default:
				break;
			}
			break;
		}
	}
	if(otr.fp != stdout) pclose(otr.fp);
	return 0;
}

/* EOF */


#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <math.h>

#define MSG(s) fprintf(stderr, "%s() %s L%d : %s\n", __func__, __FILE__, __LINE__, s)
#define ERR(s) do{ fprintf(stderr, "ERR "); MSG(s); exit(1); }while(0)

int bk_buf = -1;

int
rd(void)
{
	int v;

	if((v = bk_buf) < 0) return getchar();
	bk_buf = -1;
	return v;
}

void
bk(int v)
{
	if(bk_buf >= 0) ERR("give up");
	bk_buf = v;
}

void
rd_str(int n, char *s)
{
	int i;

	for(i=0; i<n; i++) s[i] = rd();
	s[i] = '\0';
}

int
rd_str_chk(int n, char *s)
{
	char buf[256];

	rd_str(n, buf);
	return strcmp(buf, s) == 0;
}

int
rd_int(int n) /* big endian */
{
	int i, v;

	v = 0;
	for(i=0; i<n; i++) v = (v << 8) | rd();
	return v;
}

int
rd_delta(void)
{
	int v, c;

	v = 0;
	do{
		if((c = rd()) == EOF) return EOF;
		v = (v << 7) | (c & 0x7f);
	}while(c & 0x80);
	return v;
}


#define NOTE_BUF_N	256

struct note_rec{
	int ch;
	int note;
	int onoff;
	double on_sec;
	double off_sec;
	int velo;
	double cycle, sec, freq;
	double off_v;
} note_buf[NOTE_BUF_N];

int
note_buf_is_free(int i)
{
	return note_buf[i].ch < 0;
}

void
note_buf_free(int i)
{
	note_buf[i].ch = -1;
}

void
note_buf_init(void)
{
	int i;

	for(i=0; i<NOTE_BUF_N; i++) note_buf_free(i);
}

int
note_buf_search(int ch, int note, int onoff)
{
	int i;

	for(i=0; i<NOTE_BUF_N; i++) {
		if( (ch < 0 && note_buf[i].ch < 0) ||
		    (note_buf[i].ch == ch &&
		     note_buf[i].note == note &&
		     note_buf[i].onoff == onoff) ) return i;
	}
	return -1;
}

int
header(void)
{
	int v;

	if(!rd_str_chk(4, "MThd")) ERR("header id");
	if(rd_int(4) != 6) ERR("header size");
	if(rd_int(2) != 0) ERR("header format type");
	if(rd_int(2) != 1) ERR("header track num");
	if((v = rd_int(2)) & 0x8000) ERR("header division");
	return v; /* div4 */
}

double
note_to_freq(int note)
{
	return 440 * pow(2, (note - 69) / 12.0);
}

int
opt_idx(char *key, int ac, char **av)
{
	int i;

	for(i=1; i<ac; i++) if(strcmp(av[i], key) == 0) return i;
	return -1;
}

char *
opt_str(char *key, int ac, char **av, char *def)
{
	int i;

	i = opt_idx(key, ac, av);
	if(i < 0 || i+1 >= ac) return def;
	return av[i+1];
}

int
opt_int(char *key, int ac, char **av, int def)
{
	char *s;

	if((s = opt_str(key, ac, av, NULL)) == NULL) return def;
	return strtol(s, NULL, 0);
}

struct out_rec{
	int smp_freq, smp_cnt;
	int bit_len;
	int sign;
	int ch_num;
	FILE *fp;

	int base;
	int amp;
	int iv_min;
	int iv_max;
};

void
out_init(struct out_rec *ot, int ac, char **av)
{
	char cmd[1024], *fn;

	ot->smp_freq = opt_int("-r", ac, av, 8000);
	ot->smp_cnt = 0;
	ot->bit_len = opt_int("-b", ac, av, 8);
	if(ot->bit_len != 8 && ot->bit_len != 16) ERR("bit_len");
	ot->sign = (opt_idx("-s", ac, av) >= 0);
	ot->ch_num = opt_int("-c", ac, av, 1);

	ot->fp = stdout;
	cmd[0] = '\0';
	fn = "";
	if(opt_idx("-play", ac, av) >= 0){
		strcat(cmd, "play");
	}else if(opt_idx("-sox", ac, av) >= 0){
		strcat(cmd, "sox");
		fn = opt_str("-sox", ac, av, "-d");
	}
	if(cmd[0]){
		sprintf(cmd + strlen(cmd), " -t raw -r %d -b %d %s -c %d - %s",
			ot->smp_freq, ot->bit_len,
			ot->sign ? "-s" : "-u",
			ot->ch_num, fn);
		if((ot->fp = popen(cmd, "w")) == NULL) ERR("popen");
	}
	ot->amp = ot->bit_len == 8 ? 127 : 32767;
	ot->base = ot->sign ? 0 : ot->amp + 1;
	ot->iv_min = ot->base - (ot->amp + 1);
	ot->iv_max = ot->base + ot->amp;
}

void
out_do(struct out_rec *ot, double v)
{
	int iv;

	iv = ot->base + (int)(v *ot->amp);
	if(iv > ot->iv_max) iv = ot->iv_max;
	if(iv < ot->iv_min) iv = ot->iv_min;
	switch(ot->bit_len){
	case 8:
		fputc(iv, ot->fp);
		break;
	case 16:
		fputc(iv & 0xff, ot->fp);
		fputc((iv >> 8) & 0xff, ot->fp);
		break;
	}
}

#define WAVE_SIN	0
#define WAVE_SAW	1
#define WAVE_SQUARE	2
#define WAVE_NOISE	3

double
wave_out(int wave, double cycle)
{
	cycle -= (int)cycle;

	switch(wave){
	case WAVE_SIN:
		return sin(2 * M_PI * cycle);
	case WAVE_SAW:
		cycle *= 2;
		if(cycle > 1) cycle -= 2;
		return cycle;
	case WAVE_SQUARE:
		return cycle < 0.5 ? 1 : -1;
	case WAVE_NOISE:
		return ((double)rand() / RAND_MAX) * 2 - 1;
	}
	return 0;
}

struct env_rec{
	double attack;	/* sec */
	double decay;	/* sec */
	double sustain;	/* 0..1 */
	double release;	/* sec */
};

void
env_set(struct env_rec *e, double a, double d, double s, double r)
{
	e->attack = a;
	e->decay = d;
	e->sustain = s;
	e->release = r;
}

struct tone_rec{
	int wave;
	struct env_rec env;
	double level;
} tone_inf[] = {
	{	/* strings */
		WAVE_SAW,
		{ 0.15, 0.5, 0.8, 0.5 },
		0.7
	},{	/* bass */
		WAVE_SAW,
		{ 0.05, 0.2, 0.4, 0.2 },
		0.7
	},{	/* lead */
		WAVE_SQUARE,
		{ 0.01, 0.2, 0.8, 0.3 },
		0.7
	},{	/* SIN */
		WAVE_SIN,
		{ 0, 0.3, 0.2, 0.3 },
		1.0
	}
}, drum_tone_inf[] = {
	{	/* bass */
		WAVE_NOISE,
		{ 0.01, 0.18, 0, 0.18 },
		1.0
	},{	/* snare */
		WAVE_NOISE,
		{ 0, 0.3, 0.3, 0.3 },
		1.0
	},{	/* tom */
		WAVE_NOISE,
		{ 0, 0.3, 2, 0.4 },
		1.0
	},{	/* hi-hat close */
		WAVE_NOISE,
		{ 0, 0.1, 0, 0.1 },
		1.0
	},{	/* hi-hat open */
		WAVE_NOISE,
		{ 0, 0, 1, 0.3 },
		1.0
	},{	/* cymbal */
		WAVE_NOISE,
		{ 0, 0.3, 0.3, 1 },
		1.0
	}
};
// ドラム・パート用の音色として、drum_tone_inf[] を追加
// といっても、ノイズの波形にエンベロープを適当につけただけ


struct tone_rec *
tone_get(int prog, int note, double *ret_freq)
{
	// 引数に note (ノート番号) と、
	// ret_freq (音の周波数を返すポインタ) を追加
	//
	// 従来の引数 prog が 0 以下の場合、
	// ドラム・パート として扱う
	//
	// ノート番号から、音の周波数を算出する処理は、
	// data_out() 関数の中で行なっていたが、
	// この関数の中で処理するように変更
	//
	// ドラム・パートの場合は、ノート番号は音色の指定であり、
	// 鳴らす音の周波数は、
	// この関数の中で、直接指定してるノート番号の値から算出する
	
	int idx;
	struct tone_rec *ret;

	idx = -1;
	if(prog <= 0){ /* drum part */
		switch(note){
		case 36: /* bass drum1 */
			idx = 0;
			note = 28;
			break;
		case 37: /* side stick */
		case 40: /* electric snare */
			idx = 1;
			note = 69;
			break;
		case 41: /* low floor tom */
			idx = 2;
			note = 50;
			break;
		case 42: /* closed hi-hat */
			idx = 3;
			note = 115;
			break;
		case 46: /* open hi-hat */
			idx = 4;
			note = 115;
			break;
		case 49: /* crash cymbal 1 */
		case 57: /* crash cymbal 2 */
			idx = 5;
			note = 80;
			break;
		}
		ret = idx < 0 ? NULL : &drum_tone_inf[idx];
	}else{
		switch(prog){
		case 48: /* timpani */
		case 50: /* strings ensamble 2 */
			idx = 0;
			break;
		case 35: /* electric bass (pick) */
			idx = 1;
			break;
		case 79: /* whistle */
		case 81: /* lead 1 (square) */
		case 87: /* lead 7 (fifths) */
			idx = 2;
			break;
		case 24: /* tango accordion */
		case 67: /* tenor sax */
		default:
			idx = 3;
			break;
		}
		ret = &tone_inf[idx];
	}
	if(ret_freq) *ret_freq = note_to_freq(note);
	return ret;
}

#define MIDI_CH_N	16
struct ch_rec{
	int vol;
	int pan;
	int bend;
	int rpn;
	int bend_range;
	int prog;
} ch_inf[ MIDI_CH_N ];

#define CH_PROG(ch)	( (ch) == 9 ? 0 : ch_inf[ch].prog )
// CH_ENV(ch) マクロは廃止
// CH_PROG(ch) マクロを追加
// MIDIチャンネルから、プログラム番号を取得する
// MIDIチャンネルが 9 (ドラム・パート)の場合は、
// 特別なプログラム番号として、0 を返す
// 
// ターゲットのSMF では、
// 元々チャンネル 9 のプログラム番号は 0 に設定されている
// よって不要かもしれない...

double
env_out(struct note_rec *nt)
{
	struct tone_rec *tn;
	// 音色用の構造体を保持する変数を追加
	
	struct env_rec *e;
	double sec, v;

	if((tn = tone_get(CH_PROG(nt->ch), nt->note, NULL)) == NULL) return 0;
	// 鍵盤情報から、音色の構造体を取得
	// 音色が設定されてない場合は、エンベロープ出力として 0 を返す
	
	e = &tn->env;
	// 音色の構造体に設定されているエンベロープ構造体を取得
	
	sec = nt->sec;
	if(nt->onoff){
		sec -= nt->on_sec;
		if(sec < e->attack){
			v = sec / e->attack;
			return log10(1 + v * 9);
		}
		sec -= e->attack;
		if(sec < e->decay){
			v = sec / e->decay;
			v = log10(1 + v * 9);
			return 1 - v * (1 - e->sustain);
		}
		return e->sustain;
	}
	sec -= nt->off_sec;
	if(sec < e->release){
		v = sec / e->release;
		v = log10(1 + v * 9);
		return (1 - v) * nt->off_v;
	}
	return 0;
}

void
data_out(struct out_rec *ot, double evt_sec)
{
	double v, sec, freq, dsec;
	double vl, vr, pan;
	int i, nch;
	struct note_rec *nt;
	struct tone_rec *tn;

	while((sec = (double)ot->smp_cnt / ot->smp_freq) < evt_sec){
		vl = vr = 0;
		for(i=0; i<NOTE_BUF_N; i++){
			if(note_buf_is_free(i)) continue;
			nt = &note_buf[i];
			nch = nt->ch;
			tn = tone_get(CH_PROG(nch), nt->note, &freq);
			// 従来 freq の値を算出してた箇所を、
			// tone_get() の呼び出しに変更
			//
			// プログラム番号と、ノート番号をパラメータとして
			// 音色の構造体と、鳴らす音の周波数を取得する
			
			if(tn == NULL) continue;
			// 音色が設定されていない場合は、
			// 何も処理しない
			
			if(ch_inf[nch].bend != 0) freq *= pow(2, ch_inf[nch].bend / 8192.0 * ch_inf[nch].bend_range / 12);
			dsec = sec - nt->on_sec;
			if(dsec > 0.3) freq *= pow(2, sin(2 * M_PI * 6 * dsec) / (12 * 4) );
			nt->cycle += freq * (sec - nt->sec);
			nt->sec = sec;
			nt->freq = freq;
			v = wave_out(tn->wave, nt->cycle);
			v *= env_out(&note_buf[i]) * tn->level;
			v *= nt->velo / 127.0;
			v *= ch_inf[nch].vol / (double)((1<<14)-1);
			if(ot->ch_num == 1){
				vl += v;
			}else{
				pan = ch_inf[nch].pan / (double)(1<<14);
				vl += (1 - pan) * v;
				vr += pan * v;
			}
			if(nt->onoff == 0 && sec - nt->off_sec >= tn->env.release) note_buf_free(i);
		}
		out_do(ot, vl / 16);
		if(ot->ch_num > 1) out_do(ot, vr / 16);
		ot->smp_cnt++;
	}
}

void
note_onoff(int onoff, double evt_sec, int ch, int note, int velo)
{
	int i;

	;
	// ch == 9 の場合、ドラム・パートとして、スキップしていた処理を削除
	
	if(onoff){
		if((i = note_buf_search(-1, -1, -1)) < 0){
			MSG("note_buf full");
			return;
		}
		note_buf[i].note = note;
		note_buf[i].ch = ch;
		note_buf[i].onoff = 1;
		note_buf[i].on_sec = evt_sec;
		note_buf[i].velo = velo;
		note_buf[i].cycle = 0;
		note_buf[i].sec = evt_sec;
	}else{
		if((i = note_buf_search(ch, note, 1)) < 0) return;
		note_buf[i].off_v = env_out(&note_buf[i]);
		note_buf[i].onoff = 0;
		note_buf[i].off_sec = evt_sec;
	}
}

void
msb_set(int *vp, int v)
{
	*vp &= ~(127<<7);
	*vp |= v<<7;
}

void
lsb_set(int *vp, int v)
{
	*vp &= ~127;
	*vp |= v;
}

void
bend_note_update(int ch, double sec)
{
	int i;
	struct note_rec *nt;

	for(i=0; ich != ch) continue;
		nt->cycle += nt->freq * (sec - nt->sec);
		nt->sec = sec;
	}
}

int
main(int ac, char **av)
{
	int div4, delta_sum;
	int i, n, v, hi, low, note, velo;
	int ch, type;
	double sec;
	struct out_rec otr;
	int tempo, tempo_delta_sum;
	double tempo_sec;

	out_init(&otr, ac, av);
	note_buf_init();
	for(i=0; i<MIDI_CH_N; i++){
		ch_inf[i].vol = 0;
		ch_inf[i].pan = 1<<(14-1);
		ch_inf[i].bend = 0;
		ch_inf[i].rpn = 0;
		ch_inf[i].bend_range = 2;
		ch_inf[i].prog =-1;
	}
	tempo = 500000;
	tempo_delta_sum = 0;
	tempo_sec = 0;

	div4 = header();

	if(!rd_str_chk(4, "MTrk")) ERR("track id");
	v = rd_int(4); /* skip */

	hi = low = 0;
	delta_sum = 0;
	while((v = rd_delta()) != EOF){
		delta_sum += v;
		sec = tempo_sec + (double)(delta_sum - tempo_delta_sum) / div4 * tempo * 0.000001;
		
		if((v = rd()) & 0x80){
			hi = (v >> 4) & 0xf;
			low  = v & 0xf;
		}else bk(v);

		data_out(&otr, sec);

		ch = low;
		switch(hi){
		case 8:
		case 9:
			note = rd();
			velo = rd();
			note_onoff(hi == 9, sec, ch, note, velo);
			break;
		case 0xb: /* control change */
			type = rd();
			v = rd();
			switch(type){
			case 7: /* channel volume msb */
				msb_set(&ch_inf[ch].vol, v);
				break;
			case 39: /* channel volume lsb */
				lsb_set(&ch_inf[ch].vol, v);
				break;
			case 10: /* pan msb */
				msb_set(&ch_inf[ch].pan, v);
				break;
			case 42: /* pan lsb */
				lsb_set(&ch_inf[ch].pan, v);
				break;
			case 100: /* rpn lsb */
				lsb_set(&ch_inf[ch].rpn, v);
				break;
			case 101: /* rpn msb */
				msb_set(&ch_inf[ch].rpn, v);
				break;
			case 6: /* data entry msb */
				switch(ch_inf[ch].rpn){
				case 0: /* pitch bend range */
					ch_inf[ch].bend_range = v;
					break;
				}
				break;
			}
			break;
		case 0xa:
			rd();
			rd();
			break;
		case 0xe: /* pitch wheel change */
			bend_note_update(ch, sec);
			v = rd();
			v |= rd() << 7;
			ch_inf[ch].bend = v - 8192;
			break;
		case 0xc: /* program number */
			v = rd();
			ch_inf[ch].prog = v;
			break;
		case 0xd:
			rd();
			break;
		case 0xf:
			type = rd();
			switch(low){
			case 0:
				while(rd() != 0xf7);
				break;
			case 1:
			case 3:
				rd();
				break;
			case 2:
				rd();
				rd();
				break;
			case 0xf: /* meta */
				n = rd();
				switch(type){
				case 0x51: /* set tempo */
					v = rd_int(n);
					tempo = v;
					tempo_delta_sum = delta_sum;
					tempo_sec = sec;
					break;
				default:
					for(i=0; i<n; i++) rd();
					break;
				}
				break;
			default:
				break;
			}
			break;
		}
	}
	if(otr.fp != stdout) pclose(otr.fp);
	return 0;
}

/* EOF */


prog12.c 解説

prog11.c からの変更箇所のみ

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <math.h>

#define MSG(s) fprintf(stderr, "%s() %s L%d : %s\n", __func__, __FILE__, __LINE__, s)
#define ERR(s) do{ fprintf(stderr, "ERR "); MSG(s); exit(1); }while(0)

int bk_buf = -1;

int
rd(void)
{
	int v;

	if((v = bk_buf) < 0) return getchar();
	bk_buf = -1;
	return v;
}

void
bk(int v)
{
	if(bk_buf >= 0) ERR("give up");
	bk_buf = v;
}

void
rd_str(int n, char *s)
{
	int i;

	for(i=0; i<n; i++) s[i] = rd();
	s[i] = '\0';
}

int
rd_str_chk(int n, char *s)
{
	char buf[256];

	rd_str(n, buf);
	return strcmp(buf, s) == 0;
}

int
rd_int(int n) /* big endian */
{
	int i, v;

	v = 0;
	for(i=0; i<n; i++) v = (v << 8) | rd();
	return v;
}

int
rd_delta(void)
{
	int v, c;

	v = 0;
	do{
		if((c = rd()) == EOF) return EOF;
		v = (v << 7) | (c & 0x7f);
	}while(c & 0x80);
	return v;
}


struct lpf_rec{
	int idx;
	double in[4], out[4];
	double a0, a1, a2, b0, b1, b2, div_a0;
};

void
lpf_init(struct lpf_rec *lpf, double smp_freq, double freq, double Q)
{
	int i;
	double w0, alpha;

	for(i=0; i<4; i++) lpf->in[i] = lpf->out[i] = 0;
	lpf->idx = 0;

	w0 = 2 * M_PI * freq / smp_freq;
	alpha = sin(w0) / (2 * Q);
	lpf->b1 = 1 - cos(w0);
	lpf->b0 = lpf->b2 = lpf->b1 * 0.5;
	lpf->a0 = 1 + alpha;
	lpf->a1 = -2 * cos(w0);
	lpf->a2 = 1 - alpha;
	if(lpf->a0 != 0) lpf->div_a0 = 1 / lpf->a0;
}

double
lpf_out(struct lpf_rec *lpf, double in)
{
	double *out_p;
	int i_1, i_2;

	lpf->in[lpf->idx] = in;
	out_p = &lpf->out[lpf->idx];

	if(lpf->a0 != 0){
		i_1 = (lpf->idx + 4 - 1) & 3;
		i_2 = (i_1 + 4 - 1) & 3;
		*out_p = (lpf->b0 * in
			+ lpf->b1 * lpf->in[i_1]
			+ lpf->b2 * lpf->in[i_2]
			- lpf->a1 * lpf->out[i_1]
			- lpf->a2 * lpf->out[i_2] ) * lpf->div_a0;
	}else{
		*out_p = 0;
	}
	lpf->idx = (lpf->idx + 1) & 3;
	return *out_p;
}


#define NOTE_BUF_N	256

struct note_rec{
	int ch;
	int note;
	int onoff;
	double on_sec;
	double off_sec;
	int velo;
	double cycle, sec, freq;
	double off_v;
	struct lpf_rec lpf;
} note_buf[NOTE_BUF_N];

int
note_buf_is_free(int i)
{
	return note_buf[i].ch < 0;
}

void
note_buf_free(int i)
{
	note_buf[i].ch = -1;
}

void
note_buf_init(void)
{
	int i;

	for(i=0; i<NOTE_BUF_N; i++) note_buf_free(i);
}

int
note_buf_search(int ch, int note, int onoff)
{
	int i;

	for(i=0; i<NOTE_BUF_N; i++) {
		if( (ch < 0 && note_buf[i].ch < 0) ||
		    (note_buf[i].ch == ch &&
		     note_buf[i].note == note &&
		     note_buf[i].onoff == onoff) ) return i;
	}
	return -1;
}

int
header(void)
{
	int v;

	if(!rd_str_chk(4, "MThd")) ERR("header id");
	if(rd_int(4) != 6) ERR("header size");
	if(rd_int(2) != 0) ERR("header format type");
	if(rd_int(2) != 1) ERR("header track num");
	if((v = rd_int(2)) & 0x8000) ERR("header division");
	return v; /* div4 */
}

double
note_to_freq(int note)
{
	return 440 * pow(2, (note - 69) / 12.0);
}

int
opt_idx(char *key, int ac, char **av)
{
	int i;

	for(i=1; i<ac; i++) if(strcmp(av[i], key) == 0) return i;
	return -1;
}

char *
opt_str(char *key, int ac, char **av, char *def)
{
	int i;

	i = opt_idx(key, ac, av);
	if(i < 0 || i+1 >= ac) return def;
	return av[i+1];
}

int
opt_int(char *key, int ac, char **av, int def)
{
	char *s;

	if((s = opt_str(key, ac, av, NULL)) == NULL) return def;
	return strtol(s, NULL, 0);
}

struct out_rec{
	int smp_freq, smp_cnt;
	int bit_len;
	int sign;
	int ch_num;
	FILE *fp;

	int base;
	int amp;
	int iv_min;
	int iv_max;
};

void
out_init(struct out_rec *ot, int ac, char **av)
{
	char cmd[1024], *fn;

	ot->smp_freq = opt_int("-r", ac, av, 8000);
	ot->smp_cnt = 0;
	ot->bit_len = opt_int("-b", ac, av, 8);
	if(ot->bit_len != 8 && ot->bit_len != 16) ERR("bit_len");
	ot->sign = (opt_idx("-s", ac, av) >= 0);
	ot->ch_num = opt_int("-c", ac, av, 1);

	ot->fp = stdout;
	cmd[0] = '\0';
	fn = "";
	if(opt_idx("-play", ac, av) >= 0){
		strcat(cmd, "play");
	}else if(opt_idx("-sox", ac, av) >= 0){
		strcat(cmd, "sox");
		fn = opt_str("-sox", ac, av, "-d");
	}
	if(cmd[0]){
		sprintf(cmd + strlen(cmd), " -t raw -r %d -b %d %s -c %d - %s",
			ot->smp_freq, ot->bit_len,
			ot->sign ? "-s" : "-u",
			ot->ch_num, fn);
		if((ot->fp = popen(cmd, "w")) == NULL) ERR("popen");
	}
	ot->amp = ot->bit_len == 8 ? 127 : 32767;
	ot->base = ot->sign ? 0 : ot->amp + 1;
	ot->iv_min = ot->base - (ot->amp + 1);
	ot->iv_max = ot->base + ot->amp;
}

void
out_do(struct out_rec *ot, double v)
{
	int iv;

	iv = ot->base + (int)(v *ot->amp);
	if(iv > ot->iv_max) iv = ot->iv_max;
	if(iv < ot->iv_min) iv = ot->iv_min;
	switch(ot->bit_len){
	case 8:
		fputc(iv, ot->fp);
		break;
	case 16:
		fputc(iv & 0xff, ot->fp);
		fputc((iv >> 8) & 0xff, ot->fp);
		break;
	}
}

#define WAVE_SIN	0
#define WAVE_SAW	1
#define WAVE_SQUARE	2
#define WAVE_NOISE	3

double
wave_out(int wave, double cycle)
{
	cycle -= (int)cycle;

	switch(wave){
	case WAVE_SIN:
		return sin(2 * M_PI * cycle);
	case WAVE_SAW:
		cycle *= 2;
		if(cycle > 1) cycle -= 2;
		return cycle;
	case WAVE_SQUARE:
		return cycle < 0.5 ? 1 : -1;
	case WAVE_NOISE:
		return ((double)rand() / RAND_MAX) * 2 - 1;
	}
	return 0;
}

struct env_rec{
	double attack;	/* sec */
	double decay;	/* sec */
	double sustain;	/* 0..1 */
	double release;	/* sec */
};

void
env_set(struct env_rec *e, double a, double d, double s, double r)
{
	e->attack = a;
	e->decay = d;
	e->sustain = s;
	e->release = r;
}

struct tone_rec{
	int wave;
	double lpf_freq, lpf_Q;
	struct env_rec env;
	double level;
} tone_inf[] = {
	{	/* strings */
		WAVE_SAW,
		3000, 1.5,
		{ 0.15, 0.5, 0.8, 0.5 },
		0.7
	},{	/* bass */
		WAVE_SAW,
		1000, 1.5,
		{ 0.05, 0.2, 0.4, 0.2 },
		0.7
	},{	/* lead */
		WAVE_SQUARE,
		2000, 4,
		{ 0.01, 0.2, 0.8, 0.3 },
		0.7
	},{	/* SIN */
		WAVE_SIN,
		20000, 0.8,
		{ 0, 0.3, 0.2, 0.3 },
		1.0
	}
}, drum_tone_inf[] = {
	{	/* bass */
		WAVE_NOISE,
		400, 1,
		{ 0.01, 0.18, 0, 0.18 },
		7.0
	},{	/* snare */
		WAVE_NOISE,
		1000, 1.7,
		{ 0, 0.3, 0.3, 0.3 },
		5.0
	},{	/* tom */
		WAVE_NOISE,
		800, 2,
		{ 0, 0.3, 2, 0.4 },
		1.0
	},{	/* hi-hat close */
		WAVE_NOISE,
		16000, 2,
		{ 0, 0.1, 0, 0.1 },
		1.0
	},{	/* hi-hat open */
		WAVE_NOISE,
		16000, 2,
		{ 0, 0, 1, 0.3 },
		1.0
	},{	/* cymbal */
		WAVE_NOISE,
		5000, 3,
		{ 0, 0.3, 0.3, 1 },
		1.0
	}
};

struct tone_rec *
tone_get(int prog, int note, double *ret_freq)
{
	int idx;
	struct tone_rec *ret;

	idx = -1;
	if(prog <= 0){ /* drum part */
		switch(note){
		case 36: /* bass drum1 */
			idx = 0;
			note = 28;
			break;
		case 37: /* side stick */
		case 40: /* electric snare */
			idx = 1;
			note = 69;
			break;
		case 41: /* low floor tom */
			idx = 2;
			note = 50;
			break;
		case 42: /* closed hi-hat */
			idx = 3;
			note = 115;
			break;
		case 46: /* open hi-hat */
			idx = 4;
			note = 115;
			break;
		case 49: /* crash cymbal 1 */
		case 57: /* crash cymbal 2 */
			idx = 5;
			note = 80;
			break;
		}
		ret = idx < 0 ? NULL : &drum_tone_inf[idx];
	}else{
		switch(prog){
		case 48: /* timpani */
		case 50: /* strings ensamble 2 */
			idx = 0;
			break;
		case 35: /* electric bass (pick) */
			idx = 1;
			break;
		case 79: /* whistle */
		case 81: /* lead 1 (square) */
		case 87: /* lead 7 (fifths) */
			idx = 2;
			break;
		case 24: /* tango accordion */
		case 67: /* tenor sax */
		default:
			idx = 3;
			break;
		}
		ret = &tone_inf[idx];
	}
	if(ret_freq) *ret_freq = note_to_freq(note);
	return ret;
}

#define MIDI_CH_N	16
struct ch_rec{
	int vol;
	int pan;
	int bend;
	int rpn;
	int bend_range;
	int prog;
} ch_inf[ MIDI_CH_N ];

#define CH_PROG(ch)	( (ch) == 9 ? 0 : ch_inf[ch].prog )

double
env_out(struct note_rec *nt)
{
	struct tone_rec *tn;
	struct env_rec *e;
	double sec, v;

	if((tn = tone_get(CH_PROG(nt->ch), nt->note, NULL)) == NULL) return 0;
	e = &tn->env;
	sec = nt->sec;
	if(nt->onoff){
		sec -= nt->on_sec;
		if(sec < e->attack){
			v = sec / e->attack;
			return log10(1 + v * 9);
		}
		sec -= e->attack;
		if(sec < e->decay){
			v = sec / e->decay;
			v = log10(1 + v * 9);
			return 1 - v * (1 - e->sustain);
		}
		return e->sustain;
	}
	sec -= nt->off_sec;
	if(sec < e->release){
		v = sec / e->release;
		v = log10(1 + v * 9);
		return (1 - v) * nt->off_v;
	}
	return 0;
}

void
data_out(struct out_rec *ot, double evt_sec)
{
	double v, sec, freq, dsec;
	double vl, vr, pan;
	int i, nch;
	struct note_rec *nt;
	struct tone_rec *tn;

	while((sec = (double)ot->smp_cnt / ot->smp_freq) < evt_sec){
		vl = vr = 0;
		for(i=0; i<NOTE_BUF_N; i++){
			if(note_buf_is_free(i)) continue;
			nt = &note_buf[i];
			nch = nt->ch;
			tn = tone_get(CH_PROG(nch), nt->note, &freq);
			if(tn == NULL) continue;
			if(ch_inf[nch].bend != 0) freq *= pow(2, ch_inf[nch].bend / 8192.0 * ch_inf[nch].bend_range / 12);
			dsec = sec - nt->on_sec;
			if(dsec > 0.3) freq *= pow(2, sin(2 * M_PI * 6 * dsec) / (12 * 4) );
			nt->cycle += freq * (sec - nt->sec);
			nt->sec = sec;
			nt->freq = freq;
			v = wave_out(tn->wave, nt->cycle);
			if(nt->lpf.idx < 0) lpf_init(&nt->lpf, ot->smp_freq, tn->lpf_freq, tn->lpf_Q);
			v = lpf_out(&nt->lpf, v);
			v *= env_out(&note_buf[i]) * tn->level;
			v *= nt->velo / 127.0;
			v *= ch_inf[nch].vol / (double)((1<<14)-1);
			if(ot->ch_num == 1){
				vl += v;
			}else{
				pan = ch_inf[nch].pan / (double)(1<<14);
				vl += (1 - pan) * v;
				vr += pan * v;
			}
			if(nt->onoff == 0 && sec - nt->off_sec >= tn->env.release) note_buf_free(i);
		}
		out_do(ot, vl / 16);
		if(ot->ch_num > 1) out_do(ot, vr / 16);
		ot->smp_cnt++;
	}
}

void
note_onoff(int onoff, double evt_sec, int ch, int note, int velo)
{
	int i;

	if(onoff){
		if((i = note_buf_search(-1, -1, -1)) < 0){
			MSG("note_buf full");
			return;
		}
		note_buf[i].note = note;
		note_buf[i].ch = ch;
		note_buf[i].onoff = 1;
		note_buf[i].on_sec = evt_sec;
		note_buf[i].velo = velo;
		note_buf[i].cycle = 0;
		note_buf[i].sec = evt_sec;
		note_buf[i].lpf.idx = -1;
	}else{
		if((i = note_buf_search(ch, note, 1)) < 0) return;
		note_buf[i].off_v = env_out(&note_buf[i]);
		note_buf[i].onoff = 0;
		note_buf[i].off_sec = evt_sec;
	}
}

void
msb_set(int *vp, int v)
{
	*vp &= ~(127<<7);
	*vp |= v<<7;
}

void
lsb_set(int *vp, int v)
{
	*vp &= ~127;
	*vp |= v;
}

void
bend_note_update(int ch, double sec)
{
	int i;
	struct note_rec *nt;

	for(i=0; ich != ch) continue;
		nt->cycle += nt->freq * (sec - nt->sec);
		nt->sec = sec;
	}
}

int
main(int ac, char **av)
{
	int div4, delta_sum;
	int i, n, v, hi, low, note, velo;
	int ch, type;
	double sec;
	struct out_rec otr;
	int tempo, tempo_delta_sum;
	double tempo_sec;

	out_init(&otr, ac, av);
	note_buf_init();
	for(i=0; i<MIDI_CH_N; i++){
		ch_inf[i].vol = 0;
		ch_inf[i].pan = 1<<(14-1);
		ch_inf[i].bend = 0;
		ch_inf[i].rpn = 0;
		ch_inf[i].bend_range = 2;
		ch_inf[i].prog =-1;
	}
	tempo = 500000;
	tempo_delta_sum = 0;
	tempo_sec = 0;

	div4 = header();

	if(!rd_str_chk(4, "MTrk")) ERR("track id");
	v = rd_int(4); /* skip */

	hi = low = 0;
	delta_sum = 0;
	while((v = rd_delta()) != EOF){
		delta_sum += v;
		sec = tempo_sec + (double)(delta_sum - tempo_delta_sum) / div4 * tempo * 0.000001;
		
		if((v = rd()) & 0x80){
			hi = (v >> 4) & 0xf;
			low  = v & 0xf;
		}else bk(v);

		data_out(&otr, sec);

		ch = low;
		switch(hi){
		case 8:
		case 9:
			note = rd();
			velo = rd();
			note_onoff(hi == 9, sec, ch, note, velo);
			break;
		case 0xb: /* control change */
			type = rd();
			v = rd();
			switch(type){
			case 7: /* channel volume msb */
				msb_set(&ch_inf[ch].vol, v);
				break;
			case 39: /* channel volume lsb */
				lsb_set(&ch_inf[ch].vol, v);
				break;
			case 10: /* pan msb */
				msb_set(&ch_inf[ch].pan, v);
				break;
			case 42: /* pan lsb */
				lsb_set(&ch_inf[ch].pan, v);
				break;
			case 100: /* rpn lsb */
				lsb_set(&ch_inf[ch].rpn, v);
				break;
			case 101: /* rpn msb */
				msb_set(&ch_inf[ch].rpn, v);
				break;
			case 6: /* data entry msb */
				switch(ch_inf[ch].rpn){
				case 0: /* pitch bend range */
					ch_inf[ch].bend_range = v;
					break;
				}
				break;
			}
			break;
		case 0xa:
			rd();
			rd();
			break;
		case 0xe: /* pitch wheel change */
			bend_note_update(ch, sec);
			v = rd();
			v |= rd() << 7;
			ch_inf[ch].bend = v - 8192;
			break;
		case 0xc: /* program number */
			v = rd();
			ch_inf[ch].prog = v;
			break;
		case 0xd:
			rd();
			break;
		case 0xf:
			type = rd();
			switch(low){
			case 0:
				while(rd() != 0xf7);
				break;
			case 1:
			case 3:
				rd();
				break;
			case 2:
				rd();
				rd();
				break;
			case 0xf: /* meta */
				n = rd();
				switch(type){
				case 0x51: /* set tempo */
					v = rd_int(n);
					tempo = v;
					tempo_delta_sum = delta_sum;
					tempo_sec = sec;
					break;
				default:
					for(i=0; i<n; i++) rd();
					break;
				}
				break;
			default:
				break;
			}
			break;
		}
	}
	if(otr.fp != stdout) pclose(otr.fp);
	return 0;
}

/* EOF */


#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <math.h>

#define MSG(s) fprintf(stderr, "%s() %s L%d : %s\n", __func__, __FILE__, __LINE__, s)
#define ERR(s) do{ fprintf(stderr, "ERR "); MSG(s); exit(1); }while(0)

int bk_buf = -1;

int
rd(void)
{
	int v;

	if((v = bk_buf) < 0) return getchar();
	bk_buf = -1;
	return v;
}

void
bk(int v)
{
	if(bk_buf >= 0) ERR("give up");
	bk_buf = v;
}

void
rd_str(int n, char *s)
{
	int i;

	for(i=0; i<n; i++) s[i] = rd();
	s[i] = '\0';
}

int
rd_str_chk(int n, char *s)
{
	char buf[256];

	rd_str(n, buf);
	return strcmp(buf, s) == 0;
}

int
rd_int(int n) /* big endian */
{
	int i, v;

	v = 0;
	for(i=0; i<n; i++) v = (v << 8) | rd();
	return v;
}

int
rd_delta(void)
{
	int v, c;

	v = 0;
	do{
		if((c = rd()) == EOF) return EOF;
		v = (v << 7) | (c & 0x7f);
	}while(c & 0x80);
	return v;
}


struct lpf_rec{
	int idx;
	double in[4], out[4];
	double a0, a1, a2, b0, b1, b2, div_a0;
};
// LPF 構造体定義
//
// メンバはフィルタの計算で使うパラメータばかり
//
// カット・オフ周波数や、レゾナンス(Q値)の値は、
// 初期化時に指定して、メンバに反映させる

void
lpf_init(struct lpf_rec *lpf, double smp_freq, double freq, double Q)
{
	// LPF 構造体の初期化
	//
	// smp_freq は、サンプリング周波数
	// freq は、LPF のカット・オフ周波数
	// Q は、LPF のレゾナンス(Q値)
	
	int i;
	double w0, alpha;

	for(i=0; i<4; i++) lpf->in[i] = lpf->out[i] = 0;
	lpf->idx = 0;

	w0 = 2 * M_PI * freq / smp_freq;
	alpha = sin(w0) / (2 * Q);
	lpf->b1 = 1 - cos(w0);
	lpf->b0 = lpf->b2 = lpf->b1 * 0.5;
	lpf->a0 = 1 + alpha;
	lpf->a1 = -2 * cos(w0);
	lpf->a2 = 1 - alpha;
	if(lpf->a0 != 0) lpf->div_a0 = 1 / lpf->a0;
}

double
lpf_out(struct lpf_rec *lpf, double in)
{
	// LPF のフィルタ処理
	//
	// in は入力
	// フィルタを施した結果の出力値を返す
	
	double *out_p;
	int i_1, i_2;

	lpf->in[lpf->idx] = in;
	out_p = &lpf->out[lpf->idx];

	if(lpf->a0 != 0){
		i_1 = (lpf->idx + 4 - 1) & 3;
		i_2 = (i_1 + 4 - 1) & 3;
		*out_p = (lpf->b0 * in
			+ lpf->b1 * lpf->in[i_1]
			+ lpf->b2 * lpf->in[i_2]
			- lpf->a1 * lpf->out[i_1]
			- lpf->a2 * lpf->out[i_2] ) * lpf->div_a0;
	}else{
		*out_p = 0;
	}
	lpf->idx = (lpf->idx + 1) & 3;
	return *out_p;
}


#define NOTE_BUF_N	256

struct note_rec{
	int ch;
	int note;
	int onoff;
	double on_sec;
	double off_sec;
	int velo;
	double cycle, sec, freq;
	double off_v;
	struct lpf_rec lpf;
	// LPFの構造体を追加
	
} note_buf[NOTE_BUF_N];

int
note_buf_is_free(int i)
{
	return note_buf[i].ch < 0;
}

void
note_buf_free(int i)
{
	note_buf[i].ch = -1;
}

void
note_buf_init(void)
{
	int i;

	for(i=0; i<NOTE_BUF_N; i++) note_buf_free(i);
}

int
note_buf_search(int ch, int note, int onoff)
{
	int i;

	for(i=0; i<NOTE_BUF_N; i++) {
		if( (ch < 0 && note_buf[i].ch < 0) ||
		    (note_buf[i].ch == ch &&
		     note_buf[i].note == note &&
		     note_buf[i].onoff == onoff) ) return i;
	}
	return -1;
}

int
header(void)
{
	int v;

	if(!rd_str_chk(4, "MThd")) ERR("header id");
	if(rd_int(4) != 6) ERR("header size");
	if(rd_int(2) != 0) ERR("header format type");
	if(rd_int(2) != 1) ERR("header track num");
	if((v = rd_int(2)) & 0x8000) ERR("header division");
	return v; /* div4 */
}

double
note_to_freq(int note)
{
	return 440 * pow(2, (note - 69) / 12.0);
}

int
opt_idx(char *key, int ac, char **av)
{
	int i;

	for(i=1; i<ac; i++) if(strcmp(av[i], key) == 0) return i;
	return -1;
}

char *
opt_str(char *key, int ac, char **av, char *def)
{
	int i;

	i = opt_idx(key, ac, av);
	if(i < 0 || i+1 >= ac) return def;
	return av[i+1];
}

int
opt_int(char *key, int ac, char **av, int def)
{
	char *s;

	if((s = opt_str(key, ac, av, NULL)) == NULL) return def;
	return strtol(s, NULL, 0);
}

struct out_rec{
	int smp_freq, smp_cnt;
	int bit_len;
	int sign;
	int ch_num;
	FILE *fp;

	int base;
	int amp;
	int iv_min;
	int iv_max;
};

void
out_init(struct out_rec *ot, int ac, char **av)
{
	char cmd[1024], *fn;

	ot->smp_freq = opt_int("-r", ac, av, 8000);
	ot->smp_cnt = 0;
	ot->bit_len = opt_int("-b", ac, av, 8);
	if(ot->bit_len != 8 && ot->bit_len != 16) ERR("bit_len");
	ot->sign = (opt_idx("-s", ac, av) >= 0);
	ot->ch_num = opt_int("-c", ac, av, 1);

	ot->fp = stdout;
	cmd[0] = '\0';
	fn = "";
	if(opt_idx("-play", ac, av) >= 0){
		strcat(cmd, "play");
	}else if(opt_idx("-sox", ac, av) >= 0){
		strcat(cmd, "sox");
		fn = opt_str("-sox", ac, av, "-d");
	}
	if(cmd[0]){
		sprintf(cmd + strlen(cmd), " -t raw -r %d -b %d %s -c %d - %s",
			ot->smp_freq, ot->bit_len,
			ot->sign ? "-s" : "-u",
			ot->ch_num, fn);
		if((ot->fp = popen(cmd, "w")) == NULL) ERR("popen");
	}
	ot->amp = ot->bit_len == 8 ? 127 : 32767;
	ot->base = ot->sign ? 0 : ot->amp + 1;
	ot->iv_min = ot->base - (ot->amp + 1);
	ot->iv_max = ot->base + ot->amp;
}

void
out_do(struct out_rec *ot, double v)
{
	int iv;

	iv = ot->base + (int)(v *ot->amp);
	if(iv > ot->iv_max) iv = ot->iv_max;
	if(iv < ot->iv_min) iv = ot->iv_min;
	switch(ot->bit_len){
	case 8:
		fputc(iv, ot->fp);
		break;
	case 16:
		fputc(iv & 0xff, ot->fp);
		fputc((iv >> 8) & 0xff, ot->fp);
		break;
	}
}

#define WAVE_SIN	0
#define WAVE_SAW	1
#define WAVE_SQUARE	2
#define WAVE_NOISE	3

double
wave_out(int wave, double cycle)
{
	cycle -= (int)cycle;

	switch(wave){
	case WAVE_SIN:
		return sin(2 * M_PI * cycle);
	case WAVE_SAW:
		cycle *= 2;
		if(cycle > 1) cycle -= 2;
		return cycle;
	case WAVE_SQUARE:
		return cycle < 0.5 ? 1 : -1;
	case WAVE_NOISE:
		return ((double)rand() / RAND_MAX) * 2 - 1;
	}
	return 0;
}

struct env_rec{
	double attack;	/* sec */
	double decay;	/* sec */
	double sustain;	/* 0..1 */
	double release;	/* sec */
};

void
env_set(struct env_rec *e, double a, double d, double s, double r)
{
	e->attack = a;
	e->decay = d;
	e->sustain = s;
	e->release = r;
}

struct tone_rec{
	int wave;
	double lpf_freq, lpf_Q;
	// LPF のカット・オフ周波数と
	// LPF のレゾナンス(Q値)を追加
	
	struct env_rec env;
	double level;
} tone_inf[] = {
	{	/* strings */
		WAVE_SAW,
		3000, 1.5,
		{ 0.15, 0.5, 0.8, 0.5 },
		0.7
	},{	/* bass */
		WAVE_SAW,
		1000, 1.5,
		{ 0.05, 0.2, 0.4, 0.2 },
		0.7
	},{	/* lead */
		WAVE_SQUARE,
		2000, 4,
		{ 0.01, 0.2, 0.8, 0.3 },
		0.7
	},{	/* SIN */
		WAVE_SIN,
		20000, 0.8,
		{ 0, 0.3, 0.2, 0.3 },
		1.0
	}
}, drum_tone_inf[] = {
	{	/* bass */
		WAVE_NOISE,
		400, 1,
		{ 0.01, 0.18, 0, 0.18 },
		7.0
	},{	/* snare */
		WAVE_NOISE,
		1000, 1.7,
		{ 0, 0.3, 0.3, 0.3 },
		5.0
	},{	/* tom */
		WAVE_NOISE,
		800, 2,
		{ 0, 0.3, 2, 0.4 },
		1.0
	},{	/* hi-hat close */
		WAVE_NOISE,
		16000, 2,
		{ 0, 0.1, 0, 0.1 },
		1.0
	},{	/* hi-hat open */
		WAVE_NOISE,
		16000, 2,
		{ 0, 0, 1, 0.3 },
		1.0
	},{	/* cymbal */
		WAVE_NOISE,
		5000, 3,
		{ 0, 0.3, 0.3, 1 },
		1.0
	}
};

struct tone_rec *
tone_get(int prog, int note, double *ret_freq)
{
	int idx;
	struct tone_rec *ret;

	idx = -1;
	if(prog <= 0){ /* drum part */
		switch(note){
		case 36: /* bass drum1 */
			idx = 0;
			note = 28;
			break;
		case 37: /* side stick */
		case 40: /* electric snare */
			idx = 1;
			note = 69;
			break;
		case 41: /* low floor tom */
			idx = 2;
			note = 50;
			break;
		case 42: /* closed hi-hat */
			idx = 3;
			note = 115;
			break;
		case 46: /* open hi-hat */
			idx = 4;
			note = 115;
			break;
		case 49: /* crash cymbal 1 */
		case 57: /* crash cymbal 2 */
			idx = 5;
			note = 80;
			break;
		}
		ret = idx < 0 ? NULL : &drum_tone_inf[idx];
	}else{
		switch(prog){
		case 48: /* timpani */
		case 50: /* strings ensamble 2 */
			idx = 0;
			break;
		case 35: /* electric bass (pick) */
			idx = 1;
			break;
		case 79: /* whistle */
		case 81: /* lead 1 (square) */
		case 87: /* lead 7 (fifths) */
			idx = 2;
			break;
		case 24: /* tango accordion */
		case 67: /* tenor sax */
		default:
			idx = 3;
			break;
		}
		ret = &tone_inf[idx];
	}
	if(ret_freq) *ret_freq = note_to_freq(note);
	return ret;
}

#define MIDI_CH_N	16
struct ch_rec{
	int vol;
	int pan;
	int bend;
	int rpn;
	int bend_range;
	int prog;
} ch_inf[ MIDI_CH_N ];

#define CH_PROG(ch)	( (ch) == 9 ? 0 : ch_inf[ch].prog )

double
env_out(struct note_rec *nt)
{
	struct tone_rec *tn;
	struct env_rec *e;
	double sec, v;

	if((tn = tone_get(CH_PROG(nt->ch), nt->note, NULL)) == NULL) return 0;
	e = &tn->env;
	sec = nt->sec;
	if(nt->onoff){
		sec -= nt->on_sec;
		if(sec < e->attack){
			v = sec / e->attack;
			return log10(1 + v * 9);
		}
		sec -= e->attack;
		if(sec < e->decay){
			v = sec / e->decay;
			v = log10(1 + v * 9);
			return 1 - v * (1 - e->sustain);
		}
		return e->sustain;
	}
	sec -= nt->off_sec;
	if(sec < e->release){
		v = sec / e->release;
		v = log10(1 + v * 9);
		return (1 - v) * nt->off_v;
	}
	return 0;
}

void
data_out(struct out_rec *ot, double evt_sec)
{
	double v, sec, freq, dsec;
	double vl, vr, pan;
	int i, nch;
	struct note_rec *nt;
	struct tone_rec *tn;

	while((sec = (double)ot->smp_cnt / ot->smp_freq) < evt_sec){
		vl = vr = 0;
		for(i=0; i<NOTE_BUF_N; i++){
			if(note_buf_is_free(i)) continue;
			nt = &note_buf[i];
			nch = nt->ch;
			tn = tone_get(CH_PROG(nch), nt->note, &freq);
			if(tn == NULL) continue;
			if(ch_inf[nch].bend != 0) freq *= pow(2, ch_inf[nch].bend / 8192.0 * ch_inf[nch].bend_range / 12);
			dsec = sec - nt->on_sec;
			if(dsec > 0.3) freq *= pow(2, sin(2 * M_PI * 6 * dsec) / (12 * 4) );
			nt->cycle += freq * (sec - nt->sec);
			nt->sec = sec;
			nt->freq = freq;
			v = wave_out(tn->wave, nt->cycle);
			if(nt->lpf.idx < 0) lpf_init(&nt->lpf, ot->smp_freq, tn->lpf_freq, tn->lpf_Q);
			// LPF構造体が、初期化済でなければ、初期化する
			
			v = lpf_out(&nt->lpf, v);
			// LPF のフィルタ処理
			
			v *= env_out(&note_buf[i]) * tn->level;
			v *= nt->velo / 127.0;
			v *= ch_inf[nch].vol / (double)((1<<14)-1);
			if(ot->ch_num == 1){
				vl += v;
			}else{
				pan = ch_inf[nch].pan / (double)(1<<14);
				vl += (1 - pan) * v;
				vr += pan * v;
			}
			if(nt->onoff == 0 && sec - nt->off_sec >= tn->env.release) note_buf_free(i);
		}
		out_do(ot, vl / 16);
		if(ot->ch_num > 1) out_do(ot, vr / 16);
		ot->smp_cnt++;
	}
}

void
note_onoff(int onoff, double evt_sec, int ch, int note, int velo)
{
	int i;

	if(onoff){
		if((i = note_buf_search(-1, -1, -1)) < 0){
			MSG("note_buf full");
			return;
		}
		note_buf[i].note = note;
		note_buf[i].ch = ch;
		note_buf[i].onoff = 1;
		note_buf[i].on_sec = evt_sec;
		note_buf[i].velo = velo;
		note_buf[i].cycle = 0;
		note_buf[i].sec = evt_sec;
		note_buf[i].lpf.idx = -1;
		// LPF構造体に、未初期化のマークをつけておく
		//
		// ここで、lpf_init() を呼び出して初期化しておきたい
		// ところだが、
		// struct out_rec の smp_freq へアクセスできなかったり、
		// 音色の構造体を取得が必要なので、
		// 未初期化のマークだけつけておく
		//
		// 実際の初期化は、data_out() 関数の中で行なう
		
	}else{
		if((i = note_buf_search(ch, note, 1)) < 0) return;
		note_buf[i].off_v = env_out(&note_buf[i]);
		note_buf[i].onoff = 0;
		note_buf[i].off_sec = evt_sec;
	}
}

void
msb_set(int *vp, int v)
{
	*vp &= ~(127<<7);
	*vp |= v<<7;
}

void
lsb_set(int *vp, int v)
{
	*vp &= ~127;
	*vp |= v;
}

void
bend_note_update(int ch, double sec)
{
	int i;
	struct note_rec *nt;

	for(i=0; ich != ch) continue;
		nt->cycle += nt->freq * (sec - nt->sec);
		nt->sec = sec;
	}
}

int
main(int ac, char **av)
{
	int div4, delta_sum;
	int i, n, v, hi, low, note, velo;
	int ch, type;
	double sec;
	struct out_rec otr;
	int tempo, tempo_delta_sum;
	double tempo_sec;

	out_init(&otr, ac, av);
	note_buf_init();
	for(i=0; i<MIDI_CH_N; i++){
		ch_inf[i].vol = 0;
		ch_inf[i].pan = 1<<(14-1);
		ch_inf[i].bend = 0;
		ch_inf[i].rpn = 0;
		ch_inf[i].bend_range = 2;
		ch_inf[i].prog =-1;
	}
	tempo = 500000;
	tempo_delta_sum = 0;
	tempo_sec = 0;

	div4 = header();

	if(!rd_str_chk(4, "MTrk")) ERR("track id");
	v = rd_int(4); /* skip */

	hi = low = 0;
	delta_sum = 0;
	while((v = rd_delta()) != EOF){
		delta_sum += v;
		sec = tempo_sec + (double)(delta_sum - tempo_delta_sum) / div4 * tempo * 0.000001;
		
		if((v = rd()) & 0x80){
			hi = (v >> 4) & 0xf;
			low  = v & 0xf;
		}else bk(v);

		data_out(&otr, sec);

		ch = low;
		switch(hi){
		case 8:
		case 9:
			note = rd();
			velo = rd();
			note_onoff(hi == 9, sec, ch, note, velo);
			break;
		case 0xb: /* control change */
			type = rd();
			v = rd();
			switch(type){
			case 7: /* channel volume msb */
				msb_set(&ch_inf[ch].vol, v);
				break;
			case 39: /* channel volume lsb */
				lsb_set(&ch_inf[ch].vol, v);
				break;
			case 10: /* pan msb */
				msb_set(&ch_inf[ch].pan, v);
				break;
			case 42: /* pan lsb */
				lsb_set(&ch_inf[ch].pan, v);
				break;
			case 100: /* rpn lsb */
				lsb_set(&ch_inf[ch].rpn, v);
				break;
			case 101: /* rpn msb */
				msb_set(&ch_inf[ch].rpn, v);
				break;
			case 6: /* data entry msb */
				switch(ch_inf[ch].rpn){
				case 0: /* pitch bend range */
					ch_inf[ch].bend_range = v;
					break;
				}
				break;
			}
			break;
		case 0xa:
			rd();
			rd();
			break;
		case 0xe: /* pitch wheel change */
			bend_note_update(ch, sec);
			v = rd();
			v |= rd() << 7;
			ch_inf[ch].bend = v - 8192;
			break;
		case 0xc: /* program number */
			v = rd();
			ch_inf[ch].prog = v;
			break;
		case 0xd:
			rd();
			break;
		case 0xf:
			type = rd();
			switch(low){
			case 0:
				while(rd() != 0xf7);
				break;
			case 1:
			case 3:
				rd();
				break;
			case 2:
				rd();
				rd();
				break;
			case 0xf: /* meta */
				n = rd();
				switch(type){
				case 0x51: /* set tempo */
					v = rd_int(n);
					tempo = v;
					tempo_delta_sum = delta_sum;
					tempo_sec = sec;
					break;
				default:
					for(i=0; i<n; i++) rd();
					break;
				}
				break;
			default:
				break;
			}
			break;
		}
	}
	if(otr.fp != stdout) pclose(otr.fp);
	return 0;
}

/* EOF */


prog13.c 解説

prog12.c からの変更箇所のみ

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <math.h>

#define MSG(s) fprintf(stderr, "%s() %s L%d : %s\n", __func__, __FILE__, __LINE__, s)
#define ERR(s) do{ fprintf(stderr, "ERR "); MSG(s); exit(1); }while(0)

int bk_buf = -1;

int
rd(void)
{
	int v;

	if((v = bk_buf) < 0) return getchar();
	bk_buf = -1;
	return v;
}

void
bk(int v)
{
	if(bk_buf >= 0) ERR("give up");
	bk_buf = v;
}

void
rd_str(int n, char *s)
{
	int i;

	for(i=0; i<n; i++) s[i] = rd();
	s[i] = '\0';
}

int
rd_str_chk(int n, char *s)
{
	char buf[256];

	rd_str(n, buf);
	return strcmp(buf, s) == 0;
}

int
rd_int(int n) /* big endian */
{
	int i, v;

	v = 0;
	for(i=0; i<n; i++) v = (v << 8) | rd();
	return v;
}

int
rd_delta(void)
{
	int v, c;

	v = 0;
	do{
		if((c = rd()) == EOF) return EOF;
		v = (v << 7) | (c & 0x7f);
	}while(c & 0x80);
	return v;
}


struct lpf_rec{
	int idx;
	double in[4], out[4];
	double a0, a1, a2, b0, b1, b2, div_a0;
};

void
lpf_update(struct lpf_rec *lpf, double smp_freq, double freq, double Q)
{
	double w0, alpha;

	w0 = 2 * M_PI * freq / smp_freq;
	alpha = sin(w0) / (2 * Q);
	lpf->b1 = 1 - cos(w0);
	lpf->b0 = lpf->b2 = lpf->b1 * 0.5;
	lpf->a0 = 1 + alpha;
	lpf->a1 = -2 * cos(w0);
	lpf->a2 = 1 - alpha;
	if(lpf->a0 != 0) lpf->div_a0 = 1 / lpf->a0;
}

void
lpf_init(struct lpf_rec *lpf, double smp_freq, double freq, double Q)
{
	int i;


	for(i=0; i<4; i++) lpf->in[i] = lpf->out[i] = 0;
	lpf->idx = 0;

	lpf_update(lpf, smp_freq, freq, Q);
}

double
lpf_out(struct lpf_rec *lpf, double in)
{
	double *out_p;
	int i_1, i_2;

	lpf->in[lpf->idx] = in;
	out_p = &lpf->out[lpf->idx];

	if(lpf->a0 != 0){
		i_1 = (lpf->idx + 4 - 1) & 3;
		i_2 = (i_1 + 4 - 1) & 3;
		*out_p = (lpf->b0 * in
			+ lpf->b1 * lpf->in[i_1]
			+ lpf->b2 * lpf->in[i_2]
			- lpf->a1 * lpf->out[i_1]
			- lpf->a2 * lpf->out[i_2] ) * lpf->div_a0;
	}else{
		*out_p = 0;
	}
	lpf->idx = (lpf->idx + 1) & 3;
	return *out_p;
}


#define NOTE_BUF_N	256

struct note_rec{
	int ch;
	int note;
	int onoff;
	double on_sec;
	double off_sec;
	int velo;
	double cycle, sec, freq;
	double off_v;
	struct lpf_rec lpf;
} note_buf[NOTE_BUF_N];

int
note_buf_is_free(int i)
{
	return note_buf[i].ch < 0;
}

void
note_buf_free(int i)
{
	note_buf[i].ch = -1;
}

void
note_buf_init(void)
{
	int i;

	for(i=0; i<NOTE_BUF_N; i++) note_buf_free(i);
}

int
note_buf_search(int ch, int note, int onoff)
{
	int i;

	for(i=0; i<NOTE_BUF_N; i++) {
		if( (ch < 0 && note_buf[i].ch < 0) ||
		    (note_buf[i].ch == ch &&
		     note_buf[i].note == note &&
		     note_buf[i].onoff == onoff) ) return i;
	}
	return -1;
}

int
header(void)
{
	int v;

	if(!rd_str_chk(4, "MThd")) ERR("header id");
	if(rd_int(4) != 6) ERR("header size");
	if(rd_int(2) != 0) ERR("header format type");
	if(rd_int(2) != 1) ERR("header track num");
	if((v = rd_int(2)) & 0x8000) ERR("header division");
	return v; /* div4 */
}

double
note_to_freq(int note)
{
	return 440 * pow(2, (note - 69) / 12.0);
}

int
opt_idx(char *key, int ac, char **av)
{
	int i;

	for(i=1; i<ac; i++) if(strcmp(av[i], key) == 0) return i;
	return -1;
}

char *
opt_str(char *key, int ac, char **av, char *def)
{
	int i;

	i = opt_idx(key, ac, av);
	if(i < 0 || i+1 >= ac) return def;
	return av[i+1];
}

int
opt_int(char *key, int ac, char **av, int def)
{
	char *s;

	if((s = opt_str(key, ac, av, NULL)) == NULL) return def;
	return strtol(s, NULL, 0);
}

struct out_rec{
	int smp_freq, smp_cnt;
	int bit_len;
	int sign;
	int ch_num;
	FILE *fp;

	int base;
	int amp;
	int iv_min;
	int iv_max;
};

void
out_init(struct out_rec *ot, int ac, char **av)
{
	char cmd[1024], *fn;

	ot->smp_freq = opt_int("-r", ac, av, 8000);
	ot->smp_cnt = 0;
	ot->bit_len = opt_int("-b", ac, av, 8);
	if(ot->bit_len != 8 && ot->bit_len != 16) ERR("bit_len");
	ot->sign = (opt_idx("-s", ac, av) >= 0);
	ot->ch_num = opt_int("-c", ac, av, 1);

	ot->fp = stdout;
	cmd[0] = '\0';
	fn = "";
	if(opt_idx("-play", ac, av) >= 0){
		strcat(cmd, "play");
	}else if(opt_idx("-sox", ac, av) >= 0){
		strcat(cmd, "sox");
		fn = opt_str("-sox", ac, av, "-d");
	}
	if(cmd[0]){
		sprintf(cmd + strlen(cmd), " -t raw -r %d -b %d %s -c %d - %s",
			ot->smp_freq, ot->bit_len,
			ot->sign ? "-s" : "-u",
			ot->ch_num, fn);
		if((ot->fp = popen(cmd, "w")) == NULL) ERR("popen");
	}
	ot->amp = ot->bit_len == 8 ? 127 : 32767;
	ot->base = ot->sign ? 0 : ot->amp + 1;
	ot->iv_min = ot->base - (ot->amp + 1);
	ot->iv_max = ot->base + ot->amp;
}

void
out_do(struct out_rec *ot, double v)
{
	int iv;

	iv = ot->base + (int)(v *ot->amp);
	if(iv > ot->iv_max) iv = ot->iv_max;
	if(iv < ot->iv_min) iv = ot->iv_min;
	switch(ot->bit_len){
	case 8:
		fputc(iv, ot->fp);
		break;
	case 16:
		fputc(iv & 0xff, ot->fp);
		fputc((iv >> 8) & 0xff, ot->fp);
		break;
	}
}

#define WAVE_SIN	0
#define WAVE_SAW	1
#define WAVE_SQUARE	2
#define WAVE_NOISE	3

double
wave_out(int wave, double cycle)
{
	cycle -= (int)cycle;

	switch(wave){
	case WAVE_SIN:
		return sin(2 * M_PI * cycle);
	case WAVE_SAW:
		cycle *= 2;
		if(cycle > 1) cycle -= 2;
		return cycle;
	case WAVE_SQUARE:
		return cycle < 0.5 ? 1 : -1;
	case WAVE_NOISE:
		return ((double)rand() / RAND_MAX) * 2 - 1;
	}
	return 0;
}

struct env_rec{
	double attack;	/* sec */
	double decay;	/* sec */
	double sustain;	/* 0..1 */
	double release;	/* sec */
};

void
env_set(struct env_rec *e, double a, double d, double s, double r)
{
	e->attack = a;
	e->decay = d;
	e->sustain = s;
	e->release = r;
}

struct tone_rec{
	int wave;
	double lpf_freq, lpf_Q;
	struct env_rec env;
	double level;
	int lfo_p, lfo_f;
	int lfo_wave;
	double lfo_freq, lfo_delay;
} tone_inf[] = {
	{	/* strings */
		WAVE_SAW,
		3000, 1.5,
		{ 0.15, 0.5, 0.8, 0.5 },
		0.7,
		25, 0, WAVE_SIN, 6, 0.3,
	},{	/* bass */
		WAVE_SAW,
		1000, 1.5,
		{ 0.05, 0.2, 0.4, 0.2 },
		1.0,
		60, 0, WAVE_SIN, 1.5, 0.2,
	},{	/* lead */
		WAVE_SQUARE,
		2000, 4,
		{ 0.01, 0.2, 0.8, 0.3 },
		0.5,
		10, 5, WAVE_SIN, 4, 0.3,
	},{	/* SIN */
		WAVE_SIN,
		20000, 0.8,
		{ 0, 0.3, 0.2, 0.3 },
		1.0,
		25, 0, WAVE_SIN, 6, 0.3,
	}
}, drum_tone_inf[] = {
	{	/* bass */
		WAVE_NOISE,
		400, 1,
		{ 0.01, 0.18, 0, 0.18 },
		10.0,
		0, 0, WAVE_SIN, 0, 0,
	},{	/* snare */
		WAVE_NOISE,
		1000, 1.7,
		{ 0, 0.3, 0.3, 0.3 },
		3.0,
		0, 1200, WAVE_NOISE, 0, 0,
	},{	/* tom */
		WAVE_NOISE,
		800, 2,
		{ 0, 0.3, 2, 0.4 },
		1.0,
		0, 0, WAVE_SIN, 0, 0,
	},{	/* hi-hat close */
		WAVE_NOISE,
		16000, 2,
		{ 0, 0.1, 0, 0.1 },
		0.8,
		0, 0, WAVE_SIN, 0, 0,
	},{	/* hi-hat open */
		WAVE_NOISE,
		16000, 2,
		{ 0, 0, 1, 0.3 },
		0.8,
		0, 0, WAVE_SIN, 0, 0,
	},{	/* cymbal */
		WAVE_NOISE,
		5000, 3,
		{ 0, 0.3, 0.3, 1 },
		0.8,
		0, 200, WAVE_SIN, 3, 0.3,
	}
};

struct tone_rec *
tone_get(int prog, int note, double *ret_freq)
{
	int idx;
	struct tone_rec *ret;

	idx = -1;
	if(prog <= 0){ /* drum part */
		switch(note){
		case 36: /* bass drum1 */
			idx = 0;
			note = 28;
			break;
		case 37: /* side stick */
		case 40: /* electric snare */
			idx = 1;
			note = 69;
			break;
		case 41: /* low floor tom */
			idx = 2;
			note = 50;
			break;
		case 42: /* closed hi-hat */
			idx = 3;
			note = 115;
			break;
		case 46: /* open hi-hat */
			idx = 4;
			note = 115;
			break;
		case 49: /* crash cymbal 1 */
		case 57: /* crash cymbal 2 */
			idx = 5;
			note = 80;
			break;
		}
		ret = idx < 0 ? NULL : &drum_tone_inf[idx];
	}else{
		switch(prog){
		case 48: /* timpani */
		case 50: /* strings ensamble 2 */
			idx = 0;
			break;
		case 35: /* electric bass (pick) */
			idx = 1;
			break;
		case 79: /* whistle */
		case 81: /* lead 1 (square) */
		case 87: /* lead 7 (fifths) */
			idx = 2;
			break;
		case 24: /* tango accordion */
		case 67: /* tenor sax */
		default:
			idx = 3;
			break;
		}
		ret = &tone_inf[idx];
	}
	if(ret_freq) *ret_freq = note_to_freq(note);
	return ret;
}

#define MIDI_CH_N	16
struct ch_rec{
	int vol;
	int pan;
	int bend;
	int rpn;
	int bend_range;
	int prog;
} ch_inf[ MIDI_CH_N ];

#define CH_PROG(ch)	( (ch) == 9 ? 0 : ch_inf[ch].prog )

double
env_out(struct note_rec *nt)
{
	struct tone_rec *tn;
	struct env_rec *e;
	double sec, v;

	if((tn = tone_get(CH_PROG(nt->ch), nt->note, NULL)) == NULL) return 0;
	e = &tn->env;
	sec = nt->sec;
	if(nt->onoff){
		sec -= nt->on_sec;
		if(sec < e->attack){
			v = sec / e->attack;
			return log10(1 + v * 9);
		}
		sec -= e->attack;
		if(sec < e->decay){
			v = sec / e->decay;
			v = log10(1 + v * 9);
			return 1 - v * (1 - e->sustain);
		}
		return e->sustain;
	}
	sec -= nt->off_sec;
	if(sec < e->release){
		v = sec / e->release;
		v = log10(1 + v * 9);
		return (1 - v) * nt->off_v;
	}
	return 0;
}

void
data_out(struct out_rec *ot, double evt_sec)
{
	double v, sec, freq, dsec;
	double vl, vr, pan;
	int i, nch;
	struct note_rec *nt;
	struct tone_rec *tn;
	double lfo_out;

	while((sec = (double)ot->smp_cnt / ot->smp_freq) < evt_sec){
		vl = vr = 0;
		for(i=0; i<NOTE_BUF_N; i++){
			if(note_buf_is_free(i)) continue;
			nt = &note_buf[i];
			nch = nt->ch;
			tn = tone_get(CH_PROG(nch), nt->note, &freq);
			if(tn == NULL) continue;

			if(ch_inf[nch].bend != 0) freq *= pow(2, ch_inf[nch].bend / 8192.0 * ch_inf[nch].bend_range / 12);
			dsec = sec - nt->on_sec - tn->lfo_delay;
			if((tn->lfo_p || tn->lfo_f) && dsec > 0){
				lfo_out = wave_out(tn->lfo_wave, tn->lfo_freq * dsec);
			}
			if(tn->lfo_p && dsec > 0) freq *= pow(2, lfo_out * (tn->lfo_p / 100.0) / 12);
			nt->cycle += freq * (sec - nt->sec);
			nt->sec = sec;
			nt->freq = freq;
			v = wave_out(tn->wave, nt->cycle);

			if(nt->lpf.idx < 0) lpf_init(&nt->lpf, ot->smp_freq, tn->lpf_freq, tn->lpf_Q);
			if(tn->lfo_f && dsec > 0){
				freq = tn->lpf_freq * pow(2, lfo_out * (tn->lfo_f / 100.0) / 12);
				lpf_update(&nt->lpf, ot->smp_freq, freq, tn->lpf_Q);
			}
			v = lpf_out(&nt->lpf, v);

			v *= env_out(&note_buf[i]) * tn->level;
			v *= nt->velo / 127.0;
			v *= ch_inf[nch].vol / (double)((1<<14)-1);
			if(ot->ch_num == 1){
				vl += v;
			}else{
				pan = ch_inf[nch].pan / (double)(1<<14);
				vl += (1 - pan) * v;
				vr += pan * v;
			}
			if(nt->onoff == 0 && sec - nt->off_sec >= tn->env.release) note_buf_free(i);
		}
		out_do(ot, vl / 16);
		if(ot->ch_num > 1) out_do(ot, vr / 16);
		ot->smp_cnt++;
	}
}

void
note_onoff(int onoff, double evt_sec, int ch, int note, int velo)
{
	int i;

	if(onoff){
		if((i = note_buf_search(-1, -1, -1)) < 0){
			MSG("note_buf full");
			return;
		}
		note_buf[i].note = note;
		note_buf[i].ch = ch;
		note_buf[i].onoff = 1;
		note_buf[i].on_sec = evt_sec;
		note_buf[i].velo = velo;
		note_buf[i].cycle = 0;
		note_buf[i].sec = evt_sec;
		note_buf[i].lpf.idx = -1;
	}else{
		if((i = note_buf_search(ch, note, 1)) < 0) return;
		note_buf[i].off_v = env_out(&note_buf[i]);
		note_buf[i].onoff = 0;
		note_buf[i].off_sec = evt_sec;
	}
}

void
msb_set(int *vp, int v)
{
	*vp &= ~(127<<7);
	*vp |= v<<7;
}

void
lsb_set(int *vp, int v)
{
	*vp &= ~127;
	*vp |= v;
}

void
bend_note_update(int ch, double sec)
{
	int i;
	struct note_rec *nt;

	for(i=0; i<NOTE_BUF_N; i++){
		if(note_buf_is_free(i)) continue;
		nt = &note_buf[i];
		if(nt->ch != ch) continue;
		nt->cycle += nt->freq * (sec - nt->sec);
		nt->sec = sec;
	}
}

int
main(int ac, char **av)
{
	int div4, delta_sum;
	int i, n, v, hi, low, note, velo;
	int ch, type;
	double sec;
	struct out_rec otr;
	int tempo, tempo_delta_sum;
	double tempo_sec;

	out_init(&otr, ac, av);
	note_buf_init();
	for(i=0; i<MIDI_CH_N; i++){
		ch_inf[i].vol = 0;
		ch_inf[i].pan = 1<<(14-1);
		ch_inf[i].bend = 0;
		ch_inf[i].rpn = 0;
		ch_inf[i].bend_range = 2;
		ch_inf[i].prog =-1;
	}
	tempo = 500000;
	tempo_delta_sum = 0;
	tempo_sec = 0;

	div4 = header();

	if(!rd_str_chk(4, "MTrk")) ERR("track id");
	v = rd_int(4); /* skip */

	hi = low = 0;
	delta_sum = 0;
	while((v = rd_delta()) != EOF){
		delta_sum += v;
		sec = tempo_sec + (double)(delta_sum - tempo_delta_sum) / div4 * tempo * 0.000001;
		
		if((v = rd()) & 0x80){
			hi = (v >> 4) & 0xf;
			low  = v & 0xf;
		}else bk(v);

		data_out(&otr, sec);

		ch = low;
		switch(hi){
		case 8:
		case 9:
			note = rd();
			velo = rd();
			note_onoff(hi == 9, sec, ch, note, velo);
			break;
		case 0xb: /* control change */
			type = rd();
			v = rd();
			switch(type){
			case 7: /* channel volume msb */
				msb_set(&ch_inf[ch].vol, v);
				break;
			case 39: /* channel volume lsb */
				lsb_set(&ch_inf[ch].vol, v);
				break;
			case 10: /* pan msb */
				msb_set(&ch_inf[ch].pan, v);
				break;
			case 42: /* pan lsb */
				lsb_set(&ch_inf[ch].pan, v);
				break;
			case 100: /* rpn lsb */
				lsb_set(&ch_inf[ch].rpn, v);
				break;
			case 101: /* rpn msb */
				msb_set(&ch_inf[ch].rpn, v);
				break;
			case 6: /* data entry msb */
				switch(ch_inf[ch].rpn){
				case 0: /* pitch bend range */
					ch_inf[ch].bend_range = v;
					break;
				}
				break;
			}
			break;
		case 0xa:
			rd();
			rd();
			break;
		case 0xe: /* pitch wheel change */
			bend_note_update(ch, sec);
			v = rd();
			v |= rd() << 7;
			ch_inf[ch].bend = v - 8192;
			break;
		case 0xc: /* program number */
			v = rd();
			ch_inf[ch].prog = v;
			break;
		case 0xd:
			rd();
			break;
		case 0xf:
			type = rd();
			switch(low){
			case 0:
				while(rd() != 0xf7);
				break;
			case 1:
			case 3:
				rd();
				break;
			case 2:
				rd();
				rd();
				break;
			case 0xf: /* meta */
				n = rd();
				switch(type){
				case 0x51: /* set tempo */
					v = rd_int(n);
					tempo = v;
					tempo_delta_sum = delta_sum;
					tempo_sec = sec;
					break;
				default:
					for(i=0; i<n; i++) rd();
					break;
				}
				break;
			default:
				break;
			}
			break;
		}
	}
	if(otr.fp != stdout) pclose(otr.fp);
	return 0;
}

/* EOF */


#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <math.h>

#define MSG(s) fprintf(stderr, "%s() %s L%d : %s\n", __func__, __FILE__, __LINE__, s)
#define ERR(s) do{ fprintf(stderr, "ERR "); MSG(s); exit(1); }while(0)

int bk_buf = -1;

int
rd(void)
{
	int v;

	if((v = bk_buf) < 0) return getchar();
	bk_buf = -1;
	return v;
}

void
bk(int v)
{
	if(bk_buf >= 0) ERR("give up");
	bk_buf = v;
}

void
rd_str(int n, char *s)
{
	int i;

	for(i=0; i<n; i++) s[i] = rd();
	s[i] = '\0';
}

int
rd_str_chk(int n, char *s)
{
	char buf[256];

	rd_str(n, buf);
	return strcmp(buf, s) == 0;
}

int
rd_int(int n) /* big endian */
{
	int i, v;

	v = 0;
	for(i=0; i<n; i++) v = (v << 8) | rd();
	return v;
}

int
rd_delta(void)
{
	int v, c;

	v = 0;
	do{
		if((c = rd()) == EOF) return EOF;
		v = (v << 7) | (c & 0x7f);
	}while(c & 0x80);
	return v;
}


struct lpf_rec{
	int idx;
	double in[4], out[4];
	double a0, a1, a2, b0, b1, b2, div_a0;
};

void
lpf_update(struct lpf_rec *lpf, double smp_freq, double freq, double Q)
{
	double w0, alpha;

	w0 = 2 * M_PI * freq / smp_freq;
	alpha = sin(w0) / (2 * Q);
	lpf->b1 = 1 - cos(w0);
	lpf->b0 = lpf->b2 = lpf->b1 * 0.5;
	lpf->a0 = 1 + alpha;
	lpf->a1 = -2 * cos(w0);
	lpf->a2 = 1 - alpha;
	if(lpf->a0 != 0) lpf->div_a0 = 1 / lpf->a0;
}
// lpf_init() からパラメータを設定する処理を分離して
// lpf_update() とした
// lpf_init() , data_out() から呼びだされる

void
lpf_init(struct lpf_rec *lpf, double smp_freq, double freq, double Q)
{
	int i;


	for(i=0; i<4; i++) lpf->in[i] = lpf->out[i] = 0;
	lpf->idx = 0;

	lpf_update(lpf, smp_freq, freq, Q);
	// 処理を分離して別関数 lpf_update() とした
	
}

double
lpf_out(struct lpf_rec *lpf, double in)
{
	double *out_p;
	int i_1, i_2;

	lpf->in[lpf->idx] = in;
	out_p = &lpf->out[lpf->idx];

	if(lpf->a0 != 0){
		i_1 = (lpf->idx + 4 - 1) & 3;
		i_2 = (i_1 + 4 - 1) & 3;
		*out_p = (lpf->b0 * in
			+ lpf->b1 * lpf->in[i_1]
			+ lpf->b2 * lpf->in[i_2]
			- lpf->a1 * lpf->out[i_1]
			- lpf->a2 * lpf->out[i_2] ) * lpf->div_a0;
	}else{
		*out_p = 0;
	}
	lpf->idx = (lpf->idx + 1) & 3;
	return *out_p;
}


#define NOTE_BUF_N	256

struct note_rec{
	int ch;
	int note;
	int onoff;
	double on_sec;
	double off_sec;
	int velo;
	double cycle, sec, freq;
	double off_v;
	struct lpf_rec lpf;
} note_buf[NOTE_BUF_N];

int
note_buf_is_free(int i)
{
	return note_buf[i].ch < 0;
}

void
note_buf_free(int i)
{
	note_buf[i].ch = -1;
}

void
note_buf_init(void)
{
	int i;

	for(i=0; i<NOTE_BUF_N; i++) note_buf_free(i);
}

int
note_buf_search(int ch, int note, int onoff)
{
	int i;

	for(i=0; i<NOTE_BUF_N; i++) {
		if( (ch < 0 && note_buf[i].ch < 0) ||
		    (note_buf[i].ch == ch &&
		     note_buf[i].note == note &&
		     note_buf[i].onoff == onoff) ) return i;
	}
	return -1;
}

int
header(void)
{
	int v;

	if(!rd_str_chk(4, "MThd")) ERR("header id");
	if(rd_int(4) != 6) ERR("header size");
	if(rd_int(2) != 0) ERR("header format type");
	if(rd_int(2) != 1) ERR("header track num");
	if((v = rd_int(2)) & 0x8000) ERR("header division");
	return v; /* div4 */
}

double
note_to_freq(int note)
{
	return 440 * pow(2, (note - 69) / 12.0);
}

int
opt_idx(char *key, int ac, char **av)
{
	int i;

	for(i=1; i<ac; i++) if(strcmp(av[i], key) == 0) return i;
	return -1;
}

char *
opt_str(char *key, int ac, char **av, char *def)
{
	int i;

	i = opt_idx(key, ac, av);
	if(i < 0 || i+1 >= ac) return def;
	return av[i+1];
}

int
opt_int(char *key, int ac, char **av, int def)
{
	char *s;

	if((s = opt_str(key, ac, av, NULL)) == NULL) return def;
	return strtol(s, NULL, 0);
}

struct out_rec{
	int smp_freq, smp_cnt;
	int bit_len;
	int sign;
	int ch_num;
	FILE *fp;

	int base;
	int amp;
	int iv_min;
	int iv_max;
};

void
out_init(struct out_rec *ot, int ac, char **av)
{
	char cmd[1024], *fn;

	ot->smp_freq = opt_int("-r", ac, av, 8000);
	ot->smp_cnt = 0;
	ot->bit_len = opt_int("-b", ac, av, 8);
	if(ot->bit_len != 8 && ot->bit_len != 16) ERR("bit_len");
	ot->sign = (opt_idx("-s", ac, av) >= 0);
	ot->ch_num = opt_int("-c", ac, av, 1);

	ot->fp = stdout;
	cmd[0] = '\0';
	fn = "";
	if(opt_idx("-play", ac, av) >= 0){
		strcat(cmd, "play");
	}else if(opt_idx("-sox", ac, av) >= 0){
		strcat(cmd, "sox");
		fn = opt_str("-sox", ac, av, "-d");
	}
	if(cmd[0]){
		sprintf(cmd + strlen(cmd), " -t raw -r %d -b %d %s -c %d - %s",
			ot->smp_freq, ot->bit_len,
			ot->sign ? "-s" : "-u",
			ot->ch_num, fn);
		if((ot->fp = popen(cmd, "w")) == NULL) ERR("popen");
	}
	ot->amp = ot->bit_len == 8 ? 127 : 32767;
	ot->base = ot->sign ? 0 : ot->amp + 1;
	ot->iv_min = ot->base - (ot->amp + 1);
	ot->iv_max = ot->base + ot->amp;
}

void
out_do(struct out_rec *ot, double v)
{
	int iv;

	iv = ot->base + (int)(v *ot->amp);
	if(iv > ot->iv_max) iv = ot->iv_max;
	if(iv < ot->iv_min) iv = ot->iv_min;
	switch(ot->bit_len){
	case 8:
		fputc(iv, ot->fp);
		break;
	case 16:
		fputc(iv & 0xff, ot->fp);
		fputc((iv >> 8) & 0xff, ot->fp);
		break;
	}
}

#define WAVE_SIN	0
#define WAVE_SAW	1
#define WAVE_SQUARE	2
#define WAVE_NOISE	3

double
wave_out(int wave, double cycle)
{
	cycle -= (int)cycle;

	switch(wave){
	case WAVE_SIN:
		return sin(2 * M_PI * cycle);
	case WAVE_SAW:
		cycle *= 2;
		if(cycle > 1) cycle -= 2;
		return cycle;
	case WAVE_SQUARE:
		return cycle < 0.5 ? 1 : -1;
	case WAVE_NOISE:
		return ((double)rand() / RAND_MAX) * 2 - 1;
	}
	return 0;
}

struct env_rec{
	double attack;	/* sec */
	double decay;	/* sec */
	double sustain;	/* 0..1 */
	double release;	/* sec */
};

void
env_set(struct env_rec *e, double a, double d, double s, double r)
{
	e->attack = a;
	e->decay = d;
	e->sustain = s;
	e->release = r;
}

struct tone_rec{
	int wave;
	double lpf_freq, lpf_Q;
	struct env_rec env;
	double level;
	int lfo_p, lfo_f;
	// lfo_p は LFO のピッチへの変調の強さ
	// lfo_f は LFO のフィルタへの変調の強さ
	//
	// 値の単位は「セント」 半音 (ノート番号) の1/100
	// 0 なら変調なし
	// 100 で 上下に半音分 ( 2^(-1/12)倍 から 2^(1/12)倍 ) の変化
	// 1200 で上下に1オクターブ分の変化
	
	int lfo_wave;
	// LFO の波形のタイプ
	// WAVE_SIN, WAVE_SAW, WAVE_SQUARE, WAVE_NOISE のいづれか
	
	double lfo_freq, lfo_delay;
	// LFO の周波数と、鍵盤オンからLFOが効きだすまでの時間(秒)
	
} tone_inf[] = {
	{	/* strings */
		WAVE_SAW,
		3000, 1.5,
		{ 0.15, 0.5, 0.8, 0.5 },
		0.7,
		25, 0, WAVE_SIN, 6, 0.3,
	},{	/* bass */
		WAVE_SAW,
		1000, 1.5,
		{ 0.05, 0.2, 0.4, 0.2 },
		1.0,
		60, 0, WAVE_SIN, 1.5, 0.2,
	},{	/* lead */
		WAVE_SQUARE,
		2000, 4,
		{ 0.01, 0.2, 0.8, 0.3 },
		0.5,
		10, 5, WAVE_SIN, 4, 0.3,
	},{	/* SIN */
		WAVE_SIN,
		20000, 0.8,
		{ 0, 0.3, 0.2, 0.3 },
		1.0,
		25, 0, WAVE_SIN, 6, 0.3,
	}
}, drum_tone_inf[] = {
	{	/* bass */
		WAVE_NOISE,
		400, 1,
		{ 0.01, 0.18, 0, 0.18 },
		10.0,
		0, 0, WAVE_SIN, 0, 0,
	},{	/* snare */
		WAVE_NOISE,
		1000, 1.7,
		{ 0, 0.3, 0.3, 0.3 },
		3.0,
		0, 1200, WAVE_NOISE, 0, 0,
	},{	/* tom */
		WAVE_NOISE,
		800, 2,
		{ 0, 0.3, 2, 0.4 },
		1.0,
		0, 0, WAVE_SIN, 0, 0,
	},{	/* hi-hat close */
		WAVE_NOISE,
		16000, 2,
		{ 0, 0.1, 0, 0.1 },
		0.8,
		0, 0, WAVE_SIN, 0, 0,
	},{	/* hi-hat open */
		WAVE_NOISE,
		16000, 2,
		{ 0, 0, 1, 0.3 },
		0.8,
		0, 0, WAVE_SIN, 0, 0,
	},{	/* cymbal */
		WAVE_NOISE,
		5000, 3,
		{ 0, 0.3, 0.3, 1 },
		0.8,
		0, 200, WAVE_SIN, 3, 0.3,
	}
};

struct tone_rec *
tone_get(int prog, int note, double *ret_freq)
{
	int idx;
	struct tone_rec *ret;

	idx = -1;
	if(prog <= 0){ /* drum part */
		switch(note){
		case 36: /* bass drum1 */
			idx = 0;
			note = 28;
			break;
		case 37: /* side stick */
		case 40: /* electric snare */
			idx = 1;
			note = 69;
			break;
		case 41: /* low floor tom */
			idx = 2;
			note = 50;
			break;
		case 42: /* closed hi-hat */
			idx = 3;
			note = 115;
			break;
		case 46: /* open hi-hat */
			idx = 4;
			note = 115;
			break;
		case 49: /* crash cymbal 1 */
		case 57: /* crash cymbal 2 */
			idx = 5;
			note = 80;
			break;
		}
		ret = idx < 0 ? NULL : &drum_tone_inf[idx];
	}else{
		switch(prog){
		case 48: /* timpani */
		case 50: /* strings ensamble 2 */
			idx = 0;
			break;
		case 35: /* electric bass (pick) */
			idx = 1;
			break;
		case 79: /* whistle */
		case 81: /* lead 1 (square) */
		case 87: /* lead 7 (fifths) */
			idx = 2;
			break;
		case 24: /* tango accordion */
		case 67: /* tenor sax */
		default:
			idx = 3;
			break;
		}
		ret = &tone_inf[idx];
	}
	if(ret_freq) *ret_freq = note_to_freq(note);
	return ret;
}

#define MIDI_CH_N	16
struct ch_rec{
	int vol;
	int pan;
	int bend;
	int rpn;
	int bend_range;
	int prog;
} ch_inf[ MIDI_CH_N ];

#define CH_PROG(ch)	( (ch) == 9 ? 0 : ch_inf[ch].prog )

double
env_out(struct note_rec *nt)
{
	struct tone_rec *tn;
	struct env_rec *e;
	double sec, v;

	if((tn = tone_get(CH_PROG(nt->ch), nt->note, NULL)) == NULL) return 0;
	e = &tn->env;
	sec = nt->sec;
	if(nt->onoff){
		sec -= nt->on_sec;
		if(sec < e->attack){
			v = sec / e->attack;
			return log10(1 + v * 9);
		}
		sec -= e->attack;
		if(sec < e->decay){
			v = sec / e->decay;
			v = log10(1 + v * 9);
			return 1 - v * (1 - e->sustain);
		}
		return e->sustain;
	}
	sec -= nt->off_sec;
	if(sec < e->release){
		v = sec / e->release;
		v = log10(1 + v * 9);
		return (1 - v) * nt->off_v;
	}
	return 0;
}

void
data_out(struct out_rec *ot, double evt_sec)
{
	double v, sec, freq, dsec;
	double vl, vr, pan;
	int i, nch;
	struct note_rec *nt;
	struct tone_rec *tn;
	double lfo_out;
	// LFO の波形出力を保持する変数を追加
	
	while((sec = (double)ot->smp_cnt / ot->smp_freq) < evt_sec){
		vl = vr = 0;
		for(i=0; i<NOTE_BUF_N; i++){
			if(note_buf_is_free(i)) continue;
			nt = &note_buf[i];
			nch = nt->ch;
			tn = tone_get(CH_PROG(nch), nt->note, &freq);
			if(tn == NULL) continue;

			if(ch_inf[nch].bend != 0) freq *= pow(2, ch_inf[nch].bend / 8192.0 * ch_inf[nch].bend_range / 12);
			dsec = sec - nt->on_sec - tn->lfo_delay;
			// 鍵盤オンからLFOが効きだすまでの時間が経過し、
			// LFOが効きだしてからの時間を dsec へ
			// なので dsec の値が 0 以下なら、まだ LFO は効いてない段階
			
			if((tn->lfo_p || tn->lfo_f) && dsec > 0){
				lfo_out = wave_out(tn->lfo_wave, tn->lfo_freq * dsec);
			}
			// LFO 出力が必要か判定し、
			// 必要ならば、LFOの波形を算出し、追加した変数 lfo_outへ
			
			if(tn->lfo_p && dsec > 0) freq *= pow(2, lfo_out * (tn->lfo_p / 100.0) / 12);
			// LFO のピッチへの変調が必要ならば、周波数を保持してる変数 freq を更新する
			
			nt->cycle += freq * (sec - nt->sec);
			nt->sec = sec;
			nt->freq = freq;
			v = wave_out(tn->wave, nt->cycle);

			if(nt->lpf.idx < 0) lpf_init(&nt->lpf, ot->smp_freq, tn->lpf_freq, tn->lpf_Q);
			if(tn->lfo_f && dsec > 0){
				freq = tn->lpf_freq * pow(2, lfo_out * (tn->lfo_f / 100.0) / 12);
				lpf_update(&nt->lpf, ot->smp_freq, freq, tn->lpf_Q);
			}
			// LFO のフィルタへの変調が必要ならば、
			// LPF のカット・オフ周波数 を更新し、
			// LPF のパラメータを更新する
			// LPF のパラメータの更新は、lpf_init()関数から分離した lpf_update()関数を呼び出す
			
			v = lpf_out(&nt->lpf, v);

			v *= env_out(&note_buf[i]) * tn->level;
			v *= nt->velo / 127.0;
			v *= ch_inf[nch].vol / (double)((1<<14)-1);
			if(ot->ch_num == 1){
				vl += v;
			}else{
				pan = ch_inf[nch].pan / (double)(1<<14);
				vl += (1 - pan) * v;
				vr += pan * v;
			}
			if(nt->onoff == 0 && sec - nt->off_sec >= tn->env.release) note_buf_free(i);
		}
		out_do(ot, vl / 16);
		if(ot->ch_num > 1) out_do(ot, vr / 16);
		ot->smp_cnt++;
	}
}

void
note_onoff(int onoff, double evt_sec, int ch, int note, int velo)
{
	int i;

	if(onoff){
		if((i = note_buf_search(-1, -1, -1)) < 0){
			MSG("note_buf full");
			return;
		}
		note_buf[i].note = note;
		note_buf[i].ch = ch;
		note_buf[i].onoff = 1;
		note_buf[i].on_sec = evt_sec;
		note_buf[i].velo = velo;
		note_buf[i].cycle = 0;
		note_buf[i].sec = evt_sec;
		note_buf[i].lpf.idx = -1;
	}else{
		if((i = note_buf_search(ch, note, 1)) < 0) return;
		note_buf[i].off_v = env_out(&note_buf[i]);
		note_buf[i].onoff = 0;
		note_buf[i].off_sec = evt_sec;
	}
}

void
msb_set(int *vp, int v)
{
	*vp &= ~(127<<7);
	*vp |= v<<7;
}

void
lsb_set(int *vp, int v)
{
	*vp &= ~127;
	*vp |= v;
}

void
bend_note_update(int ch, double sec)
{
	int i;
	struct note_rec *nt;

	for(i=0; i<NOTE_BUF_N; i++){
		if(note_buf_is_free(i)) continue;
		nt = &note_buf[i];
		if(nt->ch != ch) continue;
		nt->cycle += nt->freq * (sec - nt->sec);
		nt->sec = sec;
	}
}

int
main(int ac, char **av)
{
	int div4, delta_sum;
	int i, n, v, hi, low, note, velo;
	int ch, type;
	double sec;
	struct out_rec otr;
	int tempo, tempo_delta_sum;
	double tempo_sec;

	out_init(&otr, ac, av);
	note_buf_init();
	for(i=0; i<MIDI_CH_N; i++){
		ch_inf[i].vol = 0;
		ch_inf[i].pan = 1<<(14-1);
		ch_inf[i].bend = 0;
		ch_inf[i].rpn = 0;
		ch_inf[i].bend_range = 2;
		ch_inf[i].prog =-1;
	}
	tempo = 500000;
	tempo_delta_sum = 0;
	tempo_sec = 0;

	div4 = header();

	if(!rd_str_chk(4, "MTrk")) ERR("track id");
	v = rd_int(4); /* skip */

	hi = low = 0;
	delta_sum = 0;
	while((v = rd_delta()) != EOF){
		delta_sum += v;
		sec = tempo_sec + (double)(delta_sum - tempo_delta_sum) / div4 * tempo * 0.000001;
		
		if((v = rd()) & 0x80){
			hi = (v >> 4) & 0xf;
			low  = v & 0xf;
		}else bk(v);

		data_out(&otr, sec);

		ch = low;
		switch(hi){
		case 8:
		case 9:
			note = rd();
			velo = rd();
			note_onoff(hi == 9, sec, ch, note, velo);
			break;
		case 0xb: /* control change */
			type = rd();
			v = rd();
			switch(type){
			case 7: /* channel volume msb */
				msb_set(&ch_inf[ch].vol, v);
				break;
			case 39: /* channel volume lsb */
				lsb_set(&ch_inf[ch].vol, v);
				break;
			case 10: /* pan msb */
				msb_set(&ch_inf[ch].pan, v);
				break;
			case 42: /* pan lsb */
				lsb_set(&ch_inf[ch].pan, v);
				break;
			case 100: /* rpn lsb */
				lsb_set(&ch_inf[ch].rpn, v);
				break;
			case 101: /* rpn msb */
				msb_set(&ch_inf[ch].rpn, v);
				break;
			case 6: /* data entry msb */
				switch(ch_inf[ch].rpn){
				case 0: /* pitch bend range */
					ch_inf[ch].bend_range = v;
					break;
				}
				break;
			}
			break;
		case 0xa:
			rd();
			rd();
			break;
		case 0xe: /* pitch wheel change */
			bend_note_update(ch, sec);
			v = rd();
			v |= rd() << 7;
			ch_inf[ch].bend = v - 8192;
			break;
		case 0xc: /* program number */
			v = rd();
			ch_inf[ch].prog = v;
			break;
		case 0xd:
			rd();
			break;
		case 0xf:
			type = rd();
			switch(low){
			case 0:
				while(rd() != 0xf7);
				break;
			case 1:
			case 3:
				rd();
				break;
			case 2:
				rd();
				rd();
				break;
			case 0xf: /* meta */
				n = rd();
				switch(type){
				case 0x51: /* set tempo */
					v = rd_int(n);
					tempo = v;
					tempo_delta_sum = delta_sum;
					tempo_sec = sec;
					break;
				default:
					for(i=0; i<n; i++) rd();
					break;
				}
				break;
			default:
				break;
			}
			break;
		}
	}
	if(otr.fp != stdout) pclose(otr.fp);
	return 0;
}

/* EOF */


prog14.c 解説

prog13.c からの変更箇所のみ

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <math.h>

#define MSG(s) fprintf(stderr, "%s() %s L%d : %s\n", __func__, __FILE__, __LINE__, s)
#define ERR(s) do{ fprintf(stderr, "ERR "); MSG(s); exit(1); }while(0)

int bk_buf = -1;

int
rd(void)
{
	int v;

	if((v = bk_buf) < 0) return getchar();
	bk_buf = -1;
	return v;
}

void
bk(int v)
{
	if(bk_buf >= 0) ERR("give up");
	bk_buf = v;
}

void
rd_str(int n, char *s)
{
	int i;

	for(i=0; i<n; i++) s[i] = rd();
	s[i] = '\0';
}

int
rd_str_chk(int n, char *s)
{
	char buf[256];

	rd_str(n, buf);
	return strcmp(buf, s) == 0;
}

int
rd_int(int n) /* big endian */
{
	int i, v;

	v = 0;
	for(i=0; i<n; i++) v = (v << 8) | rd();
	return v;
}

int
rd_delta(void)
{
	int v, c;

	v = 0;
	do{
		if((c = rd()) == EOF) return EOF;
		v = (v << 7) | (c & 0x7f);
	}while(c & 0x80);
	return v;
}


struct lpf_rec{
	int idx;
	double in[4], out[4];
	double a0, a1, a2, b0, b1, b2, div_a0;
};

void
lpf_update(struct lpf_rec *lpf, double smp_freq, double freq, double Q)
{
	double w0, alpha;

	w0 = 2 * M_PI * freq / smp_freq;
	alpha = sin(w0) / (2 * Q);
	lpf->b1 = 1 - cos(w0);
	lpf->b0 = lpf->b2 = lpf->b1 * 0.5;
	lpf->a0 = 1 + alpha;
	lpf->a1 = -2 * cos(w0);
	lpf->a2 = 1 - alpha;
	if(lpf->a0 != 0) lpf->div_a0 = 1 / lpf->a0;
}

void
lpf_init(struct lpf_rec *lpf, double smp_freq, double freq, double Q)
{
	int i;


	for(i=0; i<4; i++) lpf->in[i] = lpf->out[i] = 0;
	lpf->idx = 0;

	lpf_update(lpf, smp_freq, freq, Q);
}

double
lpf_out(struct lpf_rec *lpf, double in)
{
	double *out_p;
	int i_1, i_2;

	lpf->in[lpf->idx] = in;
	out_p = &lpf->out[lpf->idx];

	if(lpf->a0 != 0){
		i_1 = (lpf->idx + 4 - 1) & 3;
		i_2 = (i_1 + 4 - 1) & 3;
		*out_p = (lpf->b0 * in
			+ lpf->b1 * lpf->in[i_1]
			+ lpf->b2 * lpf->in[i_2]
			- lpf->a1 * lpf->out[i_1]
			- lpf->a2 * lpf->out[i_2] ) * lpf->div_a0;
	}else{
		*out_p = 0;
	}
	lpf->idx = (lpf->idx + 1) & 3;
	return *out_p;
}


#define NOTE_BUF_N	256

struct note_rec{
	int ch;
	int note;
	int onoff;
	double on_sec;
	double off_sec;
	int velo;
	double cycle1, cycle2, sec, freq1, freq2;
	double off_v;
	struct lpf_rec lpf;
} note_buf[NOTE_BUF_N];

int
note_buf_is_free(int i)
{
	return note_buf[i].ch < 0;
}

void
note_buf_free(int i)
{
	note_buf[i].ch = -1;
}

void
note_buf_init(void)
{
	int i;

	for(i=0; i<NOTE_BUF_N; i++) note_buf_free(i);
}

int
note_buf_search(int ch, int note, int onoff)
{
	int i;

	for(i=0; i<NOTE_BUF_N; i++) {
		if( (ch < 0 && note_buf[i].ch < 0) ||
		    (note_buf[i].ch == ch &&
		     note_buf[i].note == note &&
		     note_buf[i].onoff == onoff) ) return i;
	}
	return -1;
}

int
header(void)
{
	int v;

	if(!rd_str_chk(4, "MThd")) ERR("header id");
	if(rd_int(4) != 6) ERR("header size");
	if(rd_int(2) != 0) ERR("header format type");
	if(rd_int(2) != 1) ERR("header track num");
	if((v = rd_int(2)) & 0x8000) ERR("header division");
	return v; /* div4 */
}

double
note_to_freq(int note)
{
	return 440 * pow(2, (note - 69) / 12.0);
}

int
opt_idx(char *key, int ac, char **av)
{
	int i;

	for(i=1; i<ac; i++) if(strcmp(av[i], key) == 0) return i;
	return -1;
}

char *
opt_str(char *key, int ac, char **av, char *def)
{
	int i;

	i = opt_idx(key, ac, av);
	if(i < 0 || i+1 >= ac) return def;
	return av[i+1];
}

int
opt_int(char *key, int ac, char **av, int def)
{
	char *s;

	if((s = opt_str(key, ac, av, NULL)) == NULL) return def;
	return strtol(s, NULL, 0);
}

struct out_rec{
	int smp_freq, smp_cnt;
	int bit_len;
	int sign;
	int ch_num;
	FILE *fp;

	int base;
	int amp;
	int iv_min;
	int iv_max;
};

void
out_init(struct out_rec *ot, int ac, char **av)
{
	char cmd[1024], *fn;

	ot->smp_freq = opt_int("-r", ac, av, 8000);
	ot->smp_cnt = 0;
	ot->bit_len = opt_int("-b", ac, av, 8);
	if(ot->bit_len != 8 && ot->bit_len != 16) ERR("bit_len");
	ot->sign = (opt_idx("-s", ac, av) >= 0);
	ot->ch_num = opt_int("-c", ac, av, 1);

	ot->fp = stdout;
	cmd[0] = '\0';
	fn = "";
	if(opt_idx("-play", ac, av) >= 0){
		strcat(cmd, "play");
	}else if(opt_idx("-sox", ac, av) >= 0){
		strcat(cmd, "sox");
		fn = opt_str("-sox", ac, av, "-d");
	}
	if(cmd[0]){
		sprintf(cmd + strlen(cmd), " -t raw -r %d -b %d %s -c %d - %s",
			ot->smp_freq, ot->bit_len,
			ot->sign ? "-s" : "-u",
			ot->ch_num, fn);
		if((ot->fp = popen(cmd, "w")) == NULL) ERR("popen");
	}
	ot->amp = ot->bit_len == 8 ? 127 : 32767;
	ot->base = ot->sign ? 0 : ot->amp + 1;
	ot->iv_min = ot->base - (ot->amp + 1);
	ot->iv_max = ot->base + ot->amp;
}

void
out_do(struct out_rec *ot, double v)
{
	int iv;

	iv = ot->base + (int)(v *ot->amp);
	if(iv > ot->iv_max) iv = ot->iv_max;
	if(iv < ot->iv_min) iv = ot->iv_min;
	switch(ot->bit_len){
	case 8:
		fputc(iv, ot->fp);
		break;
	case 16:
		fputc(iv & 0xff, ot->fp);
		fputc((iv >> 8) & 0xff, ot->fp);
		break;
	}
}

#define WAVE_SIN	0
#define WAVE_SAW	1
#define WAVE_SQUARE	2
#define WAVE_NOISE	3

double
wave_out(int wave, double cycle)
{
	cycle -= (int)cycle;

	switch(wave){
	case WAVE_SIN:
		return sin(2 * M_PI * cycle);
	case WAVE_SAW:
		cycle *= 2;
		if(cycle > 1) cycle -= 2;
		return cycle;
	case WAVE_SQUARE:
		return cycle < 0.5 ? 1 : -1;
	case WAVE_NOISE:
		return ((double)rand() / RAND_MAX) * 2 - 1;
	}
	return 0;
}

struct env_rec{
	double attack;	/* sec */
	double decay;	/* sec */
	double sustain;	/* 0..1 */
	double release;	/* sec */
};

void
env_set(struct env_rec *e, double a, double d, double s, double r)
{
	e->attack = a;
	e->decay = d;
	e->sustain = s;
	e->release = r;
}

struct tone_rec{
	int wave1, wave2, tune;
	double mix;
	double lpf_freq, lpf_Q;
	struct env_rec env;
	double level;
	int lfo_p1, lfo_p2, lfo_f;
	int lfo_wave;
	double lfo_freq, lfo_delay;
} tone_inf[] = {
	{	/* strings */
		WAVE_SAW, WAVE_SAW, 10, 0.5,
		3000, 1.5,
		{ 0.15, 0.5, 0.8, 0.5 },
		0.8,
		25, 0, 0, WAVE_SIN, 6, 0.3,
	},{	/* bass */
		WAVE_SAW, WAVE_SQUARE, 0, 0.5,
		1000, 1.5,
		{ 0.05, 0.2, 0.4, 0.2 },
		1.0,
		0, 60, 0, WAVE_SIN, 1.5, 0.2,
	},{	/* lead */
		WAVE_SQUARE, WAVE_SQUARE, 10, 0.5,
		2000, 4,
		{ 0.01, 0.2, 0.8, 0.3 },
		0.9,
		0, 1, 5, WAVE_SIN, 4, 0.3,
	},{	/* SIN */
		WAVE_SIN, WAVE_SIN, 0, 0,
		20000, 0.8,
		{ 0, 0.3, 0.2, 0.3 },
		1.0,
		25, 0, 0, WAVE_SIN, 6, 0.3,
	}
}, drum_tone_inf[] = {
	{	/* bass */
		WAVE_SIN, WAVE_NOISE, 0, 0.2,
		400, 1,
		{ 0.01, 0.18, 0, 0.18 },
		10.0,
		100, 0, 30, WAVE_NOISE, 0, 0.5,
	},{	/* snare */
		WAVE_NOISE, WAVE_SIN, 0, 0,
		1000, 1.7,
		{ 0, 0.3, 0.3, 0.3 },
		3.0,
		0, 0, 0, WAVE_SIN, 0, 10,
	},{	/* tom */
		WAVE_NOISE, WAVE_SIN, 0, 0,
		800, 2,
		{ 0, 0.3, 2, 0.4 },
		1.0,
		0, 0, 0, WAVE_SIN, 0, 0,
	},{	/* hi-hat close */
		WAVE_NOISE, WAVE_SIN, 0, 0,
		16000, 2,
		{ 0, 0.1, 0, 0.1 },
		0.8,
		0, 0, 0, WAVE_SIN, 0, 0,
	},{	/* hi-hat open */
		WAVE_NOISE, WAVE_SIN, 0, 0,
		16000, 2,
		{ 0, 0, 1, 0.3 },
		0.8,
		0, 0, 0, WAVE_SIN, 0, 0,
	},{	/* cymbal */
		WAVE_NOISE, WAVE_SIN, 0, 0,
		5000, 3,
		{ 0, 0.3, 0.3, 1 },
		0.8,
		0, 0, 200, WAVE_SIN, 3, 0.3,
	}
};

struct tone_rec *
tone_get(int prog, int note, double *ret_freq)
{
	int idx;
	struct tone_rec *ret;

	idx = -1;
	if(prog <= 0){ /* drum part */
		switch(note){
		case 36: /* bass drum1 */
			idx = 0;
			note = 28;
			break;
		case 37: /* side stick */
		case 40: /* electric snare */
			idx = 1;
			note = 69;
			break;
		case 41: /* low floor tom */
			idx = 2;
			note = 50;
			break;
		case 42: /* closed hi-hat */
			idx = 3;
			note = 115;
			break;
		case 46: /* open hi-hat */
			idx = 4;
			note = 115;
			break;
		case 49: /* crash cymbal 1 */
		case 57: /* crash cymbal 2 */
			idx = 5;
			note = 80;
			break;
		}
		ret = idx < 0 ? NULL : &drum_tone_inf[idx];
	}else{
		switch(prog){
		case 48: /* timpani */
		case 50: /* strings ensamble 2 */
			idx = 0;
			break;
		case 35: /* electric bass (pick) */
			idx = 1;
			break;
		case 79: /* whistle */
		case 81: /* lead 1 (square) */
		case 87: /* lead 7 (fifths) */
			idx = 2;
			break;
		case 24: /* tango accordion */
		case 67: /* tenor sax */
		default:
			idx = 3;
			break;
		}
		ret = &tone_inf[idx];
	}
	if(ret_freq) *ret_freq = note_to_freq(note);
	return ret;
}

#define MIDI_CH_N	16
struct ch_rec{
	int vol;
	int pan;
	int bend;
	int rpn;
	int bend_range;
	int prog;
} ch_inf[ MIDI_CH_N ];

#define CH_PROG(ch)	( (ch) == 9 ? 0 : ch_inf[ch].prog )

double
env_out(struct note_rec *nt)
{
	struct tone_rec *tn;
	struct env_rec *e;
	double sec, v;

	if((tn = tone_get(CH_PROG(nt->ch), nt->note, NULL)) == NULL) return 0;
	e = &tn->env;
	sec = nt->sec;
	if(nt->onoff){
		sec -= nt->on_sec;
		if(sec < e->attack){
			v = sec / e->attack;
			return log10(1 + v * 9);
		}
		sec -= e->attack;
		if(sec < e->decay){
			v = sec / e->decay;
			v = log10(1 + v * 9);
			return 1 - v * (1 - e->sustain);
		}
		return e->sustain;
	}
	sec -= nt->off_sec;
	if(sec < e->release){
		v = sec / e->release;
		v = log10(1 + v * 9);
		return (1 - v) * nt->off_v;
	}
	return 0;
}

void
data_out(struct out_rec *ot, double evt_sec)
{
	double v, v1, v2, sec, freq, freq1, freq2, dsec;
	double vl, vr, pan;
	int i, nch;
	struct note_rec *nt;
	struct tone_rec *tn;
	double lfo_out;

	while((sec = (double)ot->smp_cnt / ot->smp_freq) < evt_sec){
		vl = vr = 0;
		for(i=0; i<NOTE_BUF_N; i++){
			if(note_buf_is_free(i)) continue;
			nt = &note_buf[i];
			nch = nt->ch;
			tn = tone_get(CH_PROG(nch), nt->note, &freq);
			if(tn == NULL) continue;

			if(ch_inf[nch].bend != 0) freq *= pow(2, ch_inf[nch].bend / 8192.0 * ch_inf[nch].bend_range / 12);
			freq1 = freq2 = freq;
			freq2 *= pow(2, (tn->tune / 100.0) / 12);
			dsec = sec - nt->on_sec - tn->lfo_delay;
			if((tn->lfo_p1 || tn->lfo_p2 || tn->lfo_f) && dsec > 0){
				lfo_out = wave_out(tn->lfo_wave, tn->lfo_freq * dsec);
			}
			if(tn->lfo_p1 && dsec > 0) freq1 *= pow(2, lfo_out * (tn->lfo_p1 / 100.0) / 12);
			nt->cycle1 += freq1 * (sec - nt->sec);
			nt->freq1 = freq1;
			if(tn->lfo_p2 && dsec > 0) freq2 *= pow(2, lfo_out * (tn->lfo_p2 / 100.0) / 12);
			nt->cycle2 += freq2 * (sec - nt->sec);
			nt->freq2 = freq2;
			nt->sec = sec;
			v1 = wave_out(tn->wave1, nt->cycle1);
			v2 = wave_out(tn->wave2, nt->cycle2);
			v = v1 * (1 - tn->mix) + v2 * tn->mix;

			if(nt->lpf.idx < 0) lpf_init(&nt->lpf, ot->smp_freq, tn->lpf_freq, tn->lpf_Q);
			if(tn->lfo_f && dsec > 0){
				freq = tn->lpf_freq * pow(2, lfo_out * (tn->lfo_f / 100.0) / 12);
				lpf_update(&nt->lpf, ot->smp_freq, freq, tn->lpf_Q);
			}
			v = lpf_out(&nt->lpf, v);

			v *= env_out(&note_buf[i]) * tn->level;
			v *= nt->velo / 127.0;
			v *= ch_inf[nch].vol / (double)((1<<14)-1);
			if(ot->ch_num == 1){
				vl += v;
			}else{
				pan = ch_inf[nch].pan / (double)(1<<14);
				vl += (1 - pan) * v;
				vr += pan * v;
			}
			if(nt->onoff == 0 && sec - nt->off_sec >= tn->env.release) note_buf_free(i);
		}
		out_do(ot, vl / 16);
		if(ot->ch_num > 1) out_do(ot, vr / 16);
		ot->smp_cnt++;
	}
}

void
note_onoff(int onoff, double evt_sec, int ch, int note, int velo)
{
	int i;

	if(onoff){
		if((i = note_buf_search(-1, -1, -1)) < 0){
			MSG("note_buf full");
			return;
		}
		note_buf[i].note = note;
		note_buf[i].ch = ch;
		note_buf[i].onoff = 1;
		note_buf[i].on_sec = evt_sec;
		note_buf[i].velo = velo;
		note_buf[i].cycle1 = 0;
		note_buf[i].cycle2 = 0;
		note_buf[i].sec = evt_sec;
		note_buf[i].lpf.idx = -1;
	}else{
		if((i = note_buf_search(ch, note, 1)) < 0) return;
		note_buf[i].off_v = env_out(&note_buf[i]);
		note_buf[i].onoff = 0;
		note_buf[i].off_sec = evt_sec;
	}
}

void
msb_set(int *vp, int v)
{
	*vp &= ~(127<<7);
	*vp |= v<<7;
}

void
lsb_set(int *vp, int v)
{
	*vp &= ~127;
	*vp |= v;
}

void
bend_note_update(int ch, double sec)
{
	int i;
	struct note_rec *nt;

	for(i=0; i<NOTE_BUF_N; i++){
		if(note_buf_is_free(i)) continue;
		nt = &note_buf[i];
		if(nt->ch != ch) continue;
		nt->cycle1 += nt->freq1 * (sec - nt->sec);
		nt->cycle2 += nt->freq2 * (sec - nt->sec);
		nt->sec = sec;
	}
}

int
main(int ac, char **av)
{
	int div4, delta_sum;
	int i, n, v, hi, low, note, velo;
	int ch, type;
	double sec;
	struct out_rec otr;
	int tempo, tempo_delta_sum;
	double tempo_sec;

	out_init(&otr, ac, av);
	note_buf_init();
	for(i=0; i<MIDI_CH_N; i++){
		ch_inf[i].vol = 0;
		ch_inf[i].pan = 1<<(14-1);
		ch_inf[i].bend = 0;
		ch_inf[i].rpn = 0;
		ch_inf[i].bend_range = 2;
		ch_inf[i].prog =-1;
	}
	tempo = 500000;
	tempo_delta_sum = 0;
	tempo_sec = 0;

	div4 = header();

	if(!rd_str_chk(4, "MTrk")) ERR("track id");
	v = rd_int(4); /* skip */

	hi = low = 0;
	delta_sum = 0;
	while((v = rd_delta()) != EOF){
		delta_sum += v;
		sec = tempo_sec + (double)(delta_sum - tempo_delta_sum) / div4 * tempo * 0.000001;
		
		if((v = rd()) & 0x80){
			hi = (v >> 4) & 0xf;
			low  = v & 0xf;
		}else bk(v);

		data_out(&otr, sec);

		ch = low;
		switch(hi){
		case 8:
		case 9:
			note = rd();
			velo = rd();
			note_onoff(hi == 9, sec, ch, note, velo);
			break;
		case 0xb: /* control change */
			type = rd();
			v = rd();
			switch(type){
			case 7: /* channel volume msb */
				msb_set(&ch_inf[ch].vol, v);
				break;
			case 39: /* channel volume lsb */
				lsb_set(&ch_inf[ch].vol, v);
				break;
			case 10: /* pan msb */
				msb_set(&ch_inf[ch].pan, v);
				break;
			case 42: /* pan lsb */
				lsb_set(&ch_inf[ch].pan, v);
				break;
			case 100: /* rpn lsb */
				lsb_set(&ch_inf[ch].rpn, v);
				break;
			case 101: /* rpn msb */
				msb_set(&ch_inf[ch].rpn, v);
				break;
			case 6: /* data entry msb */
				switch(ch_inf[ch].rpn){
				case 0: /* pitch bend range */
					ch_inf[ch].bend_range = v;
					break;
				}
				break;
			}
			break;
		case 0xa:
			rd();
			rd();
			break;
		case 0xe: /* pitch wheel change */
			bend_note_update(ch, sec);
			v = rd();
			v |= rd() << 7;
			ch_inf[ch].bend = v - 8192;
			break;
		case 0xc: /* program number */
			v = rd();
			ch_inf[ch].prog = v;
			break;
		case 0xd:
			rd();
			break;
		case 0xf:
			type = rd();
			switch(low){
			case 0:
				while(rd() != 0xf7);
				break;
			case 1:
			case 3:
				rd();
				break;
			case 2:
				rd();
				rd();
				break;
			case 0xf: /* meta */
				n = rd();
				switch(type){
				case 0x51: /* set tempo */
					v = rd_int(n);
					tempo = v;
					tempo_delta_sum = delta_sum;
					tempo_sec = sec;
					break;
				default:
					for(i=0; i<n; i++) rd();
					break;
				}
				break;
			default:
				break;
			}
			break;
		}
	}
	if(otr.fp != stdout) pclose(otr.fp);
	return 0;
}

/* EOF */


#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <math.h>

#define MSG(s) fprintf(stderr, "%s() %s L%d : %s\n", __func__, __FILE__, __LINE__, s)
#define ERR(s) do{ fprintf(stderr, "ERR "); MSG(s); exit(1); }while(0)

int bk_buf = -1;

int
rd(void)
{
	int v;

	if((v = bk_buf) < 0) return getchar();
	bk_buf = -1;
	return v;
}

void
bk(int v)
{
	if(bk_buf >= 0) ERR("give up");
	bk_buf = v;
}

void
rd_str(int n, char *s)
{
	int i;

	for(i=0; i<n; i++) s[i] = rd();
	s[i] = '\0';
}

int
rd_str_chk(int n, char *s)
{
	char buf[256];

	rd_str(n, buf);
	return strcmp(buf, s) == 0;
}

int
rd_int(int n) /* big endian */
{
	int i, v;

	v = 0;
	for(i=0; i<n; i++) v = (v << 8) | rd();
	return v;
}

int
rd_delta(void)
{
	int v, c;

	v = 0;
	do{
		if((c = rd()) == EOF) return EOF;
		v = (v << 7) | (c & 0x7f);
	}while(c & 0x80);
	return v;
}


struct lpf_rec{
	int idx;
	double in[4], out[4];
	double a0, a1, a2, b0, b1, b2, div_a0;
};

void
lpf_update(struct lpf_rec *lpf, double smp_freq, double freq, double Q)
{
	double w0, alpha;

	w0 = 2 * M_PI * freq / smp_freq;
	alpha = sin(w0) / (2 * Q);
	lpf->b1 = 1 - cos(w0);
	lpf->b0 = lpf->b2 = lpf->b1 * 0.5;
	lpf->a0 = 1 + alpha;
	lpf->a1 = -2 * cos(w0);
	lpf->a2 = 1 - alpha;
	if(lpf->a0 != 0) lpf->div_a0 = 1 / lpf->a0;
}

void
lpf_init(struct lpf_rec *lpf, double smp_freq, double freq, double Q)
{
	int i;


	for(i=0; i<4; i++) lpf->in[i] = lpf->out[i] = 0;
	lpf->idx = 0;

	lpf_update(lpf, smp_freq, freq, Q);
}

double
lpf_out(struct lpf_rec *lpf, double in)
{
	double *out_p;
	int i_1, i_2;

	lpf->in[lpf->idx] = in;
	out_p = &lpf->out[lpf->idx];

	if(lpf->a0 != 0){
		i_1 = (lpf->idx + 4 - 1) & 3;
		i_2 = (i_1 + 4 - 1) & 3;
		*out_p = (lpf->b0 * in
			+ lpf->b1 * lpf->in[i_1]
			+ lpf->b2 * lpf->in[i_2]
			- lpf->a1 * lpf->out[i_1]
			- lpf->a2 * lpf->out[i_2] ) * lpf->div_a0;
	}else{
		*out_p = 0;
	}
	lpf->idx = (lpf->idx + 1) & 3;
	return *out_p;
}


#define NOTE_BUF_N	256

struct note_rec{
	int ch;
	int note;
	int onoff;
	double on_sec;
	double off_sec;
	int velo;
	double cycle1, cycle2, sec, freq1, freq2;
	// cycle を cycle1, cycle2 に分離
	// freq を freq1, fre2 に分離
	
	double off_v;
	struct lpf_rec lpf;
} note_buf[NOTE_BUF_N];

int
note_buf_is_free(int i)
{
	return note_buf[i].ch < 0;
}

void
note_buf_free(int i)
{
	note_buf[i].ch = -1;
}

void
note_buf_init(void)
{
	int i;

	for(i=0; i<NOTE_BUF_N; i++) note_buf_free(i);
}

int
note_buf_search(int ch, int note, int onoff)
{
	int i;

	for(i=0; i<NOTE_BUF_N; i++) {
		if( (ch < 0 && note_buf[i].ch < 0) ||
		    (note_buf[i].ch == ch &&
		     note_buf[i].note == note &&
		     note_buf[i].onoff == onoff) ) return i;
	}
	return -1;
}

int
header(void)
{
	int v;

	if(!rd_str_chk(4, "MThd")) ERR("header id");
	if(rd_int(4) != 6) ERR("header size");
	if(rd_int(2) != 0) ERR("header format type");
	if(rd_int(2) != 1) ERR("header track num");
	if((v = rd_int(2)) & 0x8000) ERR("header division");
	return v; /* div4 */
}

double
note_to_freq(int note)
{
	return 440 * pow(2, (note - 69) / 12.0);
}

int
opt_idx(char *key, int ac, char **av)
{
	int i;

	for(i=1; i<ac; i++) if(strcmp(av[i], key) == 0) return i;
	return -1;
}

char *
opt_str(char *key, int ac, char **av, char *def)
{
	int i;

	i = opt_idx(key, ac, av);
	if(i < 0 || i+1 >= ac) return def;
	return av[i+1];
}

int
opt_int(char *key, int ac, char **av, int def)
{
	char *s;

	if((s = opt_str(key, ac, av, NULL)) == NULL) return def;
	return strtol(s, NULL, 0);
}

struct out_rec{
	int smp_freq, smp_cnt;
	int bit_len;
	int sign;
	int ch_num;
	FILE *fp;

	int base;
	int amp;
	int iv_min;
	int iv_max;
};

void
out_init(struct out_rec *ot, int ac, char **av)
{
	char cmd[1024], *fn;

	ot->smp_freq = opt_int("-r", ac, av, 8000);
	ot->smp_cnt = 0;
	ot->bit_len = opt_int("-b", ac, av, 8);
	if(ot->bit_len != 8 && ot->bit_len != 16) ERR("bit_len");
	ot->sign = (opt_idx("-s", ac, av) >= 0);
	ot->ch_num = opt_int("-c", ac, av, 1);

	ot->fp = stdout;
	cmd[0] = '\0';
	fn = "";
	if(opt_idx("-play", ac, av) >= 0){
		strcat(cmd, "play");
	}else if(opt_idx("-sox", ac, av) >= 0){
		strcat(cmd, "sox");
		fn = opt_str("-sox", ac, av, "-d");
	}
	if(cmd[0]){
		sprintf(cmd + strlen(cmd), " -t raw -r %d -b %d %s -c %d - %s",
			ot->smp_freq, ot->bit_len,
			ot->sign ? "-s" : "-u",
			ot->ch_num, fn);
		if((ot->fp = popen(cmd, "w")) == NULL) ERR("popen");
	}
	ot->amp = ot->bit_len == 8 ? 127 : 32767;
	ot->base = ot->sign ? 0 : ot->amp + 1;
	ot->iv_min = ot->base - (ot->amp + 1);
	ot->iv_max = ot->base + ot->amp;
}

void
out_do(struct out_rec *ot, double v)
{
	int iv;

	iv = ot->base + (int)(v *ot->amp);
	if(iv > ot->iv_max) iv = ot->iv_max;
	if(iv < ot->iv_min) iv = ot->iv_min;
	switch(ot->bit_len){
	case 8:
		fputc(iv, ot->fp);
		break;
	case 16:
		fputc(iv & 0xff, ot->fp);
		fputc((iv >> 8) & 0xff, ot->fp);
		break;
	}
}

#define WAVE_SIN	0
#define WAVE_SAW	1
#define WAVE_SQUARE	2
#define WAVE_NOISE	3

double
wave_out(int wave, double cycle)
{
	cycle -= (int)cycle;

	switch(wave){
	case WAVE_SIN:
		return sin(2 * M_PI * cycle);
	case WAVE_SAW:
		cycle *= 2;
		if(cycle > 1) cycle -= 2;
		return cycle;
	case WAVE_SQUARE:
		return cycle < 0.5 ? 1 : -1;
	case WAVE_NOISE:
		return ((double)rand() / RAND_MAX) * 2 - 1;
	}
	return 0;
}

struct env_rec{
	double attack;	/* sec */
	double decay;	/* sec */
	double sustain;	/* 0..1 */
	double release;	/* sec */
};

void
env_set(struct env_rec *e, double a, double d, double s, double r)
{
	e->attack = a;
	e->decay = d;
	e->sustain = s;
	e->release = r;
}

struct tone_rec{
	int wave1, wave2, tune;
	// wave を wave1, wave2 に分離
	// VCO2 用の tune 追加 (単位セント)
	
	double mix;
	// VCO1 とVCO2 の混合比 mix 追加
	
	double lpf_freq, lpf_Q;
	struct env_rec env;
	double level;
	int lfo_p1, lfo_p2, lfo_f;
	// lfo_p を lfo_p1, lfo_p2 に分離
	
	int lfo_wave;
	double lfo_freq, lfo_delay;
} tone_inf[] = {
	{	/* strings */
		WAVE_SAW, WAVE_SAW, 10, 0.5,
		3000, 1.5,
		{ 0.15, 0.5, 0.8, 0.5 },
		0.8,
		25, 0, 0, WAVE_SIN, 6, 0.3,
	},{	/* bass */
		WAVE_SAW, WAVE_SQUARE, 0, 0.5,
		1000, 1.5,
		{ 0.05, 0.2, 0.4, 0.2 },
		1.0,
		0, 60, 0, WAVE_SIN, 1.5, 0.2,
	},{	/* lead */
		WAVE_SQUARE, WAVE_SQUARE, 10, 0.5,
		2000, 4,
		{ 0.01, 0.2, 0.8, 0.3 },
		0.9,
		0, 1, 5, WAVE_SIN, 4, 0.3,
	},{	/* SIN */
		WAVE_SIN, WAVE_SIN, 0, 0,
		20000, 0.8,
		{ 0, 0.3, 0.2, 0.3 },
		1.0,
		25, 0, 0, WAVE_SIN, 6, 0.3,
	}
}, drum_tone_inf[] = {
	{	/* bass */
		WAVE_SIN, WAVE_NOISE, 0, 0.2,
		400, 1,
		{ 0.01, 0.18, 0, 0.18 },
		10.0,
		100, 0, 30, WAVE_NOISE, 0, 0.5,
	},{	/* snare */
		WAVE_NOISE, WAVE_SIN, 0, 0,
		1000, 1.7,
		{ 0, 0.3, 0.3, 0.3 },
		3.0,
		0, 0, 0, WAVE_SIN, 0, 10,
	},{	/* tom */
		WAVE_NOISE, WAVE_SIN, 0, 0,
		800, 2,
		{ 0, 0.3, 2, 0.4 },
		1.0,
		0, 0, 0, WAVE_SIN, 0, 0,
	},{	/* hi-hat close */
		WAVE_NOISE, WAVE_SIN, 0, 0,
		16000, 2,
		{ 0, 0.1, 0, 0.1 },
		0.8,
		0, 0, 0, WAVE_SIN, 0, 0,
	},{	/* hi-hat open */
		WAVE_NOISE, WAVE_SIN, 0, 0,
		16000, 2,
		{ 0, 0, 1, 0.3 },
		0.8,
		0, 0, 0, WAVE_SIN, 0, 0,
	},{	/* cymbal */
		WAVE_NOISE, WAVE_SIN, 0, 0,
		5000, 3,
		{ 0, 0.3, 0.3, 1 },
		0.8,
		0, 0, 200, WAVE_SIN, 3, 0.3,
	}
};

struct tone_rec *
tone_get(int prog, int note, double *ret_freq)
{
	int idx;
	struct tone_rec *ret;

	idx = -1;
	if(prog <= 0){ /* drum part */
		switch(note){
		case 36: /* bass drum1 */
			idx = 0;
			note = 28;
			break;
		case 37: /* side stick */
		case 40: /* electric snare */
			idx = 1;
			note = 69;
			break;
		case 41: /* low floor tom */
			idx = 2;
			note = 50;
			break;
		case 42: /* closed hi-hat */
			idx = 3;
			note = 115;
			break;
		case 46: /* open hi-hat */
			idx = 4;
			note = 115;
			break;
		case 49: /* crash cymbal 1 */
		case 57: /* crash cymbal 2 */
			idx = 5;
			note = 80;
			break;
		}
		ret = idx < 0 ? NULL : &drum_tone_inf[idx];
	}else{
		switch(prog){
		case 48: /* timpani */
		case 50: /* strings ensamble 2 */
			idx = 0;
			break;
		case 35: /* electric bass (pick) */
			idx = 1;
			break;
		case 79: /* whistle */
		case 81: /* lead 1 (square) */
		case 87: /* lead 7 (fifths) */
			idx = 2;
			break;
		case 24: /* tango accordion */
		case 67: /* tenor sax */
		default:
			idx = 3;
			break;
		}
		ret = &tone_inf[idx];
	}
	if(ret_freq) *ret_freq = note_to_freq(note);
	return ret;
}

#define MIDI_CH_N	16
struct ch_rec{
	int vol;
	int pan;
	int bend;
	int rpn;
	int bend_range;
	int prog;
} ch_inf[ MIDI_CH_N ];

#define CH_PROG(ch)	( (ch) == 9 ? 0 : ch_inf[ch].prog )

double
env_out(struct note_rec *nt)
{
	struct tone_rec *tn;
	struct env_rec *e;
	double sec, v;

	if((tn = tone_get(CH_PROG(nt->ch), nt->note, NULL)) == NULL) return 0;
	e = &tn->env;
	sec = nt->sec;
	if(nt->onoff){
		sec -= nt->on_sec;
		if(sec < e->attack){
			v = sec / e->attack;
			return log10(1 + v * 9);
		}
		sec -= e->attack;
		if(sec < e->decay){
			v = sec / e->decay;
			v = log10(1 + v * 9);
			return 1 - v * (1 - e->sustain);
		}
		return e->sustain;
	}
	sec -= nt->off_sec;
	if(sec < e->release){
		v = sec / e->release;
		v = log10(1 + v * 9);
		return (1 - v) * nt->off_v;
	}
	return 0;
}

void
data_out(struct out_rec *ot, double evt_sec)
{
	double v, v1, v2, sec, freq, freq1, freq2, dsec;
	// VCO1, VCO2 の波形の値を保持する変数 v1, v2 追加
	// VCO1, VCO2 の周波数を保持する変数 freq1, freq2 追加
	
	double vl, vr, pan;
	int i, nch;
	struct note_rec *nt;
	struct tone_rec *tn;
	double lfo_out;

	while((sec = (double)ot->smp_cnt / ot->smp_freq) < evt_sec){
		vl = vr = 0;
		for(i=0; i<NOTE_BUF_N; i++){
			if(note_buf_is_free(i)) continue;
			nt = &note_buf[i];
			nch = nt->ch;
			tn = tone_get(CH_PROG(nch), nt->note, &freq);
			if(tn == NULL) continue;

			if(ch_inf[nch].bend != 0) freq *= pow(2, ch_inf[nch].bend / 8192.0 * ch_inf[nch].bend_range / 12);
			freq1 = freq2 = freq;
			// VCO1, VCO2 用の周波数を保持する変数
			// freq1, freq2 初期化
			
			freq2 *= pow(2, (tn->tune / 100.0) / 12);
			// VCO2 の tune で freq2 更新
			
			dsec = sec - nt->on_sec - tn->lfo_delay;
			if((tn->lfo_p1 || tn->lfo_p2 || tn->lfo_f) && dsec > 0){
			// lfo_p 箇所 lfo_p1, lfo_p2 で置き換え
			
				lfo_out = wave_out(tn->lfo_wave, tn->lfo_freq * dsec);
			}
			if(tn->lfo_p1 && dsec > 0) freq1 *= pow(2, lfo_out * (tn->lfo_p1 / 100.0) / 12);
			nt->cycle1 += freq1 * (sec - nt->sec);
			nt->freq1 = freq1;
			// 従来のピッチへのLFO 処理、サイクル数の更新、周波数の記録などは、
			// VCO1 用の処理に
			
			if(tn->lfo_p2 && dsec > 0) freq2 *= pow(2, lfo_out * (tn->lfo_p2 / 100.0) / 12);
			nt->cycle2 += freq2 * (sec - nt->sec);
			nt->freq2 = freq2;
			// 新たに VCO2 用の処理を追加
			
			nt->sec = sec;
			v1 = wave_out(tn->wave1, nt->cycle1);
			v2 = wave_out(tn->wave2, nt->cycle2);
			// 従来のVCOの波形生成は、
			// VCO1用、VCO2用に分離
			
			v = v1 * (1 - tn->mix) + v2 * tn->mix;
			// 追加した VCO1, VCO2 の混合比 mix で混合
			
			if(nt->lpf.idx < 0) lpf_init(&nt->lpf, ot->smp_freq, tn->lpf_freq, tn->lpf_Q);
			if(tn->lfo_f && dsec > 0){
				freq = tn->lpf_freq * pow(2, lfo_out * (tn->lfo_f / 100.0) / 12);
				lpf_update(&nt->lpf, ot->smp_freq, freq, tn->lpf_Q);
			}
			v = lpf_out(&nt->lpf, v);

			v *= env_out(&note_buf[i]) * tn->level;
			v *= nt->velo / 127.0;
			v *= ch_inf[nch].vol / (double)((1<<14)-1);
			if(ot->ch_num == 1){
				vl += v;
			}else{
				pan = ch_inf[nch].pan / (double)(1<<14);
				vl += (1 - pan) * v;
				vr += pan * v;
			}
			if(nt->onoff == 0 && sec - nt->off_sec >= tn->env.release) note_buf_free(i);
		}
		out_do(ot, vl / 16);
		if(ot->ch_num > 1) out_do(ot, vr / 16);
		ot->smp_cnt++;
	}
}

void
note_onoff(int onoff, double evt_sec, int ch, int note, int velo)
{
	int i;

	if(onoff){
		if((i = note_buf_search(-1, -1, -1)) < 0){
			MSG("note_buf full");
			return;
		}
		note_buf[i].note = note;
		note_buf[i].ch = ch;
		note_buf[i].onoff = 1;
		note_buf[i].on_sec = evt_sec;
		note_buf[i].velo = velo;
		note_buf[i].cycle1 = 0;
		note_buf[i].cycle2 = 0;
		// 従来の cycle の初期化は
		// cycle1, cycle2 に分離
		
		note_buf[i].sec = evt_sec;
		note_buf[i].lpf.idx = -1;
	}else{
		if((i = note_buf_search(ch, note, 1)) < 0) return;
		note_buf[i].off_v = env_out(&note_buf[i]);
		note_buf[i].onoff = 0;
		note_buf[i].off_sec = evt_sec;
	}
}

void
msb_set(int *vp, int v)
{
	*vp &= ~(127<<7);
	*vp |= v<<7;
}

void
lsb_set(int *vp, int v)
{
	*vp &= ~127;
	*vp |= v;
}

void
bend_note_update(int ch, double sec)
{
	int i;
	struct note_rec *nt;

	for(i=0; i<NOTE_BUF_N; i++){
		if(note_buf_is_free(i)) continue;
		nt = &note_buf[i];
		if(nt->ch != ch) continue;
		nt->cycle1 += nt->freq1 * (sec - nt->sec);
		nt->cycle2 += nt->freq2 * (sec - nt->sec);
		// 従来の cycle の更新処理は、cycle1, cycle2 に分離
		
		nt->sec = sec;
	}
}

int
main(int ac, char **av)
{
	int div4, delta_sum;
	int i, n, v, hi, low, note, velo;
	int ch, type;
	double sec;
	struct out_rec otr;
	int tempo, tempo_delta_sum;
	double tempo_sec;

	out_init(&otr, ac, av);
	note_buf_init();
	for(i=0; i<MIDI_CH_N; i++){
		ch_inf[i].vol = 0;
		ch_inf[i].pan = 1<<(14-1);
		ch_inf[i].bend = 0;
		ch_inf[i].rpn = 0;
		ch_inf[i].bend_range = 2;
		ch_inf[i].prog =-1;
	}
	tempo = 500000;
	tempo_delta_sum = 0;
	tempo_sec = 0;

	div4 = header();

	if(!rd_str_chk(4, "MTrk")) ERR("track id");
	v = rd_int(4); /* skip */

	hi = low = 0;
	delta_sum = 0;
	while((v = rd_delta()) != EOF){
		delta_sum += v;
		sec = tempo_sec + (double)(delta_sum - tempo_delta_sum) / div4 * tempo * 0.000001;
		
		if((v = rd()) & 0x80){
			hi = (v >> 4) & 0xf;
			low  = v & 0xf;
		}else bk(v);

		data_out(&otr, sec);

		ch = low;
		switch(hi){
		case 8:
		case 9:
			note = rd();
			velo = rd();
			note_onoff(hi == 9, sec, ch, note, velo);
			break;
		case 0xb: /* control change */
			type = rd();
			v = rd();
			switch(type){
			case 7: /* channel volume msb */
				msb_set(&ch_inf[ch].vol, v);
				break;
			case 39: /* channel volume lsb */
				lsb_set(&ch_inf[ch].vol, v);
				break;
			case 10: /* pan msb */
				msb_set(&ch_inf[ch].pan, v);
				break;
			case 42: /* pan lsb */
				lsb_set(&ch_inf[ch].pan, v);
				break;
			case 100: /* rpn lsb */
				lsb_set(&ch_inf[ch].rpn, v);
				break;
			case 101: /* rpn msb */
				msb_set(&ch_inf[ch].rpn, v);
				break;
			case 6: /* data entry msb */
				switch(ch_inf[ch].rpn){
				case 0: /* pitch bend range */
					ch_inf[ch].bend_range = v;
					break;
				}
				break;
			}
			break;
		case 0xa:
			rd();
			rd();
			break;
		case 0xe: /* pitch wheel change */
			bend_note_update(ch, sec);
			v = rd();
			v |= rd() << 7;
			ch_inf[ch].bend = v - 8192;
			break;
		case 0xc: /* program number */
			v = rd();
			ch_inf[ch].prog = v;
			break;
		case 0xd:
			rd();
			break;
		case 0xf:
			type = rd();
			switch(low){
			case 0:
				while(rd() != 0xf7);
				break;
			case 1:
			case 3:
				rd();
				break;
			case 2:
				rd();
				rd();
				break;
			case 0xf: /* meta */
				n = rd();
				switch(type){
				case 0x51: /* set tempo */
					v = rd_int(n);
					tempo = v;
					tempo_delta_sum = delta_sum;
					tempo_sec = sec;
					break;
				default:
					for(i=0; i<n; i++) rd();
					break;
				}
				break;
			default:
				break;
			}
			break;
		}
	}
	if(otr.fp != stdout) pclose(otr.fp);
	return 0;
}

/* EOF */


prog15.c 解説

prog14.c からの変更箇所のみ

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <math.h>

#define MSG(s) fprintf(stderr, "%s() %s L%d : %s\n", __func__, __FILE__, __LINE__, s)
#define ERR(s) do{ fprintf(stderr, "ERR "); MSG(s); exit(1); }while(0)

int bk_buf = -1;

int
rd(void)
{
	int v;

	if((v = bk_buf) < 0) return getchar();
	bk_buf = -1;
	return v;
}

void
bk(int v)
{
	if(bk_buf >= 0) ERR("give up");
	bk_buf = v;
}

void
rd_str(int n, char *s)
{
	int i;

	for(i=0; i<n; i++) s[i] = rd();
	s[i] = '\0';
}

int
rd_str_chk(int n, char *s)
{
	char buf[256];

	rd_str(n, buf);
	return strcmp(buf, s) == 0;
}

int
rd_int(int n) /* big endian */
{
	int i, v;

	v = 0;
	for(i=0; i<n; i++) v = (v << 8) | rd();
	return v;
}

int
rd_delta(void)
{
	int v, c;

	v = 0;
	do{
		if((c = rd()) == EOF) return EOF;
		v = (v << 7) | (c & 0x7f);
	}while(c & 0x80);
	return v;
}


struct lpf_rec{
	int idx;
	double in[4], out[4];
	double a0, a1, a2, b0, b1, b2, div_a0;
};

void
lpf_update(struct lpf_rec *lpf, double smp_freq, double freq, double Q)
{
	double w0, alpha;

	w0 = 2 * M_PI * freq / smp_freq;
	alpha = sin(w0) / (2 * Q);
	lpf->b1 = 1 - cos(w0);
	lpf->b0 = lpf->b2 = lpf->b1 * 0.5;
	lpf->a0 = 1 + alpha;
	lpf->a1 = -2 * cos(w0);
	lpf->a2 = 1 - alpha;
	if(lpf->a0 != 0) lpf->div_a0 = 1 / lpf->a0;
}

void
lpf_init(struct lpf_rec *lpf, double smp_freq, double freq, double Q)
{
	int i;


	for(i=0; i<4; i++) lpf->in[i] = lpf->out[i] = 0;
	lpf->idx = 0;

	lpf_update(lpf, smp_freq, freq, Q);
}

double
lpf_out(struct lpf_rec *lpf, double in)
{
	double *out_p;
	int i_1, i_2;

	lpf->in[lpf->idx] = in;
	out_p = &lpf->out[lpf->idx];

	if(lpf->a0 != 0){
		i_1 = (lpf->idx + 4 - 1) & 3;
		i_2 = (i_1 + 4 - 1) & 3;
		*out_p = (lpf->b0 * in
			+ lpf->b1 * lpf->in[i_1]
			+ lpf->b2 * lpf->in[i_2]
			- lpf->a1 * lpf->out[i_1]
			- lpf->a2 * lpf->out[i_2] ) * lpf->div_a0;
	}else{
		*out_p = 0;
	}
	lpf->idx = (lpf->idx + 1) & 3;
	return *out_p;
}


#define NOTE_BUF_N	256

struct vco_stat_rec{
	double cycle, freq, sec;
};

void
vco_stat_update(struct vco_stat_rec *stat, double freq, double sec)
{
	stat->cycle += freq * (sec - stat->sec);	
	stat->freq = freq;
	stat->sec = sec;
}

struct note_rec{
	int ch;
	int note;
	int onoff;
	double on_sec;
	double off_sec;
	int velo;
	struct vco_stat_rec vco_stat[2];
	double off_v;
	struct lpf_rec lpf;
} note_buf[NOTE_BUF_N];

int
note_buf_is_free(int i)
{
	return note_buf[i].ch < 0;
}

void
note_buf_free(int i)
{
	note_buf[i].ch = -1;
}

void
note_buf_init(void)
{
	int i;

	for(i=0; i<NOTE_BUF_N; i++) note_buf_free(i);
}

int
note_buf_search(int ch, int note, int onoff)
{
	int i;

	for(i=0; i<NOTE_BUF_N; i++) {
		if( (ch < 0 && note_buf[i].ch < 0) ||
		    (note_buf[i].ch == ch &&
		     note_buf[i].note == note &&
		     note_buf[i].onoff == onoff) ) return i;
	}
	return -1;
}

int
header(void)
{
	int v;

	if(!rd_str_chk(4, "MThd")) ERR("header id");
	if(rd_int(4) != 6) ERR("header size");
	if(rd_int(2) != 0) ERR("header format type");
	if(rd_int(2) != 1) ERR("header track num");
	if((v = rd_int(2)) & 0x8000) ERR("header division");
	return v; /* div4 */
}

double
note_to_freq(int note)
{
	return 440 * pow(2, (note - 69) / 12.0);
}

int
opt_idx(char *key, int ac, char **av)
{
	int i;

	for(i=1; i<ac; i++) if(strcmp(av[i], key) == 0) return i;
	return -1;
}

char *
opt_str(char *key, int ac, char **av, char *def)
{
	int i;

	i = opt_idx(key, ac, av);
	if(i < 0 || i+1 >= ac) return def;
	return av[i+1];
}

int
opt_int(char *key, int ac, char **av, int def)
{
	char *s;

	if((s = opt_str(key, ac, av, NULL)) == NULL) return def;
	return strtol(s, NULL, 0);
}

struct out_rec{
	int smp_freq, smp_cnt;
	int bit_len;
	int sign;
	int ch_num;
	FILE *fp;

	int base;
	int amp;
	int iv_min;
	int iv_max;
};

void
out_init(struct out_rec *ot, int ac, char **av)
{
	char cmd[1024], *fn;

	ot->smp_freq = opt_int("-r", ac, av, 44100);
	ot->smp_cnt = 0;
	ot->bit_len = opt_int("-b", ac, av, 16);
	if(ot->bit_len != 8 && ot->bit_len != 16) ERR("bit_len");
	ot->sign = (opt_idx("-u", ac, av) < 0);
	ot->ch_num = opt_int("-c", ac, av, 2);

	ot->fp = stdout;
	cmd[0] = '\0';
	fn = "";
	if(opt_idx("-play", ac, av) >= 0){
		strcat(cmd, "play");
	}else if(opt_idx("-sox", ac, av) >= 0){
		strcat(cmd, "sox");
		fn = opt_str("-sox", ac, av, "-d");
	}
	if(cmd[0]){
		sprintf(cmd + strlen(cmd), " -t raw -r %d -b %d %s -c %d - %s",
			ot->smp_freq, ot->bit_len,
			ot->sign ? "-s" : "-u",
			ot->ch_num, fn);
		if((ot->fp = popen(cmd, "w")) == NULL) ERR("popen");
	}
	ot->amp = ot->bit_len == 8 ? 127 : 32767;
	ot->base = ot->sign ? 0 : ot->amp + 1;
	ot->iv_min = ot->base - (ot->amp + 1);
	ot->iv_max = ot->base + ot->amp;
}

void
out_do(struct out_rec *ot, double v)
{
	int iv;

	iv = ot->base + (int)(v *ot->amp);
	if(iv > ot->iv_max) iv = ot->iv_max;
	if(iv < ot->iv_min) iv = ot->iv_min;
	switch(ot->bit_len){
	case 8:
		fputc(iv, ot->fp);
		break;
	case 16:
		fputc(iv & 0xff, ot->fp);
		fputc((iv >> 8) & 0xff, ot->fp);
		break;
	}
}

#define WAVE_SIN	0
#define WAVE_SAW	1
#define WAVE_SQUARE	2
#define WAVE_NOISE	3

double
wave_out(int wave, double cycle)
{
	cycle -= (int)cycle;

	switch(wave){
	case WAVE_SIN:
		return sin(2 * M_PI * cycle);
	case WAVE_SAW:
		cycle *= 2;
		if(cycle > 1) cycle -= 2;
		return cycle;
	case WAVE_SQUARE:
		return cycle < 0.5 ? 1 : -1;
	case WAVE_NOISE:
		return ((double)rand() / RAND_MAX) * 2 - 1;
	}
	return 0;
}

struct vco_rec{
	int wave1, wave2;
	int tune; /* for vco2 */
	double mix;
};

struct lfo_rec{
	int pitch1, pitch2;
	int filter;
	int wave;
	double freq, delay;
};

struct env_rec{
	double attack;	/* sec */
	double decay;	/* sec */
	double sustain;	/* 0..1 */
	double release;	/* sec */
};

struct tone_rec{
	struct vco_rec vco;
	double lpf_freq, lpf_Q;
	struct env_rec env;
	double level;
	struct lfo_rec lfo;
} tone_inf[] = {
	{	/* strings */
		{ WAVE_SAW, WAVE_SAW, 10, 0.5 },
		3000, 1.5,
		{ 0.15, 0.5, 0.8, 0.5 },
		0.8,
		{ 25, 0, 0, WAVE_SIN, 6, 0.3 },
	},{	/* bass */
		{ WAVE_SAW, WAVE_SQUARE, 0, 0.5 },
		1000, 1.5,
		{ 0.05, 0.2, 0.4, 0.2 },
		1.0,
		{ 0, 60, 0, WAVE_SIN, 1.5, 0.2 },
	},{	/* lead */
		{ WAVE_SQUARE, WAVE_SQUARE, 10, 0.5 },
		2000, 4,
		{ 0.01, 0.2, 0.8, 0.3 },
		0.9,
		{ 0, 1, 5, WAVE_SIN, 4, 0.3 },
	},{	/* SIN */
		{ WAVE_SIN, WAVE_SIN, 0, 0 },
		20000, 0.8,
		{ 0, 0.3, 0.2, 0.3 },
		1.0,
		{ 25, 0, 0, WAVE_SIN, 6, 0.3 },
	}
}, drum_tone_inf[] = {
	{	/* bass */
		{ WAVE_SIN, WAVE_NOISE, 0, 0.2 },
		400, 1,
		{ 0.01, 0.18, 0, 0.18 },
		10.0,
		{ 100, 0, 30, WAVE_NOISE, 0, 0.5 },
	},{	/* snare */
		{ WAVE_NOISE, WAVE_SIN, 0, 0 },
		1000, 1.7,
		{ 0, 0.3, 0.3, 0.3 },
		3.0,
		{ 0, 0, 0, WAVE_SIN, 0, 10 },
	},{	/* tom */
		{ WAVE_NOISE, WAVE_SIN, 0, 0 },
		800, 2,
		{ 0, 0.3, 2, 0.4 },
		1.0,
		{ 0, 0, 0, WAVE_SIN, 0, 0 },
	},{	/* hi-hat close */
		{ WAVE_NOISE, WAVE_SIN, 0, 0 },
		16000, 2,
		{ 0, 0.1, 0, 0.1 },
		0.8,
		{ 0, 0, 0, WAVE_SIN, 0, 0 },
	},{	/* hi-hat open */
		{ WAVE_NOISE, WAVE_SIN, 0, 0 },
		16000, 2,
		{ 0, 0, 1, 0.3 },
		0.8,
		{ 0, 0, 0, WAVE_SIN, 0, 0 },
	},{	/* cymbal */
		{ WAVE_NOISE, WAVE_SIN, 0, 0 },
		5000, 3,
		{ 0, 0.3, 0.3, 1 },
		0.8,
		{ 0, 0, 200, WAVE_SIN, 3, 0.3 },
	}
};

struct tone_rec *
tone_get(int prog, int note, double *ret_freq)
{
	int idx;
	struct tone_rec *ret;

	idx = -1;
	if(prog <= 0){ /* drum part */
		switch(note){
		case 36: /* bass drum1 */
			idx = 0;
			note = 28;
			break;
		case 37: /* side stick */
		case 40: /* electric snare */
			idx = 1;
			note = 69;
			break;
		case 41: /* low floor tom */
			idx = 2;
			note = 50;
			break;
		case 42: /* closed hi-hat */
			idx = 3;
			note = 115;
			break;
		case 46: /* open hi-hat */
			idx = 4;
			note = 115;
			break;
		case 49: /* crash cymbal 1 */
		case 57: /* crash cymbal 2 */
			idx = 5;
			note = 80;
			break;
		}
		ret = idx < 0 ? NULL : &drum_tone_inf[idx];
	}else{
		switch(prog){
		case 48: /* timpani */
		case 50: /* strings ensamble 2 */
			idx = 0;
			break;
		case 35: /* electric bass (pick) */
			idx = 1;
			break;
		case 79: /* whistle */
		case 81: /* lead 1 (square) */
		case 87: /* lead 7 (fifths) */
			idx = 2;
			break;
		case 24: /* tango accordion */
		case 67: /* tenor sax */
		default:
			idx = 3;
			break;
		}
		ret = &tone_inf[idx];
	}
	if(ret_freq) *ret_freq = note_to_freq(note);
	return ret;
}

#define MIDI_CH_N	16
struct ch_rec{
	int vol;
	int pan;
	int bend;
	int rpn;
	int bend_range;
	int prog;
} ch_inf[ MIDI_CH_N ];

#define CH_PROG(ch)	( (ch) == 9 ? 0 : ch_inf[ch].prog )

double
env_out(struct note_rec *nt)
{
	struct tone_rec *tn;
	struct env_rec *e;
	double sec, v;

	if((tn = tone_get(CH_PROG(nt->ch), nt->note, NULL)) == NULL) return 0;
	e = &tn->env;
	sec = nt->vco_stat[0].sec;
	if(nt->onoff){
		sec -= nt->on_sec;
		if(sec < e->attack){
			v = sec / e->attack;
			return log10(1 + v * 9);
		}
		sec -= e->attack;
		if(sec < e->decay){
			v = sec / e->decay;
			v = log10(1 + v * 9);
			return 1 - v * (1 - e->sustain);
		}
		return e->sustain;
	}
	sec -= nt->off_sec;
	if(sec < e->release){
		v = sec / e->release;
		v = log10(1 + v * 9);
		return (1 - v) * nt->off_v;
	}
	return 0;
}

struct lfo_work_rec{
	int value; /* lfo_rec.pitch1, pitch2 or filter */
	double dsec; /* after delay (sec - on_sec - delay) */
	double out;
};

void
lfo_out(struct lfo_rec *lfo, struct lfo_work_rec *lfo_wk, double sec, double on_sec)
{
	lfo_wk->dsec = sec - on_sec - lfo->delay;
	if((lfo->pitch1 || lfo->pitch2 || lfo->filter) && lfo_wk->dsec > 0){
		lfo_wk->out = wave_out(lfo->wave, lfo->freq * lfo_wk->dsec);
	}
}

double
vco_out(int wave, struct vco_stat_rec *stat, double freq, double sec, struct lfo_work_rec *lfo_wk)
{
	if(lfo_wk->value && lfo_wk->dsec > 0) freq *= pow(2, lfo_wk->out * (lfo_wk->value / 100.0) / 12);
	vco_stat_update(stat, freq, sec);
	return wave_out(wave, stat->cycle);
}

double
vcf_out(double lpf_freq, double lpf_Q, struct lpf_rec *lpf, struct out_rec *ot, struct lfo_work_rec *lfo_wk, double v)
{
	if(lpf->idx < 0) lpf_init(lpf, ot->smp_freq, lpf_freq, lpf_Q);
	if(lfo_wk->value && lfo_wk->dsec > 0){
		lpf_freq *= pow(2, lfo_wk->out * (lfo_wk->value / 100.0) / 12);
		lpf_update(lpf, ot->smp_freq, lpf_freq, lpf_Q);
	}
	return lpf_out(lpf, v);
}

int
note_out(struct out_rec *ot, double sec, struct note_rec *nt, double *vl, double *vr)
{
	double v, v1, v2, freq, pan;
	int nch;
	struct tone_rec *tn;
	struct vco_rec *vco;
	struct lfo_rec *lfo;
	struct lfo_work_rec lfo_wk;

	nch = nt->ch;
	tn = tone_get(CH_PROG(nch), nt->note, &freq);
	if(tn == NULL) return 0;

	if(ch_inf[nch].bend != 0) freq *= pow(2, ch_inf[nch].bend / 8192.0 * ch_inf[nch].bend_range / 12);

	lfo = &tn->lfo;
	lfo_out(lfo, &lfo_wk, sec, nt->on_sec);

	vco = &tn->vco;
	lfo_wk.value = lfo->pitch1;
	v1 = vco_out(vco->wave1, &nt->vco_stat[0], freq, sec, &lfo_wk);
	freq *= pow(2, (vco->tune / 100.0) / 12);
	lfo_wk.value = lfo->pitch2;
	v2 = vco_out(vco->wave2, &nt->vco_stat[1], freq, sec, &lfo_wk);
	v = v1 * (1 - vco->mix) + v2 * vco->mix;

	lfo_wk.value = lfo->filter;
	v = vcf_out(tn->lpf_freq, tn->lpf_Q, &nt->lpf, ot, &lfo_wk, v);

	v *= env_out(nt) * tn->level;
	v *= nt->velo / 127.0;
	v *= ch_inf[nch].vol / (double)((1<<14)-1);
	if(ot->ch_num == 1){
		*vl += v;
	}else{
	pan = ch_inf[nch].pan / (double)(1<<14);
		*vl += (1 - pan) * v;
		*vr += pan * v;
	}
	return (nt->onoff == 0 && sec - nt->off_sec >= tn->env.release);
}

void
data_out(struct out_rec *ot, double evt_sec)
{
	double sec, vl, vr;
	int i;
	struct note_rec *nt;

	while((sec = (double)ot->smp_cnt / ot->smp_freq) < evt_sec){
		vl = vr = 0;
		for(i=0; i<NOTE_BUF_N; i++){
			if(note_buf_is_free(i)) continue;
			nt = &note_buf[i];
			if(note_out(ot, sec, nt, &vl, &vr)) note_buf_free(i);
		}
		out_do(ot, vl / 16);
		if(ot->ch_num > 1) out_do(ot, vr / 16);
		ot->smp_cnt++;
	}
}

void
note_onoff(int onoff, double evt_sec, int ch, int note, int velo)
{
	int i, j;
	struct vco_stat_rec *stat;

	if(onoff){
		if((i = note_buf_search(-1, -1, -1)) < 0){
			MSG("note_buf full");
			return;
		}
		note_buf[i].note = note;
		note_buf[i].ch = ch;
		note_buf[i].onoff = 1;
		note_buf[i].on_sec = evt_sec;
		note_buf[i].velo = velo;
		for(j=0; j<2; j++){
			stat = &note_buf[i].vco_stat[j];
			stat->cycle = 0;
			stat->sec = evt_sec;
		}
		note_buf[i].lpf.idx = -1;
	}else{
		if((i = note_buf_search(ch, note, 1)) < 0) return;
		note_buf[i].off_v = env_out(&note_buf[i]);
		note_buf[i].onoff = 0;
		note_buf[i].off_sec = evt_sec;
	}
}

void
msb_set(int *vp, int v)
{
	*vp &= ~(127<<7);
	*vp |= v<<7;
}

void
lsb_set(int *vp, int v)
{
	*vp &= ~127;
	*vp |= v;
}

void
bend_note_update(int ch, double sec)
{
	int i, j;
	struct note_rec *nt;
	struct vco_stat_rec *stat;

	for(i=0; i<NOTE_BUF_N; i++){
		if(note_buf_is_free(i)) continue;
		nt = &note_buf[i];
		if(nt->ch != ch) continue;
		for(j=0; j<2; j++){
			stat = &nt->vco_stat[j];
			vco_stat_update(stat, stat->freq, sec);
		}
	}
}

int
main(int ac, char **av)
{
	int div4, delta_sum;
	int i, n, v, hi, low, note, velo;
	int ch, type;
	double sec;
	struct out_rec otr;
	int tempo, tempo_delta_sum;
	double tempo_sec;

	out_init(&otr, ac, av);
	note_buf_init();
	for(i=0; i<MIDI_CH_N; i++){
		ch_inf[i].vol = 0;
		ch_inf[i].pan = 1<<(14-1);
		ch_inf[i].bend = 0;
		ch_inf[i].rpn = 0;
		ch_inf[i].bend_range = 2;
		ch_inf[i].prog =-1;
	}
	tempo = 500000;
	tempo_delta_sum = 0;
	tempo_sec = 0;

	div4 = header();

	if(!rd_str_chk(4, "MTrk")) ERR("track id");
	v = rd_int(4); /* skip */

	hi = low = 0;
	delta_sum = 0;
	while((v = rd_delta()) != EOF){
		delta_sum += v;
		sec = tempo_sec + (double)(delta_sum - tempo_delta_sum) / div4 * tempo * 0.000001;
		
		if((v = rd()) & 0x80){
			hi = (v >> 4) & 0xf;
			low  = v & 0xf;
		}else bk(v);

		data_out(&otr, sec);

		ch = low;
		switch(hi){
		case 8:
		case 9:
			note = rd();
			velo = rd();
			note_onoff(hi == 9, sec, ch, note, velo);
			break;
		case 0xb: /* control change */
			type = rd();
			v = rd();
			switch(type){
			case 7: /* channel volume msb */
				msb_set(&ch_inf[ch].vol, v);
				break;
			case 39: /* channel volume lsb */
				lsb_set(&ch_inf[ch].vol, v);
				break;
			case 10: /* pan msb */
				msb_set(&ch_inf[ch].pan, v);
				break;
			case 42: /* pan lsb */
				lsb_set(&ch_inf[ch].pan, v);
				break;
			case 100: /* rpn lsb */
				lsb_set(&ch_inf[ch].rpn, v);
				break;
			case 101: /* rpn msb */
				msb_set(&ch_inf[ch].rpn, v);
				break;
			case 6: /* data entry msb */
				switch(ch_inf[ch].rpn){
				case 0: /* pitch bend range */
					ch_inf[ch].bend_range = v;
					break;
				}
				break;
			}
			break;
		case 0xa:
			rd();
			rd();
			break;
		case 0xe: /* pitch wheel change */
			bend_note_update(ch, sec);
			v = rd();
			v |= rd() << 7;
			ch_inf[ch].bend = v - 8192;
			break;
		case 0xc: /* program number */
			v = rd();
			ch_inf[ch].prog = v;
			break;
		case 0xd:
			rd();
			break;
		case 0xf:
			type = rd();
			switch(low){
			case 0:
				while(rd() != 0xf7);
				break;
			case 1:
			case 3:
				rd();
				break;
			case 2:
				rd();
				rd();
				break;
			case 0xf: /* meta */
				n = rd();
				switch(type){
				case 0x51: /* set tempo */
					v = rd_int(n);
					tempo = v;
					tempo_delta_sum = delta_sum;
					tempo_sec = sec;
					break;
				default:
					for(i=0; i<n; i++) rd();
					break;
				}
				break;
			default:
				break;
			}
			break;
		}
	}
	if(otr.fp != stdout) pclose(otr.fp);
	return 0;
}

/* EOF */


#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <math.h>

#define MSG(s) fprintf(stderr, "%s() %s L%d : %s\n", __func__, __FILE__, __LINE__, s)
#define ERR(s) do{ fprintf(stderr, "ERR "); MSG(s); exit(1); }while(0)

int bk_buf = -1;

int
rd(void)
{
	int v;

	if((v = bk_buf) < 0) return getchar();
	bk_buf = -1;
	return v;
}

void
bk(int v)
{
	if(bk_buf >= 0) ERR("give up");
	bk_buf = v;
}

void
rd_str(int n, char *s)
{
	int i;

	for(i=0; i<n; i++) s[i] = rd();
	s[i] = '\0';
}

int
rd_str_chk(int n, char *s)
{
	char buf[256];

	rd_str(n, buf);
	return strcmp(buf, s) == 0;
}

int
rd_int(int n) /* big endian */
{
	int i, v;

	v = 0;
	for(i=0; i<n; i++) v = (v << 8) | rd();
	return v;
}

int
rd_delta(void)
{
	int v, c;

	v = 0;
	do{
		if((c = rd()) == EOF) return EOF;
		v = (v << 7) | (c & 0x7f);
	}while(c & 0x80);
	return v;
}


struct lpf_rec{
	int idx;
	double in[4], out[4];
	double a0, a1, a2, b0, b1, b2, div_a0;
};

void
lpf_update(struct lpf_rec *lpf, double smp_freq, double freq, double Q)
{
	double w0, alpha;

	w0 = 2 * M_PI * freq / smp_freq;
	alpha = sin(w0) / (2 * Q);
	lpf->b1 = 1 - cos(w0);
	lpf->b0 = lpf->b2 = lpf->b1 * 0.5;
	lpf->a0 = 1 + alpha;
	lpf->a1 = -2 * cos(w0);
	lpf->a2 = 1 - alpha;
	if(lpf->a0 != 0) lpf->div_a0 = 1 / lpf->a0;
}

void
lpf_init(struct lpf_rec *lpf, double smp_freq, double freq, double Q)
{
	int i;


	for(i=0; i<4; i++) lpf->in[i] = lpf->out[i] = 0;
	lpf->idx = 0;

	lpf_update(lpf, smp_freq, freq, Q);
}

double
lpf_out(struct lpf_rec *lpf, double in)
{
	double *out_p;
	int i_1, i_2;

	lpf->in[lpf->idx] = in;
	out_p = &lpf->out[lpf->idx];

	if(lpf->a0 != 0){
		i_1 = (lpf->idx + 4 - 1) & 3;
		i_2 = (i_1 + 4 - 1) & 3;
		*out_p = (lpf->b0 * in
			+ lpf->b1 * lpf->in[i_1]
			+ lpf->b2 * lpf->in[i_2]
			- lpf->a1 * lpf->out[i_1]
			- lpf->a2 * lpf->out[i_2] ) * lpf->div_a0;
	}else{
		*out_p = 0;
	}
	lpf->idx = (lpf->idx + 1) & 3;
	return *out_p;
}


#define NOTE_BUF_N	256

struct vco_stat_rec{
	double cycle, freq, sec;
};
// 構造体 note_rec にあった、VCOの状態関連のメンバを
// 構造体 vco_stat_rec としてまとめた

void
vco_stat_update(struct vco_stat_rec *stat, double freq, double sec)
{
	stat->cycle += freq * (sec - stat->sec);	
	stat->freq = freq;
	stat->sec = sec;
}
// 構造体 vco_stat_rec の内容 (VCOの状態) を、
// 周波数 freq で、時刻 sec まで出力した状態に更新する

struct note_rec{
	int ch;
	int note;
	int onoff;
	double on_sec;
	double off_sec;
	int velo;
	struct vco_stat_rec vco_stat[2];
	// VCOの状態関連のメンバを
	// 追加した構造体 vco_stat_rec に置き換え
	
	double off_v;
	struct lpf_rec lpf;
} note_buf[NOTE_BUF_N];

int
note_buf_is_free(int i)
{
	return note_buf[i].ch < 0;
}

void
note_buf_free(int i)
{
	note_buf[i].ch = -1;
}

void
note_buf_init(void)
{
	int i;

	for(i=0; i<NOTE_BUF_N; i++) note_buf_free(i);
}

int
note_buf_search(int ch, int note, int onoff)
{
	int i;

	for(i=0; i<NOTE_BUF_N; i++) {
		if( (ch < 0 && note_buf[i].ch < 0) ||
		    (note_buf[i].ch == ch &&
		     note_buf[i].note == note &&
		     note_buf[i].onoff == onoff) ) return i;
	}
	return -1;
}

int
header(void)
{
	int v;

	if(!rd_str_chk(4, "MThd")) ERR("header id");
	if(rd_int(4) != 6) ERR("header size");
	if(rd_int(2) != 0) ERR("header format type");
	if(rd_int(2) != 1) ERR("header track num");
	if((v = rd_int(2)) & 0x8000) ERR("header division");
	return v; /* div4 */
}

double
note_to_freq(int note)
{
	return 440 * pow(2, (note - 69) / 12.0);
}

int
opt_idx(char *key, int ac, char **av)
{
	int i;

	for(i=1; i<ac; i++) if(strcmp(av[i], key) == 0) return i;
	return -1;
}

char *
opt_str(char *key, int ac, char **av, char *def)
{
	int i;

	i = opt_idx(key, ac, av);
	if(i < 0 || i+1 >= ac) return def;
	return av[i+1];
}

int
opt_int(char *key, int ac, char **av, int def)
{
	char *s;

	if((s = opt_str(key, ac, av, NULL)) == NULL) return def;
	return strtol(s, NULL, 0);
}

struct out_rec{
	int smp_freq, smp_cnt;
	int bit_len;
	int sign;
	int ch_num;
	FILE *fp;

	int base;
	int amp;
	int iv_min;
	int iv_max;
};

void
out_init(struct out_rec *ot, int ac, char **av)
{
	char cmd[1024], *fn;

	ot->smp_freq = opt_int("-r", ac, av, 44100);
	// サンプリング周波数のデフォルト値を 44100 Hz に変更
	
	ot->smp_cnt = 0;
	ot->bit_len = opt_int("-b", ac, av, 16);
	// ビット長のデフォルト値を 16 bit に変更
	
	if(ot->bit_len != 8 && ot->bit_len != 16) ERR("bit_len");
	ot->sign = (opt_idx("-u", ac, av) < 0);
	// 符号有無のデフォルトを、符号ありに変更
	
	ot->ch_num = opt_int("-c", ac, av, 2);
	// チャンネル数のデフォルト値を 2 (ステレオ) に変更
	
	ot->fp = stdout;
	cmd[0] = '\0';
	fn = "";
	if(opt_idx("-play", ac, av) >= 0){
		strcat(cmd, "play");
	}else if(opt_idx("-sox", ac, av) >= 0){
		strcat(cmd, "sox");
		fn = opt_str("-sox", ac, av, "-d");
	}
	if(cmd[0]){
		sprintf(cmd + strlen(cmd), " -t raw -r %d -b %d %s -c %d - %s",
			ot->smp_freq, ot->bit_len,
			ot->sign ? "-s" : "-u",
			ot->ch_num, fn);
		if((ot->fp = popen(cmd, "w")) == NULL) ERR("popen");
	}
	ot->amp = ot->bit_len == 8 ? 127 : 32767;
	ot->base = ot->sign ? 0 : ot->amp + 1;
	ot->iv_min = ot->base - (ot->amp + 1);
	ot->iv_max = ot->base + ot->amp;
}

void
out_do(struct out_rec *ot, double v)
{
	int iv;

	iv = ot->base + (int)(v *ot->amp);
	if(iv > ot->iv_max) iv = ot->iv_max;
	if(iv < ot->iv_min) iv = ot->iv_min;
	switch(ot->bit_len){
	case 8:
		fputc(iv, ot->fp);
		break;
	case 16:
		fputc(iv & 0xff, ot->fp);
		fputc((iv >> 8) & 0xff, ot->fp);
		break;
	}
}

#define WAVE_SIN	0
#define WAVE_SAW	1
#define WAVE_SQUARE	2
#define WAVE_NOISE	3

double
wave_out(int wave, double cycle)
{
	cycle -= (int)cycle;

	switch(wave){
	case WAVE_SIN:
		return sin(2 * M_PI * cycle);
	case WAVE_SAW:
		cycle *= 2;
		if(cycle > 1) cycle -= 2;
		return cycle;
	case WAVE_SQUARE:
		return cycle < 0.5 ? 1 : -1;
	case WAVE_NOISE:
		return ((double)rand() / RAND_MAX) * 2 - 1;
	}
	return 0;
}

struct vco_rec{
	int wave1, wave2;
	int tune; /* for vco2 */
	double mix;
};
// 構造体 tone_rec にあった VCO関連のメンバを、
// 構造体 vco_rec として定義
//
// wave1 は、VCO1 の波形
// wave2 は、VCO2 の波形
// tune は、VCO2 のチューニングで、VOC1 からのずれをセント (100で半音) で保持
// mix は、VCO1 と VOC2 の混合比
// 0.0 で VCO1 のみ、0.5 で半々、1.0 で VCO2 のみ

struct lfo_rec{
	int pitch1, pitch2;
	int filter;
	int wave;
	double freq, delay;
};
// 構造体 tone_rec にあった LFO 関連のメンバを、
// 構造体 lfo_rec として定義
//
// pitch1 は、VCO1 のピッチへの変調の強さ
// pitch2 は、VCO2 のピッチへの変調の強さ
// filter は、LPF のカット・オフ周波数への変調の強さ
// wave は、LFOの波形
// freq は、LFOの周波数
// delay は、鍵盤オンからLFOが効き始めるまでの時間(秒)

struct env_rec{
	double attack;	/* sec */
	double decay;	/* sec */
	double sustain;	/* 0..1 */
	double release;	/* sec */
};

struct tone_rec{
	struct vco_rec vco;
	// VCO関連のメンバを構造体に変更
	
	double lpf_freq, lpf_Q;
	struct env_rec env;
	double level;
	struct lfo_rec lfo;
	// LFO関連のメンバを構造体に変更
	
} tone_inf[] = {
	{	/* strings */
		{ WAVE_SAW, WAVE_SAW, 10, 0.5 },
		3000, 1.5,
		{ 0.15, 0.5, 0.8, 0.5 },
		0.8,
		{ 25, 0, 0, WAVE_SIN, 6, 0.3 },
	},{	/* bass */
		{ WAVE_SAW, WAVE_SQUARE, 0, 0.5 },
		1000, 1.5,
		{ 0.05, 0.2, 0.4, 0.2 },
		1.0,
		{ 0, 60, 0, WAVE_SIN, 1.5, 0.2 },
	},{	/* lead */
		{ WAVE_SQUARE, WAVE_SQUARE, 10, 0.5 },
		2000, 4,
		{ 0.01, 0.2, 0.8, 0.3 },
		0.9,
		{ 0, 1, 5, WAVE_SIN, 4, 0.3 },
	},{	/* SIN */
		{ WAVE_SIN, WAVE_SIN, 0, 0 },
		20000, 0.8,
		{ 0, 0.3, 0.2, 0.3 },
		1.0,
		{ 25, 0, 0, WAVE_SIN, 6, 0.3 },
	}
}, drum_tone_inf[] = {
	{	/* bass */
		{ WAVE_SIN, WAVE_NOISE, 0, 0.2 },
		400, 1,
		{ 0.01, 0.18, 0, 0.18 },
		10.0,
		{ 100, 0, 30, WAVE_NOISE, 0, 0.5 },
	},{	/* snare */
		{ WAVE_NOISE, WAVE_SIN, 0, 0 },
		1000, 1.7,
		{ 0, 0.3, 0.3, 0.3 },
		3.0,
		{ 0, 0, 0, WAVE_SIN, 0, 10 },
	},{	/* tom */
		{ WAVE_NOISE, WAVE_SIN, 0, 0 },
		800, 2,
		{ 0, 0.3, 2, 0.4 },
		1.0,
		{ 0, 0, 0, WAVE_SIN, 0, 0 },
	},{	/* hi-hat close */
		{ WAVE_NOISE, WAVE_SIN, 0, 0 },
		16000, 2,
		{ 0, 0.1, 0, 0.1 },
		0.8,
		{ 0, 0, 0, WAVE_SIN, 0, 0 },
	},{	/* hi-hat open */
		{ WAVE_NOISE, WAVE_SIN, 0, 0 },
		16000, 2,
		{ 0, 0, 1, 0.3 },
		0.8,
		{ 0, 0, 0, WAVE_SIN, 0, 0 },
	},{	/* cymbal */
		{ WAVE_NOISE, WAVE_SIN, 0, 0 },
		5000, 3,
		{ 0, 0.3, 0.3, 1 },
		0.8,
		{ 0, 0, 200, WAVE_SIN, 3, 0.3 },
	}
};

struct tone_rec *
tone_get(int prog, int note, double *ret_freq)
{
	int idx;
	struct tone_rec *ret;

	idx = -1;
	if(prog <= 0){ /* drum part */
		switch(note){
		case 36: /* bass drum1 */
			idx = 0;
			note = 28;
			break;
		case 37: /* side stick */
		case 40: /* electric snare */
			idx = 1;
			note = 69;
			break;
		case 41: /* low floor tom */
			idx = 2;
			note = 50;
			break;
		case 42: /* closed hi-hat */
			idx = 3;
			note = 115;
			break;
		case 46: /* open hi-hat */
			idx = 4;
			note = 115;
			break;
		case 49: /* crash cymbal 1 */
		case 57: /* crash cymbal 2 */
			idx = 5;
			note = 80;
			break;
		}
		ret = idx < 0 ? NULL : &drum_tone_inf[idx];
	}else{
		switch(prog){
		case 48: /* timpani */
		case 50: /* strings ensamble 2 */
			idx = 0;
			break;
		case 35: /* electric bass (pick) */
			idx = 1;
			break;
		case 79: /* whistle */
		case 81: /* lead 1 (square) */
		case 87: /* lead 7 (fifths) */
			idx = 2;
			break;
		case 24: /* tango accordion */
		case 67: /* tenor sax */
		default:
			idx = 3;
			break;
		}
		ret = &tone_inf[idx];
	}
	if(ret_freq) *ret_freq = note_to_freq(note);
	return ret;
}

#define MIDI_CH_N	16
struct ch_rec{
	int vol;
	int pan;
	int bend;
	int rpn;
	int bend_range;
	int prog;
} ch_inf[ MIDI_CH_N ];

#define CH_PROG(ch)	( (ch) == 9 ? 0 : ch_inf[ch].prog )

double
env_out(struct note_rec *nt)
{
	struct tone_rec *tn;
	struct env_rec *e;
	double sec, v;

	if((tn = tone_get(CH_PROG(nt->ch), nt->note, NULL)) == NULL) return 0;
	e = &tn->env;
	sec = nt->vco_stat[0].sec;
	// 構造体 note_rec のメンバ sec は、
	// vco_stat_rec 構造体へと移動したので、
	// そちらを参照するように変更
	// (VCO1 も VCO2 も同じ .sec の値を保持している)
	
	if(nt->onoff){
		sec -= nt->on_sec;
		if(sec < e->attack){
			v = sec / e->attack;
			return log10(1 + v * 9);
		}
		sec -= e->attack;
		if(sec < e->decay){
			v = sec / e->decay;
			v = log10(1 + v * 9);
			return 1 - v * (1 - e->sustain);
		}
		return e->sustain;
	}
	sec -= nt->off_sec;
	if(sec < e->release){
		v = sec / e->release;
		v = log10(1 + v * 9);
		return (1 - v) * nt->off_v;
	}
	return 0;
}

struct lfo_work_rec{
	int value; /* lfo_rec.pitch1, pitch2 or filter */
	double dsec; /* after delay (sec - on_sec - delay) */
	double out;
};
// LFO処理のワーク変数をまとめた構造体
// value は、lfo_rec の pitch1, pitch2, filter のいづれかの値を設定する
// dsec は、LFOが効き始めてからの経過時間(秒)
// out は、LFOの出力波形の値 (-1.0〜+1.0)

void
lfo_out(struct lfo_rec *lfo, struct lfo_work_rec *lfo_wk, double sec, double on_sec)
{
	lfo_wk->dsec = sec - on_sec - lfo->delay;
	if((lfo->pitch1 || lfo->pitch2 || lfo->filter) && lfo_wk->dsec > 0){
		lfo_wk->out = wave_out(lfo->wave, lfo->freq * lfo_wk->dsec);
	}
}
// LFOの波形出力処理
// LFOが効き始めてからの経過時間(秒)などを判定し、
// 不要なら何もしないで返る
// 出力波形は、構造体 lfo_work_rec の メンバoutに記録される

double
vco_out(int wave, struct vco_stat_rec *stat, double freq, double sec, struct lfo_work_rec *lfo_wk)
{
	if(lfo_wk->value && lfo_wk->dsec > 0) freq *= pow(2, lfo_wk->out * (lfo_wk->value / 100.0) / 12);
	vco_stat_update(stat, freq, sec);
	return wave_out(wave, stat->cycle);
}
// VCOの出力処理
// VCO1 のパラメータ、VCO2 のパラメータで、2回呼び出される
// LFOが効き始めてからの経過時間(秒)などを判定し、
// 必要なら、ピッチにLFOによる変調をかける
// VCOの状態を保持する構造体を更新し
// 出力波形を、返り値として返す

double
vcf_out(double lpf_freq, double lpf_Q, struct lpf_rec *lpf, struct out_rec *ot, struct lfo_work_rec *lfo_wk, double v)
{
	if(lpf->idx < 0) lpf_init(lpf, ot->smp_freq, lpf_freq, lpf_Q);
	if(lfo_wk->value && lfo_wk->dsec > 0){
		lpf_freq *= pow(2, lfo_wk->out * (lfo_wk->value / 100.0) / 12);
		lpf_update(lpf, ot->smp_freq, lpf_freq, lpf_Q);
	}
	return lpf_out(lpf, v);
}
// VCFのフィルタ処理
// LFOが効き始めてからの経過時間(秒)などを判定し、
// 必要なら、カット・オフ周波数にLFOによる変調をかける
// フィルタ処理後の出力値を、返り値として返す

int
note_out(struct out_rec *ot, double sec, struct note_rec *nt, double *vl, double *vr)
{
	// 鍵盤情報ごとの音の出力処理
	//
	// 鍵盤情報の構造体 note_rec から、
	// 出力波形の値を、引数のポインタ変数の中身へ積算する
	// 左チャンネルの出力は、引数 vl の中身へ
	// 右チャンネルの出力は、引数 vr の中身へ
	
	double v, v1, v2, freq, pan;
	int nch;
	struct tone_rec *tn;
	struct vco_rec *vco;
	struct lfo_rec *lfo;
	struct lfo_work_rec lfo_wk;

	nch = nt->ch;
	tn = tone_get(CH_PROG(nch), nt->note, &freq);
	if(tn == NULL) return 0;
	// プログラム番号やノート番号に
	// 音色が設定されてなければ、何もしないで返る
	
	if(ch_inf[nch].bend != 0) freq *= pow(2, ch_inf[nch].bend / 8192.0 * ch_inf[nch].bend_range / 12);
	// ピッチ・ベンド処理
	
	lfo = &tn->lfo;
	lfo_out(lfo, &lfo_wk, sec, nt->on_sec);
	// LFOの処理
	
	vco = &tn->vco;
	lfo_wk.value = lfo->pitch1;
	v1 = vco_out(vco->wave1, &nt->vco_stat[0], freq, sec, &lfo_wk);
	// VCO1の処理
	
	freq *= pow(2, (vco->tune / 100.0) / 12);
	lfo_wk.value = lfo->pitch2;
	v2 = vco_out(vco->wave2, &nt->vco_stat[1], freq, sec, &lfo_wk);
	// VCO2の処理
	
	v = v1 * (1 - vco->mix) + v2 * vco->mix;
	// VCO1, VCO2 の混合
	
	lfo_wk.value = lfo->filter;
	v = vcf_out(tn->lpf_freq, tn->lpf_Q, &nt->lpf, ot, &lfo_wk, v);
	// VCFの処理
	
	v *= env_out(nt) * tn->level;
	// VCAの処理
	
	v *= nt->velo / 127.0;
	v *= ch_inf[nch].vol / (double)((1<<14)-1);
	if(ot->ch_num == 1){
		*vl += v;
	}else{
	pan = ch_inf[nch].pan / (double)(1<<14);
		*vl += (1 - pan) * v;
		*vr += pan * v;
	}
	return (nt->onoff == 0 && sec - nt->off_sec >= tn->env.release);
}

void
data_out(struct out_rec *ot, double evt_sec)
{
	double sec, vl, vr;
	int i;
	struct note_rec *nt;

	while((sec = (double)ot->smp_cnt / ot->smp_freq) < evt_sec){
		vl = vr = 0;
		for(i=0; i<NOTE_BUF_N; i++){
			if(note_buf_is_free(i)) continue;
			nt = &note_buf[i];
			if(note_out(ot, sec, nt, &vl, &vr)) note_buf_free(i);
		}
		out_do(ot, vl / 16);
		if(ot->ch_num > 1) out_do(ot, vr / 16);
		ot->smp_cnt++;
	}
}

void
note_onoff(int onoff, double evt_sec, int ch, int note, int velo)
{
	int i, j;
	struct vco_stat_rec *stat;

	if(onoff){
		if((i = note_buf_search(-1, -1, -1)) < 0){
			MSG("note_buf full");
			return;
		}
		note_buf[i].note = note;
		note_buf[i].ch = ch;
		note_buf[i].onoff = 1;
		note_buf[i].on_sec = evt_sec;
		note_buf[i].velo = velo;
		for(j=0; j<2; j++){
			stat = &note_buf[i].vco_stat[j];
			stat->cycle = 0;
			stat->sec = evt_sec;
		}
		// VCOの状態の初期化
		
		note_buf[i].lpf.idx = -1;
	}else{
		if((i = note_buf_search(ch, note, 1)) < 0) return;
		note_buf[i].off_v = env_out(&note_buf[i]);
		note_buf[i].onoff = 0;
		note_buf[i].off_sec = evt_sec;
	}
}

void
msb_set(int *vp, int v)
{
	*vp &= ~(127<<7);
	*vp |= v<<7;
}

void
lsb_set(int *vp, int v)
{
	*vp &= ~127;
	*vp |= v;
}

void
bend_note_update(int ch, double sec)
{
	int i, j;
	struct note_rec *nt;
	struct vco_stat_rec *stat;

	for(i=0; i<NOTE_BUF_N; i++){
		if(note_buf_is_free(i)) continue;
		nt = &note_buf[i];
		if(nt->ch != ch) continue;
		for(j=0; j<2; j++){
			stat = &nt->vco_stat[j];
			vco_stat_update(stat, stat->freq, sec);
		}
		// VCOの状態の更新処理
		
	}
}

int
main(int ac, char **av)
{
	int div4, delta_sum;
	int i, n, v, hi, low, note, velo;
	int ch, type;
	double sec;
	struct out_rec otr;
	int tempo, tempo_delta_sum;
	double tempo_sec;

	out_init(&otr, ac, av);
	note_buf_init();
	for(i=0; i<MIDI_CH_N; i++){
		ch_inf[i].vol = 0;
		ch_inf[i].pan = 1<<(14-1);
		ch_inf[i].bend = 0;
		ch_inf[i].rpn = 0;
		ch_inf[i].bend_range = 2;
		ch_inf[i].prog =-1;
	}
	tempo = 500000;
	tempo_delta_sum = 0;
	tempo_sec = 0;

	div4 = header();

	if(!rd_str_chk(4, "MTrk")) ERR("track id");
	v = rd_int(4); /* skip */

	hi = low = 0;
	delta_sum = 0;
	while((v = rd_delta()) != EOF){
		delta_sum += v;
		sec = tempo_sec + (double)(delta_sum - tempo_delta_sum) / div4 * tempo * 0.000001;
		
		if((v = rd()) & 0x80){
			hi = (v >> 4) & 0xf;
			low  = v & 0xf;
		}else bk(v);

		data_out(&otr, sec);

		ch = low;
		switch(hi){
		case 8:
		case 9:
			note = rd();
			velo = rd();
			note_onoff(hi == 9, sec, ch, note, velo);
			break;
		case 0xb: /* control change */
			type = rd();
			v = rd();
			switch(type){
			case 7: /* channel volume msb */
				msb_set(&ch_inf[ch].vol, v);
				break;
			case 39: /* channel volume lsb */
				lsb_set(&ch_inf[ch].vol, v);
				break;
			case 10: /* pan msb */
				msb_set(&ch_inf[ch].pan, v);
				break;
			case 42: /* pan lsb */
				lsb_set(&ch_inf[ch].pan, v);
				break;
			case 100: /* rpn lsb */
				lsb_set(&ch_inf[ch].rpn, v);
				break;
			case 101: /* rpn msb */
				msb_set(&ch_inf[ch].rpn, v);
				break;
			case 6: /* data entry msb */
				switch(ch_inf[ch].rpn){
				case 0: /* pitch bend range */
					ch_inf[ch].bend_range = v;
					break;
				}
				break;
			}
			break;
		case 0xa:
			rd();
			rd();
			break;
		case 0xe: /* pitch wheel change */
			bend_note_update(ch, sec);
			v = rd();
			v |= rd() << 7;
			ch_inf[ch].bend = v - 8192;
			break;
		case 0xc: /* program number */
			v = rd();
			ch_inf[ch].prog = v;
			break;
		case 0xd:
			rd();
			break;
		case 0xf:
			type = rd();
			switch(low){
			case 0:
				while(rd() != 0xf7);
				break;
			case 1:
			case 3:
				rd();
				break;
			case 2:
				rd();
				rd();
				break;
			case 0xf: /* meta */
				n = rd();
				switch(type){
				case 0x51: /* set tempo */
					v = rd_int(n);
					tempo = v;
					tempo_delta_sum = delta_sum;
					tempo_sec = sec;
					break;
				default:
					for(i=0; i<n; i++) rd();
					break;
				}
				break;
			default:
				break;
			}
			break;
		}
	}
	if(otr.fp != stdout) pclose(otr.fp);
	return 0;
}

/* EOF */


prog16.c 解説

prog15.c からの変更箇所のみ

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <math.h>

#define MSG(s) fprintf(stderr, "%s() %s L%d : %s\n", __func__, __FILE__, __LINE__, s)
#define ERR(s) do{ fprintf(stderr, "ERR "); MSG(s); exit(1); }while(0)

int bk_buf = -1;

int
rd(void)
{
	int v;

	if((v = bk_buf) < 0) return getchar();
	bk_buf = -1;
	return v;
}

void
bk(int v)
{
	if(bk_buf >= 0) ERR("give up");
	bk_buf = v;
}

void
rd_str(int n, char *s)
{
	int i;

	for(i=0; i<n; i++) s[i] = rd();
	s[i] = '\0';
}

int
rd_str_chk(int n, char *s)
{
	char buf[256];

	rd_str(n, buf);
	return strcmp(buf, s) == 0;
}

int
rd_int(int n) /* big endian */
{
	int i, v;

	v = 0;
	for(i=0; i<n; i++) v = (v << 8) | rd();
	return v;
}

int
rd_delta(void)
{
	int v, c;

	v = 0;
	do{
		if((c = rd()) == EOF) return EOF;
		v = (v << 7) | (c & 0x7f);
	}while(c & 0x80);
	return v;
}


struct lpf_rec{
	double freq, Q;
};

struct lpf_stat_rec{
	int idx;
	double in[4], out[4];
	double a0, a1, a2, b0, b1, b2, div_a0;
};

void
lpf_update(struct lpf_rec *lpf, struct lpf_stat_rec *stat, int smp_freq)
{
	double w0, alpha;

	w0 = 2 * M_PI * lpf->freq / smp_freq;
	alpha = sin(w0) / (2 * lpf->Q);
	stat->b1 = 1 - cos(w0);
	stat->b0 = stat->b2 = stat->b1 * 0.5;
	stat->a0 = 1 + alpha;
	stat->a1 = -2 * cos(w0);
	stat->a2 = 1 - alpha;
	if(stat->a0 != 0) stat->div_a0 = 1 / stat->a0;
}

void
lpf_init(struct lpf_rec *lpf, struct lpf_stat_rec *stat, int smp_freq)
{
	int i;

	for(i=0; i<4; i++) stat->in[i] = stat->out[i] = 0;
	stat->idx = 0;

	lpf_update(lpf, stat, smp_freq);
}

double
lpf_out(struct lpf_stat_rec *stat, double in)
{
	double *out_p;
	int i_1, i_2;

	stat->in[stat->idx] = in;
	out_p = &stat->out[stat->idx];

	if(stat->a0 != 0){
		i_1 = (stat->idx + 4 - 1) & 3;
		i_2 = (i_1 + 4 - 1) & 3;
		*out_p = (stat->b0 * in
			+ stat->b1 * stat->in[i_1]
			+ stat->b2 * stat->in[i_2]
			- stat->a1 * stat->out[i_1]
			- stat->a2 * stat->out[i_2] ) * stat->div_a0;
	}else{
		*out_p = 0;
	}
	stat->idx = (stat->idx + 1) & 3;
	return *out_p;
}


#define NOTE_BUF_N	256

struct vco_stat_rec{
	double cycle, freq, sec;
};

void
vco_stat_update(struct vco_stat_rec *stat, double freq, double sec)
{
	stat->cycle += freq * (sec - stat->sec);	
	stat->freq = freq;
	stat->sec = sec;
}

struct note_rec{
	int ch;
	int note;
	int onoff;
	double on_sec;
	double off_sec;
	int velo;
	struct vco_stat_rec vco_stat[2];
	double off_v;
	struct lpf_stat_rec lpf_stat;
} note_buf[NOTE_BUF_N];

int
note_buf_is_free(int i)
{
	return note_buf[i].ch < 0;
}

void
note_buf_free(int i)
{
	note_buf[i].ch = -1;
}

void
note_buf_init(void)
{
	int i;

	for(i=0; i<NOTE_BUF_N; i++) note_buf_free(i);
}

int
note_buf_search(int ch, int note, int onoff)
{
	int i;

	for(i=0; i<NOTE_BUF_N; i++) {
		if( (ch < 0 && note_buf[i].ch < 0) ||
		    (note_buf[i].ch == ch &&
		     note_buf[i].note == note &&
		     note_buf[i].onoff == onoff) ) return i;
	}
	return -1;
}

int
header(void)
{
	int v;

	if(!rd_str_chk(4, "MThd")) ERR("header id");
	if(rd_int(4) != 6) ERR("header size");
	if(rd_int(2) != 0) ERR("header format type");
	if(rd_int(2) != 1) ERR("header track num");
	if((v = rd_int(2)) & 0x8000) ERR("header division");
	return v; /* div4 */
}

double
note_to_freq(int note)
{
	return 440 * pow(2, (note - 69) / 12.0);
}

int
opt_idx(char *key, int ac, char **av)
{
	int i;

	for(i=1; i<ac; i++) if(strcmp(av[i], key) == 0) return i;
	return -1;
}

char *
opt_str(char *key, int ac, char **av, char *def)
{
	int i;

	i = opt_idx(key, ac, av);
	if(i < 0 || i+1 >= ac) return def;
	return av[i+1];
}

int
opt_int(char *key, int ac, char **av, int def)
{
	char *s;

	if((s = opt_str(key, ac, av, NULL)) == NULL) return def;
	return strtol(s, NULL, 0);
}

struct out_rec{
	int smp_freq, smp_cnt;
	int bit_len;
	int sign;
	int ch_num;
	FILE *fp;

	int base;
	int amp;
	int iv_min;
	int iv_max;
	double smp_t, sec;
};

void
out_init(struct out_rec *ot, int ac, char **av)
{
	char cmd[1024], *fn;

	ot->smp_freq = opt_int("-r", ac, av, 44100);
	ot->smp_cnt = 0;
	ot->bit_len = opt_int("-b", ac, av, 16);
	if(ot->bit_len != 8 && ot->bit_len != 16) ERR("bit_len");
	ot->sign = (opt_idx("-u", ac, av) < 0);
	ot->ch_num = opt_int("-c", ac, av, 2);

	ot->fp = stdout;
	cmd[0] = '\0';
	fn = "";
	if(opt_idx("-play", ac, av) >= 0){
		strcat(cmd, "play");
	}else if(opt_idx("-sox", ac, av) >= 0){
		strcat(cmd, "sox");
		fn = opt_str("-sox", ac, av, "-d");
	}
	if(cmd[0]){
		sprintf(cmd + strlen(cmd), " -t raw -r %d -b %d %s -c %d - %s",
			ot->smp_freq, ot->bit_len,
			ot->sign ? "-s" : "-u",
			ot->ch_num, fn);
		if((ot->fp = popen(cmd, "w")) == NULL) ERR("popen");
	}
	ot->amp = ot->bit_len == 8 ? 127 : 32767;
	ot->base = ot->sign ? 0 : ot->amp + 1;
	ot->iv_min = ot->base - (ot->amp + 1);
	ot->iv_max = ot->base + ot->amp;

	ot->smp_t = 1.0 / ot->smp_freq;
}

void
out_do(struct out_rec *ot, double v)
{
	int iv;

	iv = ot->base + (int)(v *ot->amp);
	if(iv > ot->iv_max) iv = ot->iv_max;
	if(iv < ot->iv_min) iv = ot->iv_min;
	switch(ot->bit_len){
	case 8:
		fputc(iv, ot->fp);
		break;
	case 16:
		fputc(iv & 0xff, ot->fp);
		fputc((iv >> 8) & 0xff, ot->fp);
		break;
	}
}

#define OFF		0
#define ON		1

#define WAVE_SIN	0
#define WAVE_SAW	1
#define WAVE_SQUARE	2
#define WAVE_NOISE	3

double
wave_out(int wave, double cycle)
{
	cycle -= (int)cycle;

	switch(wave){
	case WAVE_SIN:
		return sin(2 * M_PI * cycle);
	case WAVE_SAW:
		cycle *= 2;
		if(cycle > 1) cycle -= 2;
		return cycle;
	case WAVE_SQUARE:
		return cycle < 0.5 ? 1 : -1;
	case WAVE_NOISE:
		return ((double)rand() / RAND_MAX) * 2 - 1;
	}
	return 0;
}

struct vco_rec{
	int wave1, wave2;
	int tune; /* for vco2 */
	double mix;
	int ring;
};

struct lfo_rec{
	int pitch1, pitch2;
	int filter;
	int wave;
	double freq, delay;
};

struct env_rec{
	double attack;	/* sec */
	double decay;	/* sec */
	double sustain;	/* 0..1 */
	double release;	/* sec */
};

struct tone_rec{
	struct vco_rec vco;
	struct lpf_rec lpf;
	struct env_rec env;
	double level;
	struct lfo_rec lfo;
} tone_inf[] = {
	{	/* strings */
		{ WAVE_SAW, WAVE_SAW, 12, 0.5, OFF },
		{ 3000, 1.5 },
		{ 0.15, 0.5, 0.8, 0.5 },
		1.0,
		{ OFF, 12, OFF, WAVE_SIN, 4, 0.3 },
	},{	/* bass */
		{ WAVE_SAW, WAVE_SQUARE, OFF, 0.5, OFF },
		{ 1000, 1.5} ,
		{ 0.05, 0.2, 0.4, 0.2 },
		1.0,
		{ OFF, 60, OFF, WAVE_SIN, 1.5, 0.2 },
	},{	/* lead */
		{ WAVE_SQUARE, WAVE_SQUARE, 10, 0.5, OFF },
		{ 2000, 4 },
		{ 0.01, 0.2, 0.8, 0.3 },
		1.0,
		{ OFF, 1, 5, WAVE_SIN, 4, 0.3 },
	},{	/* SIN */
		{ WAVE_SIN, WAVE_SIN, OFF, 0, OFF },
		{ 20000, 0.8 },
		{ 0, 0.3, 0.2, 0.3 },
		1.4,
		{ 25, OFF, OFF, WAVE_SIN, 6, 0.3 },
	}
}, drum_tone_inf[] = {
	{	/* bass */
		{ WAVE_SIN, WAVE_NOISE, OFF, 0.4, OFF },
		{ 400, 1 },
		{ 0.01, 0.18, 0, 0.18 },
		9.0,
		{ 100, OFF, 30, WAVE_NOISE, 0, 0.5 },
	},{	/* snare */
		{ WAVE_SQUARE, WAVE_NOISE, OFF, 0.8, ON },
		{ 1500, 1.7 },
		{ 0, 0.4, 0.3, 0.4 },
		5,
		{ OFF, OFF, OFF, },
	},{	/* tom */
		{ WAVE_SQUARE, WAVE_NOISE, OFF, 0.8, ON },
		{ 800, 2 },
		{ 0, 0.3, 2, 0.4 },
		2,
		{ OFF, OFF, OFF, },
	},{	/* hi-hat close */
		{ WAVE_SQUARE, WAVE_SQUARE, 700, 0.9, ON },
		{ 16000, 2 },
		{ 0, 0.15, 0, 0.15 },
		0.6,
		{ OFF, OFF, OFF, },
	},{	/* hi-hat open */
		{ WAVE_SQUARE, WAVE_SQUARE, 700, 0.9, ON },
		{ 16000, 2 },
		{ 0, 0, 1, 0.35 },
		0.6,
		{ OFF, OFF, OFF, },
	},{	/* cymbal */
		{ WAVE_NOISE, WAVE_SQUARE, OFF, 0.8, ON },
		{ 5000, 3 },
		{ 0, 0.3, 0.3, 1 },
		0.8,
		{ OFF, OFF, 200, WAVE_SIN, 3, 0.3 },
	}
};

struct tone_rec *
tone_get(int prog, int note, double *ret_freq)
{
	int idx;
	struct tone_rec *ret;

	idx = -1;
	if(prog <= 0){ /* drum part */
		switch(note){
		case 36: /* bass drum1 */
			idx = 0;
			note = 28;
			break;
		case 37: /* side stick */
		case 40: /* electric snare */
			idx = 1;
			note = 69;
			break;
		case 41: /* low floor tom */
			idx = 2;
			note = 50;
			break;
		case 42: /* closed hi-hat */
			idx = 3;
			note = 115 + 8;
			break;
		case 46: /* open hi-hat */
			idx = 4;
			note = 115 + 8;
			break;
		case 49: /* crash cymbal 1 */
		case 57: /* crash cymbal 2 */
			idx = 5;
			note = 80;
			break;
		}
		ret = idx < 0 ? NULL : &drum_tone_inf[idx];
	}else{
		switch(prog){
		case 48: /* timpani */
		case 50: /* strings ensamble 2 */
			idx = 0;
			break;
		case 35: /* electric bass (pick) */
			idx = 1;
			break;
		case 79: /* whistle */
		case 81: /* lead 1 (square) */
		case 87: /* lead 7 (fifths) */
			idx = 2;
			break;
		case 24: /* tango accordion */
		case 67: /* tenor sax */
		default:
			idx = 3;
			break;
		}
		ret = &tone_inf[idx];
	}
	if(ret_freq) *ret_freq = note_to_freq(note);
	return ret;
}

#define MIDI_CH_N	16
struct ch_rec{
	int vol;
	int pan;
	int bend;
	int rpn;
	int bend_range;
	int prog;
} ch_inf[ MIDI_CH_N ];

#define CH_PROG(ch)	( (ch) == 9 ? 0 : ch_inf[ch].prog )

double
env_out(struct note_rec *nt)
{
	struct tone_rec *tn;
	struct env_rec *e;
	double sec, v;

	if((tn = tone_get(CH_PROG(nt->ch), nt->note, NULL)) == NULL) return 0;
	e = &tn->env;
	sec = nt->vco_stat[0].sec;
	if(nt->onoff){
		sec -= nt->on_sec;
		if(sec < e->attack){
			v = sec / e->attack;
			return log10(1 + v * 9);
		}
		sec -= e->attack;
		if(sec < e->decay){
			v = sec / e->decay;
			v = log10(1 + v * 9);
			return 1 - v * (1 - e->sustain);
		}
		return e->sustain;
	}
	sec -= nt->off_sec;
	if(sec < e->release){
		v = sec / e->release;
		v = log10(1 + v * 9);
		return (1 - v) * nt->off_v;
	}
	return 0;
}

struct lfo_work_rec{
	int value; /* lfo_rec.pitch1, pitch2 or filter */
	double dsec; /* after delay (sec - on_sec - delay) */
	double out;
};

void
lfo_out(struct lfo_rec *lfo, struct lfo_work_rec *lfo_wk, double sec, double on_sec)
{
	lfo_wk->dsec = sec - on_sec - lfo->delay;
	if((lfo->pitch1 || lfo->pitch2 || lfo->filter) && lfo_wk->dsec > 0){
		lfo_wk->out = wave_out(lfo->wave, lfo->freq * lfo_wk->dsec);
	}
}

double
vco_out(int wave, struct vco_stat_rec *stat, double freq, double sec, struct lfo_work_rec *lfo_wk)
{
	if(lfo_wk->value && lfo_wk->dsec > 0) freq *= pow(2, lfo_wk->out * (lfo_wk->value / 100.0) / 12);
	vco_stat_update(stat, freq, sec);
	return wave_out(wave, stat->cycle);
}

double
vcf_out(struct lpf_rec *lpf, struct lpf_stat_rec *lpf_stat, struct out_rec *ot, struct lfo_work_rec *lfo_wk, double v)
{
	struct lpf_rec lpf_tmp;

	if(lpf_stat->idx < 0) lpf_init(lpf, lpf_stat, ot->smp_freq);
	if(lfo_wk->value && lfo_wk->dsec > 0){
		lpf_tmp = *lpf;
		lpf_tmp.freq *= pow(2, lfo_wk->out * (lfo_wk->value / 100.0) / 12);
		lpf_update(&lpf_tmp, lpf_stat, ot->smp_freq);
	}
	return lpf_out(lpf_stat, v);
}

int
note_out(struct out_rec *ot, struct note_rec *nt, double *vl, double *vr)
{
	double v, v1, v2, freq, pan;
	int nch;
	struct tone_rec *tn;
	struct vco_rec *vco;
	struct lfo_rec *lfo;
	struct lfo_work_rec lfo_wk;

	nch = nt->ch;
	tn = tone_get(CH_PROG(nch), nt->note, &freq);
	if(tn == NULL) return 0;

	if(ch_inf[nch].bend != 0) freq *= pow(2, ch_inf[nch].bend / 8192.0 * ch_inf[nch].bend_range / 12);

	lfo = &tn->lfo;
	lfo_out(lfo, &lfo_wk, ot->sec, nt->on_sec);

	vco = &tn->vco;
	lfo_wk.value = lfo->pitch1;
	v1 = vco_out(vco->wave1, &nt->vco_stat[0], freq, ot->sec, &lfo_wk);
	freq *= pow(2, (vco->tune / 100.0) / 12);
	lfo_wk.value = lfo->pitch2;
	v2 = vco_out(vco->wave2, &nt->vco_stat[1], freq, ot->sec, &lfo_wk);
	if(vco->ring){
		v = v1 * v2;
		v1 = (v1 + v2) / 2;
		v2 = v;
	}
	v = v1 * (1 - vco->mix) + v2 * vco->mix;

	lfo_wk.value = lfo->filter;
	v = vcf_out(&tn->lpf, &nt->lpf_stat, ot, &lfo_wk, v);

	v *= env_out(nt) * tn->level;
	v *= nt->velo / 127.0;
	v *= ch_inf[nch].vol / (double)((1<<14)-1);
	if(ot->ch_num == 1){
		*vl += v;
	}else{
	pan = ch_inf[nch].pan / (double)(1<<14);
		*vl += (1 - pan) * v;
		*vr += pan * v;
	}
	return (nt->onoff == 0 && ot->sec - nt->off_sec >= tn->env.release);
}

void
data_out(struct out_rec *ot, double evt_sec)
{
	double vl, vr;
	int i;
	struct note_rec *nt;

	while((ot->sec = ot->smp_t * ot->smp_cnt) < evt_sec){
		vl = vr = 0;
		for(i=0; i<NOTE_BUF_N; i++){
			if(note_buf_is_free(i)) continue;
			nt = &note_buf[i];
			if(note_out(ot, nt, &vl, &vr)) note_buf_free(i);
		}
		out_do(ot, vl / 16);
		if(ot->ch_num > 1) out_do(ot, vr / 16);
		ot->smp_cnt++;
	}
}

void
note_onoff(int onoff, double evt_sec, int ch, int note, int velo)
{
	int i, j;
	struct vco_stat_rec *stat;

	if(onoff){
		if((i = note_buf_search(-1, -1, -1)) < 0){
			MSG("note_buf full");
			return;
		}
		note_buf[i].note = note;
		note_buf[i].ch = ch;
		note_buf[i].onoff = 1;
		note_buf[i].on_sec = evt_sec;
		note_buf[i].velo = velo;
		for(j=0; j<2; j++){
			stat = &note_buf[i].vco_stat[j];
			stat->cycle = 0;
			stat->sec = evt_sec;
		}
		note_buf[i].lpf_stat.idx = -1;
	}else{
		if((i = note_buf_search(ch, note, 1)) < 0) return;
		note_buf[i].off_v = env_out(&note_buf[i]);
		note_buf[i].onoff = 0;
		note_buf[i].off_sec = evt_sec;
	}
}

void
msb_set(int *vp, int v)
{
	*vp &= ~(127<<7);
	*vp |= v<<7;
}

void
lsb_set(int *vp, int v)
{
	*vp &= ~127;
	*vp |= v;
}

void
bend_note_update(int ch, double sec)
{
	int i, j;
	struct note_rec *nt;
	struct vco_stat_rec *stat;

	for(i=0; i<NOTE_BUF_N; i++){
		if(note_buf_is_free(i)) continue;
		nt = &note_buf[i];
		if(nt->ch != ch) continue;
		for(j=0; j<2; j++){
			stat = &nt->vco_stat[j];
			vco_stat_update(stat, stat->freq, sec);
		}
	}
}

int
main(int ac, char **av)
{
	int div4, delta_sum;
	int i, n, v, hi, low, note, velo;
	int ch, type;
	double sec;
	struct out_rec otr;
	int tempo, tempo_delta_sum;
	double tempo_sec;

	out_init(&otr, ac, av);
	note_buf_init();
	for(i=0; i<MIDI_CH_N; i++){
		ch_inf[i].vol = 0;
		ch_inf[i].pan = 1<<(14-1);
		ch_inf[i].bend = 0;
		ch_inf[i].rpn = 0;
		ch_inf[i].bend_range = 2;
		ch_inf[i].prog =-1;
	}
	tempo = 500000;
	tempo_delta_sum = 0;
	tempo_sec = 0;

	div4 = header();

	if(!rd_str_chk(4, "MTrk")) ERR("track id");
	v = rd_int(4); /* skip */

	hi = low = 0;
	delta_sum = 0;
	while((v = rd_delta()) != EOF){
		delta_sum += v;
		sec = tempo_sec + (double)(delta_sum - tempo_delta_sum) / div4 * tempo * 0.000001;
		
		if((v = rd()) & 0x80){
			hi = (v >> 4) & 0xf;
			low  = v & 0xf;
		}else bk(v);

		data_out(&otr, sec);

		ch = low;
		switch(hi){
		case 8:
		case 9:
			note = rd();
			velo = rd();
			note_onoff(hi == 9, sec, ch, note, velo);
			break;
		case 0xb: /* control change */
			type = rd();
			v = rd();
			switch(type){
			case 7: /* channel volume msb */
				msb_set(&ch_inf[ch].vol, v);
				break;
			case 39: /* channel volume lsb */
				lsb_set(&ch_inf[ch].vol, v);
				break;
			case 10: /* pan msb */
				msb_set(&ch_inf[ch].pan, v);
				break;
			case 42: /* pan lsb */
				lsb_set(&ch_inf[ch].pan, v);
				break;
			case 100: /* rpn lsb */
				lsb_set(&ch_inf[ch].rpn, v);
				break;
			case 101: /* rpn msb */
				msb_set(&ch_inf[ch].rpn, v);
				break;
			case 6: /* data entry msb */
				switch(ch_inf[ch].rpn){
				case 0: /* pitch bend range */
					ch_inf[ch].bend_range = v;
					break;
				}
				break;
			}
			break;
		case 0xa:
			rd();
			rd();
			break;
		case 0xe: /* pitch wheel change */
			bend_note_update(ch, sec);
			v = rd();
			v |= rd() << 7;
			ch_inf[ch].bend = v - 8192;
			break;
		case 0xc: /* program number */
			v = rd();
			ch_inf[ch].prog = v;
			break;
		case 0xd:
			rd();
			break;
		case 0xf:
			type = rd();
			switch(low){
			case 0:
				while(rd() != 0xf7);
				break;
			case 1:
			case 3:
				rd();
				break;
			case 2:
				rd();
				rd();
				break;
			case 0xf: /* meta */
				n = rd();
				switch(type){
				case 0x51: /* set tempo */
					v = rd_int(n);
					tempo = v;
					tempo_delta_sum = delta_sum;
					tempo_sec = sec;
					break;
				default:
					for(i=0; i<n; i++) rd();
					break;
				}
				break;
			default:
				break;
			}
			break;
		}
	}
	if(otr.fp != stdout) pclose(otr.fp);
	return 0;
}

/* EOF */


#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <math.h>

#define MSG(s) fprintf(stderr, "%s() %s L%d : %s\n", __func__, __FILE__, __LINE__, s)
#define ERR(s) do{ fprintf(stderr, "ERR "); MSG(s); exit(1); }while(0)

int bk_buf = -1;

int
rd(void)
{
	int v;

	if((v = bk_buf) < 0) return getchar();
	bk_buf = -1;
	return v;
}

void
bk(int v)
{
	if(bk_buf >= 0) ERR("give up");
	bk_buf = v;
}

void
rd_str(int n, char *s)
{
	int i;

	for(i=0; i<n; i++) s[i] = rd();
	s[i] = '\0';
}

int
rd_str_chk(int n, char *s)
{
	char buf[256];

	rd_str(n, buf);
	return strcmp(buf, s) == 0;
}

int
rd_int(int n) /* big endian */
{
	int i, v;

	v = 0;
	for(i=0; i<n; i++) v = (v << 8) | rd();
	return v;
}

int
rd_delta(void)
{
	int v, c;

	v = 0;
	do{
		if((c = rd()) == EOF) return EOF;
		v = (v << 7) | (c & 0x7f);
	}while(c & 0x80);
	return v;
}


struct lpf_rec{
	double freq, Q;
};
// 構造体 tone_rec のメンバ lpf_freq, lpf_Q をまとめて、
// 新たに構造体 lpf_rec とした

struct lpf_stat_rec{
	int idx;
	double in[4], out[4];
	double a0, a1, a2, b0, b1, b2, div_a0;
};
// 構造体 lpf_rec は、名前を lpf_stat_rec に変更

void
lpf_update(struct lpf_rec *lpf, struct lpf_stat_rec *stat, int smp_freq)
{
	// LPF関連の構造体の変更にともない
	// 引数を変更
	
	double w0, alpha;

	w0 = 2 * M_PI * lpf->freq / smp_freq;
	alpha = sin(w0) / (2 * lpf->Q);
	stat->b1 = 1 - cos(w0);
	stat->b0 = stat->b2 = stat->b1 * 0.5;
	stat->a0 = 1 + alpha;
	stat->a1 = -2 * cos(w0);
	stat->a2 = 1 - alpha;
	if(stat->a0 != 0) stat->div_a0 = 1 / stat->a0;
}

void
lpf_init(struct lpf_rec *lpf, struct lpf_stat_rec *stat, int smp_freq)
{
	// LPF関連の構造体の変更にともない
	// 引数を変更
	
	int i;

	for(i=0; i<4; i++) stat->in[i] = stat->out[i] = 0;
	stat->idx = 0;

	lpf_update(lpf, stat, smp_freq);
}

double
lpf_out(struct lpf_stat_rec *stat, double in)
{
	// LPF関連の構造体の変更にともない
	// 引数を変更
	
	double *out_p;
	int i_1, i_2;

	stat->in[stat->idx] = in;
	out_p = &stat->out[stat->idx];

	if(stat->a0 != 0){
		i_1 = (stat->idx + 4 - 1) & 3;
		i_2 = (i_1 + 4 - 1) & 3;
		*out_p = (stat->b0 * in
			+ stat->b1 * stat->in[i_1]
			+ stat->b2 * stat->in[i_2]
			- stat->a1 * stat->out[i_1]
			- stat->a2 * stat->out[i_2] ) * stat->div_a0;
	}else{
		*out_p = 0;
	}
	stat->idx = (stat->idx + 1) & 3;
	return *out_p;
}


#define NOTE_BUF_N	256

struct vco_stat_rec{
	double cycle, freq, sec;
};

void
vco_stat_update(struct vco_stat_rec *stat, double freq, double sec)
{
	stat->cycle += freq * (sec - stat->sec);	
	stat->freq = freq;
	stat->sec = sec;
}

struct note_rec{
	int ch;
	int note;
	int onoff;
	double on_sec;
	double off_sec;
	int velo;
	struct vco_stat_rec vco_stat[2];
	double off_v;
	struct lpf_stat_rec lpf_stat;
	// LPF関連の構造体の変更にともない
	// 変更
	
} note_buf[NOTE_BUF_N];

int
note_buf_is_free(int i)
{
	return note_buf[i].ch < 0;
}

void
note_buf_free(int i)
{
	note_buf[i].ch = -1;
}

void
note_buf_init(void)
{
	int i;

	for(i=0; i<NOTE_BUF_N; i++) note_buf_free(i);
}

int
note_buf_search(int ch, int note, int onoff)
{
	int i;

	for(i=0; i<NOTE_BUF_N; i++) {
		if( (ch < 0 && note_buf[i].ch < 0) ||
		    (note_buf[i].ch == ch &&
		     note_buf[i].note == note &&
		     note_buf[i].onoff == onoff) ) return i;
	}
	return -1;
}

int
header(void)
{
	int v;

	if(!rd_str_chk(4, "MThd")) ERR("header id");
	if(rd_int(4) != 6) ERR("header size");
	if(rd_int(2) != 0) ERR("header format type");
	if(rd_int(2) != 1) ERR("header track num");
	if((v = rd_int(2)) & 0x8000) ERR("header division");
	return v; /* div4 */
}

double
note_to_freq(int note)
{
	return 440 * pow(2, (note - 69) / 12.0);
}

int
opt_idx(char *key, int ac, char **av)
{
	int i;

	for(i=1; i<ac; i++) if(strcmp(av[i], key) == 0) return i;
	return -1;
}

char *
opt_str(char *key, int ac, char **av, char *def)
{
	int i;

	i = opt_idx(key, ac, av);
	if(i < 0 || i+1 >= ac) return def;
	return av[i+1];
}

int
opt_int(char *key, int ac, char **av, int def)
{
	char *s;

	if((s = opt_str(key, ac, av, NULL)) == NULL) return def;
	return strtol(s, NULL, 0);
}

struct out_rec{
	int smp_freq, smp_cnt;
	int bit_len;
	int sign;
	int ch_num;
	FILE *fp;

	int base;
	int amp;
	int iv_min;
	int iv_max;
	double smp_t, sec;
	// ワーク用として
	// サンプリング周期 (1 / サンプリング周波数)と、
	// 時刻(秒)を追加
	
};

void
out_init(struct out_rec *ot, int ac, char **av)
{
	char cmd[1024], *fn;

	ot->smp_freq = opt_int("-r", ac, av, 44100);
	ot->smp_cnt = 0;
	ot->bit_len = opt_int("-b", ac, av, 16);
	if(ot->bit_len != 8 && ot->bit_len != 16) ERR("bit_len");
	ot->sign = (opt_idx("-u", ac, av) < 0);
	ot->ch_num = opt_int("-c", ac, av, 2);

	ot->fp = stdout;
	cmd[0] = '\0';
	fn = "";
	if(opt_idx("-play", ac, av) >= 0){
		strcat(cmd, "play");
	}else if(opt_idx("-sox", ac, av) >= 0){
		strcat(cmd, "sox");
		fn = opt_str("-sox", ac, av, "-d");
	}
	if(cmd[0]){
		sprintf(cmd + strlen(cmd), " -t raw -r %d -b %d %s -c %d - %s",
			ot->smp_freq, ot->bit_len,
			ot->sign ? "-s" : "-u",
			ot->ch_num, fn);
		if((ot->fp = popen(cmd, "w")) == NULL) ERR("popen");
	}
	ot->amp = ot->bit_len == 8 ? 127 : 32767;
	ot->base = ot->sign ? 0 : ot->amp + 1;
	ot->iv_min = ot->base - (ot->amp + 1);
	ot->iv_max = ot->base + ot->amp;

	ot->smp_t = 1.0 / ot->smp_freq;
	// サンプリング周期の設定追加
	
}

void
out_do(struct out_rec *ot, double v)
{
	int iv;

	iv = ot->base + (int)(v *ot->amp);
	if(iv > ot->iv_max) iv = ot->iv_max;
	if(iv < ot->iv_min) iv = ot->iv_min;
	switch(ot->bit_len){
	case 8:
		fputc(iv, ot->fp);
		break;
	case 16:
		fputc(iv & 0xff, ot->fp);
		fputc((iv >> 8) & 0xff, ot->fp);
		break;
	}
}

#define OFF		0
#define ON		1
// 構造体 tone_rec の初期値指定用に追加

#define WAVE_SIN	0
#define WAVE_SAW	1
#define WAVE_SQUARE	2
#define WAVE_NOISE	3

double
wave_out(int wave, double cycle)
{
	cycle -= (int)cycle;

	switch(wave){
	case WAVE_SIN:
		return sin(2 * M_PI * cycle);
	case WAVE_SAW:
		cycle *= 2;
		if(cycle > 1) cycle -= 2;
		return cycle;
	case WAVE_SQUARE:
		return cycle < 0.5 ? 1 : -1;
	case WAVE_NOISE:
		return ((double)rand() / RAND_MAX) * 2 - 1;
	}
	return 0;
}

struct vco_rec{
	int wave1, wave2;
	int tune; /* for vco2 */
	double mix;
	int ring;
	// リング・モジュレーション用のON/OFFフラグを追加
	
};

struct lfo_rec{
	int pitch1, pitch2;
	int filter;
	int wave;
	double freq, delay;
};

struct env_rec{
	double attack;	/* sec */
	double decay;	/* sec */
	double sustain;	/* 0..1 */
	double release;	/* sec */
};

struct tone_rec{
	struct vco_rec vco;
	struct lpf_rec lpf;
	// LPF関連の構造体の変更にともない
	// 変更
	
	struct env_rec env;
	double level;
	struct lfo_rec lfo;
} tone_inf[] = {
	{	/* strings */
		{ WAVE_SAW, WAVE_SAW, 12, 0.5, OFF },
		{ 3000, 1.5 },
		{ 0.15, 0.5, 0.8, 0.5 },
		1.0,
		{ OFF, 12, OFF, WAVE_SIN, 4, 0.3 },
	},{	/* bass */
		{ WAVE_SAW, WAVE_SQUARE, OFF, 0.5, OFF },
		{ 1000, 1.5} ,
		{ 0.05, 0.2, 0.4, 0.2 },
		1.0,
		{ OFF, 60, OFF, WAVE_SIN, 1.5, 0.2 },
	},{	/* lead */
		{ WAVE_SQUARE, WAVE_SQUARE, 10, 0.5, OFF },
		{ 2000, 4 },
		{ 0.01, 0.2, 0.8, 0.3 },
		1.0,
		{ OFF, 1, 5, WAVE_SIN, 4, 0.3 },
	},{	/* SIN */
		{ WAVE_SIN, WAVE_SIN, OFF, 0, OFF },
		{ 20000, 0.8 },
		{ 0, 0.3, 0.2, 0.3 },
		1.4,
		{ 25, OFF, OFF, WAVE_SIN, 6, 0.3 },
	}
}, drum_tone_inf[] = {
	{	/* bass */
		{ WAVE_SIN, WAVE_NOISE, OFF, 0.4, OFF },
		{ 400, 1 },
		{ 0.01, 0.18, 0, 0.18 },
		9.0,
		{ 100, OFF, 30, WAVE_NOISE, 0, 0.5 },
	},{	/* snare */
		{ WAVE_SQUARE, WAVE_NOISE, OFF, 0.8, ON },
		{ 1500, 1.7 },
		{ 0, 0.4, 0.3, 0.4 },
		5,
		{ OFF, OFF, OFF, },
	},{	/* tom */
		{ WAVE_SQUARE, WAVE_NOISE, OFF, 0.8, ON },
		{ 800, 2 },
		{ 0, 0.3, 2, 0.4 },
		2,
		{ OFF, OFF, OFF, },
	},{	/* hi-hat close */
		{ WAVE_SQUARE, WAVE_SQUARE, 700, 0.9, ON },
		{ 16000, 2 },
		{ 0, 0.15, 0, 0.15 },
		0.6,
		{ OFF, OFF, OFF, },
	},{	/* hi-hat open */
		{ WAVE_SQUARE, WAVE_SQUARE, 700, 0.9, ON },
		{ 16000, 2 },
		{ 0, 0, 1, 0.35 },
		0.6,
		{ OFF, OFF, OFF, },
	},{	/* cymbal */
		{ WAVE_NOISE, WAVE_SQUARE, OFF, 0.8, ON },
		{ 5000, 3 },
		{ 0, 0.3, 0.3, 1 },
		0.8,
		{ OFF, OFF, 200, WAVE_SIN, 3, 0.3 },
	}
};

struct tone_rec *
tone_get(int prog, int note, double *ret_freq)
{
	int idx;
	struct tone_rec *ret;

	idx = -1;
	if(prog <= 0){ /* drum part */
		switch(note){
		case 36: /* bass drum1 */
			idx = 0;
			note = 28;
			break;
		case 37: /* side stick */
		case 40: /* electric snare */
			idx = 1;
			note = 69;
			break;
		case 41: /* low floor tom */
			idx = 2;
			note = 50;
			break;
		case 42: /* closed hi-hat */
			idx = 3;
			note = 115 + 8;
			break;
		case 46: /* open hi-hat */
			idx = 4;
			note = 115 + 8;
			break;
		case 49: /* crash cymbal 1 */
		case 57: /* crash cymbal 2 */
			idx = 5;
			note = 80;
			break;
		}
		ret = idx < 0 ? NULL : &drum_tone_inf[idx];
	}else{
		switch(prog){
		case 48: /* timpani */
		case 50: /* strings ensamble 2 */
			idx = 0;
			break;
		case 35: /* electric bass (pick) */
			idx = 1;
			break;
		case 79: /* whistle */
		case 81: /* lead 1 (square) */
		case 87: /* lead 7 (fifths) */
			idx = 2;
			break;
		case 24: /* tango accordion */
		case 67: /* tenor sax */
		default:
			idx = 3;
			break;
		}
		ret = &tone_inf[idx];
	}
	if(ret_freq) *ret_freq = note_to_freq(note);
	return ret;
}

#define MIDI_CH_N	16
struct ch_rec{
	int vol;
	int pan;
	int bend;
	int rpn;
	int bend_range;
	int prog;
} ch_inf[ MIDI_CH_N ];

#define CH_PROG(ch)	( (ch) == 9 ? 0 : ch_inf[ch].prog )

double
env_out(struct note_rec *nt)
{
	struct tone_rec *tn;
	struct env_rec *e;
	double sec, v;

	if((tn = tone_get(CH_PROG(nt->ch), nt->note, NULL)) == NULL) return 0;
	e = &tn->env;
	sec = nt->vco_stat[0].sec;
	if(nt->onoff){
		sec -= nt->on_sec;
		if(sec < e->attack){
			v = sec / e->attack;
			return log10(1 + v * 9);
		}
		sec -= e->attack;
		if(sec < e->decay){
			v = sec / e->decay;
			v = log10(1 + v * 9);
			return 1 - v * (1 - e->sustain);
		}
		return e->sustain;
	}
	sec -= nt->off_sec;
	if(sec < e->release){
		v = sec / e->release;
		v = log10(1 + v * 9);
		return (1 - v) * nt->off_v;
	}
	return 0;
}

struct lfo_work_rec{
	int value; /* lfo_rec.pitch1, pitch2 or filter */
	double dsec; /* after delay (sec - on_sec - delay) */
	double out;
};

void
lfo_out(struct lfo_rec *lfo, struct lfo_work_rec *lfo_wk, double sec, double on_sec)
{
	lfo_wk->dsec = sec - on_sec - lfo->delay;
	if((lfo->pitch1 || lfo->pitch2 || lfo->filter) && lfo_wk->dsec > 0){
		lfo_wk->out = wave_out(lfo->wave, lfo->freq * lfo_wk->dsec);
	}
}

double
vco_out(int wave, struct vco_stat_rec *stat, double freq, double sec, struct lfo_work_rec *lfo_wk)
{
	if(lfo_wk->value && lfo_wk->dsec > 0) freq *= pow(2, lfo_wk->out * (lfo_wk->value / 100.0) / 12);
	vco_stat_update(stat, freq, sec);
	return wave_out(wave, stat->cycle);
}

double
vcf_out(struct lpf_rec *lpf, struct lpf_stat_rec *lpf_stat, struct out_rec *ot, struct lfo_work_rec *lfo_wk, double v)
{
	// LPF関連の構造体の変更にともない
	// 引数変更
	
	struct lpf_rec lpf_tmp;

	if(lpf_stat->idx < 0) lpf_init(lpf, lpf_stat, ot->smp_freq);
	if(lfo_wk->value && lfo_wk->dsec > 0){
		lpf_tmp = *lpf;
		lpf_tmp.freq *= pow(2, lfo_wk->out * (lfo_wk->value / 100.0) / 12);
		lpf_update(&lpf_tmp, lpf_stat, ot->smp_freq);
	}
	return lpf_out(lpf_stat, v);
}

int
note_out(struct out_rec *ot, struct note_rec *nt, double *vl, double *vr)
{
	// 構造体 out_rec へのワーク用の sec 追加に伴い
	// 引数変更
	
	double v, v1, v2, freq, pan;
	int nch;
	struct tone_rec *tn;
	struct vco_rec *vco;
	struct lfo_rec *lfo;
	struct lfo_work_rec lfo_wk;

	nch = nt->ch;
	tn = tone_get(CH_PROG(nch), nt->note, &freq);
	if(tn == NULL) return 0;

	if(ch_inf[nch].bend != 0) freq *= pow(2, ch_inf[nch].bend / 8192.0 * ch_inf[nch].bend_range / 12);

	lfo = &tn->lfo;
	lfo_out(lfo, &lfo_wk, ot->sec, nt->on_sec);

	vco = &tn->vco;
	lfo_wk.value = lfo->pitch1;
	v1 = vco_out(vco->wave1, &nt->vco_stat[0], freq, ot->sec, &lfo_wk);
	freq *= pow(2, (vco->tune / 100.0) / 12);
	lfo_wk.value = lfo->pitch2;
	v2 = vco_out(vco->wave2, &nt->vco_stat[1], freq, ot->sec, &lfo_wk);
	if(vco->ring){
		v = v1 * v2;
		v1 = (v1 + v2) / 2;
		v2 = v;
	}
	// リング・モジュレーションの処理を追加
	
	v = v1 * (1 - vco->mix) + v2 * vco->mix;

	lfo_wk.value = lfo->filter;
	v = vcf_out(&tn->lpf, &nt->lpf_stat, ot, &lfo_wk, v);

	v *= env_out(nt) * tn->level;
	v *= nt->velo / 127.0;
	v *= ch_inf[nch].vol / (double)((1<<14)-1);
	if(ot->ch_num == 1){
		*vl += v;
	}else{
	pan = ch_inf[nch].pan / (double)(1<<14);
		*vl += (1 - pan) * v;
		*vr += pan * v;
	}
	return (nt->onoff == 0 && ot->sec - nt->off_sec >= tn->env.release);
}

void
data_out(struct out_rec *ot, double evt_sec)
{
	// 構造体 out_rec へのワーク用の sec 追加に伴い
	// ローカル変数 sec は削除
	
	double vl, vr;
	int i;
	struct note_rec *nt;

	while((ot->sec = ot->smp_t * ot->smp_cnt) < evt_sec){
		vl = vr = 0;
		for(i=0; i<NOTE_BUF_N; i++){
			if(note_buf_is_free(i)) continue;
			nt = &note_buf[i];
			if(note_out(ot, nt, &vl, &vr)) note_buf_free(i);
		}
		out_do(ot, vl / 16);
		if(ot->ch_num > 1) out_do(ot, vr / 16);
		ot->smp_cnt++;
	}
}

void
note_onoff(int onoff, double evt_sec, int ch, int note, int velo)
{
	int i, j;
	struct vco_stat_rec *stat;

	if(onoff){
		if((i = note_buf_search(-1, -1, -1)) < 0){
			MSG("note_buf full");
			return;
		}
		note_buf[i].note = note;
		note_buf[i].ch = ch;
		note_buf[i].onoff = 1;
		note_buf[i].on_sec = evt_sec;
		note_buf[i].velo = velo;
		for(j=0; j<2; j++){
			stat = &note_buf[i].vco_stat[j];
			stat->cycle = 0;
			stat->sec = evt_sec;
		}
		note_buf[i].lpf_stat.idx = -1;
		// LPF関連の構造体の変更にともない
		// 変更
		
	}else{
		if((i = note_buf_search(ch, note, 1)) < 0) return;
		note_buf[i].off_v = env_out(&note_buf[i]);
		note_buf[i].onoff = 0;
		note_buf[i].off_sec = evt_sec;
	}
}

void
msb_set(int *vp, int v)
{
	*vp &= ~(127<<7);
	*vp |= v<<7;
}

void
lsb_set(int *vp, int v)
{
	*vp &= ~127;
	*vp |= v;
}

void
bend_note_update(int ch, double sec)
{
	int i, j;
	struct note_rec *nt;
	struct vco_stat_rec *stat;

	for(i=0; i<NOTE_BUF_N; i++){
		if(note_buf_is_free(i)) continue;
		nt = &note_buf[i];
		if(nt->ch != ch) continue;
		for(j=0; j<2; j++){
			stat = &nt->vco_stat[j];
			vco_stat_update(stat, stat->freq, sec);
		}
	}
}

int
main(int ac, char **av)
{
	int div4, delta_sum;
	int i, n, v, hi, low, note, velo;
	int ch, type;
	double sec;
	struct out_rec otr;
	int tempo, tempo_delta_sum;
	double tempo_sec;

	out_init(&otr, ac, av);
	note_buf_init();
	for(i=0; i<MIDI_CH_N; i++){
		ch_inf[i].vol = 0;
		ch_inf[i].pan = 1<<(14-1);
		ch_inf[i].bend = 0;
		ch_inf[i].rpn = 0;
		ch_inf[i].bend_range = 2;
		ch_inf[i].prog =-1;
	}
	tempo = 500000;
	tempo_delta_sum = 0;
	tempo_sec = 0;

	div4 = header();

	if(!rd_str_chk(4, "MTrk")) ERR("track id");
	v = rd_int(4); /* skip */

	hi = low = 0;
	delta_sum = 0;
	while((v = rd_delta()) != EOF){
		delta_sum += v;
		sec = tempo_sec + (double)(delta_sum - tempo_delta_sum) / div4 * tempo * 0.000001;
		
		if((v = rd()) & 0x80){
			hi = (v >> 4) & 0xf;
			low  = v & 0xf;
		}else bk(v);

		data_out(&otr, sec);

		ch = low;
		switch(hi){
		case 8:
		case 9:
			note = rd();
			velo = rd();
			note_onoff(hi == 9, sec, ch, note, velo);
			break;
		case 0xb: /* control change */
			type = rd();
			v = rd();
			switch(type){
			case 7: /* channel volume msb */
				msb_set(&ch_inf[ch].vol, v);
				break;
			case 39: /* channel volume lsb */
				lsb_set(&ch_inf[ch].vol, v);
				break;
			case 10: /* pan msb */
				msb_set(&ch_inf[ch].pan, v);
				break;
			case 42: /* pan lsb */
				lsb_set(&ch_inf[ch].pan, v);
				break;
			case 100: /* rpn lsb */
				lsb_set(&ch_inf[ch].rpn, v);
				break;
			case 101: /* rpn msb */
				msb_set(&ch_inf[ch].rpn, v);
				break;
			case 6: /* data entry msb */
				switch(ch_inf[ch].rpn){
				case 0: /* pitch bend range */
					ch_inf[ch].bend_range = v;
					break;
				}
				break;
			}
			break;
		case 0xa:
			rd();
			rd();
			break;
		case 0xe: /* pitch wheel change */
			bend_note_update(ch, sec);
			v = rd();
			v |= rd() << 7;
			ch_inf[ch].bend = v - 8192;
			break;
		case 0xc: /* program number */
			v = rd();
			ch_inf[ch].prog = v;
			break;
		case 0xd:
			rd();
			break;
		case 0xf:
			type = rd();
			switch(low){
			case 0:
				while(rd() != 0xf7);
				break;
			case 1:
			case 3:
				rd();
				break;
			case 2:
				rd();
				rd();
				break;
			case 0xf: /* meta */
				n = rd();
				switch(type){
				case 0x51: /* set tempo */
					v = rd_int(n);
					tempo = v;
					tempo_delta_sum = delta_sum;
					tempo_sec = sec;
					break;
				default:
					for(i=0; i<n; i++) rd();
					break;
				}
				break;
			default:
				break;
			}
			break;
		}
	}
	if(otr.fp != stdout) pclose(otr.fp);
	return 0;
}

/* EOF */


prog18.c 解説

prog17.c からの変更箇所のみ

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <math.h>

#define MSG(s) fprintf(stderr, "%s() %s L%d : %s\n", __func__, __FILE__, __LINE__, s)
#define ERR(s) do{ fprintf(stderr, "ERR "); MSG(s); exit(1); }while(0)

int bk_buf = -1;

int
rd(void)
{
	int v;

	if((v = bk_buf) < 0) return getchar();
	bk_buf = -1;
	return v;
}

void
bk(int v)
{
	if(bk_buf >= 0) ERR("give up");
	bk_buf = v;
}

void
rd_str(int n, char *s)
{
	int i;

	for(i=0; i<n; i++) s[i] = rd();
	s[i] = '\0';
}

int
rd_str_chk(int n, char *s)
{
	char buf[256];

	rd_str(n, buf);
	return strcmp(buf, s) == 0;
}

int
rd_int(int n) /* big endian */
{
	int i, v;

	v = 0;
	for(i=0; i<n; i++) v = (v << 8) | rd();
	return v;
}

int
rd_delta(void)
{
	int v, c;

	v = 0;
	do{
		if((c = rd()) == EOF) return EOF;
		v = (v << 7) | (c & 0x7f);
	}while(c & 0x80);
	return v;
}


struct lpf_rec{
	double freq, Q;
};

struct lpf_stat_rec{
	int idx;
	double in[4], out[4];
	double a0, a1, a2, b0, b1, b2, div_a0;
};

void
lpf_update(struct lpf_rec *lpf, struct lpf_stat_rec *stat, int smp_freq)
{
	double w0, alpha;

	w0 = 2 * M_PI * lpf->freq / smp_freq;
	alpha = sin(w0) / (2 * lpf->Q);
	stat->b1 = 1 - cos(w0);
	stat->b0 = stat->b2 = stat->b1 * 0.5;
	stat->a0 = 1 + alpha;
	stat->a1 = -2 * cos(w0);
	stat->a2 = 1 - alpha;
	if(stat->a0 != 0) stat->div_a0 = 1 / stat->a0;
}

void
lpf_init(struct lpf_rec *lpf, struct lpf_stat_rec *stat, int smp_freq)
{
	int i;

	for(i=0; i<4; i++) stat->in[i] = stat->out[i] = 0;
	stat->idx = 0;

	lpf_update(lpf, stat, smp_freq);
}

double
lpf_out(struct lpf_stat_rec *stat, double in)
{
	double *out_p;
	int i_1, i_2;

	stat->in[stat->idx] = in;
	out_p = &stat->out[stat->idx];

	if(stat->a0 != 0){
		i_1 = (stat->idx + 4 - 1) & 3;
		i_2 = (i_1 + 4 - 1) & 3;
		*out_p = (stat->b0 * in
			+ stat->b1 * stat->in[i_1]
			+ stat->b2 * stat->in[i_2]
			- stat->a1 * stat->out[i_1]
			- stat->a2 * stat->out[i_2] ) * stat->div_a0;
	}else{
		*out_p = 0;
	}
	stat->idx = (stat->idx + 1) & 3;
	return *out_p;
}


#define NOTE_BUF_N	256

struct vco_stat_rec{
	double cycle, freq, sec;
};

void
vco_stat_update(struct vco_stat_rec *stat, double freq, double sec)
{
	stat->cycle += freq * (sec - stat->sec);	
	stat->freq = freq;
	stat->sec = sec;
}

struct note_rec{
	int ch;
	int note;
	int onoff;
	double on_sec;
	double off_sec;
	int velo;
	struct vco_stat_rec vco_stat[2];
	double off_v;
	struct lpf_stat_rec lpf_stat;
} note_buf[NOTE_BUF_N];

int
note_buf_is_free(int i)
{
	return note_buf[i].ch < 0;
}

void
note_buf_free(int i)
{
	note_buf[i].ch = -1;
}

void
note_buf_init(void)
{
	int i;

	for(i=0; i<NOTE_BUF_N; i++) note_buf_free(i);
}

int
note_buf_search(int ch, int note, int onoff)
{
	int i;

	for(i=0; i<NOTE_BUF_N; i++) {
		if( (ch < 0 && note_buf[i].ch < 0) ||
		    (note_buf[i].ch == ch &&
		     note_buf[i].note == note &&
		     note_buf[i].onoff == onoff) ) return i;
	}
	return -1;
}

int
header(void)
{
	int v;

	if(!rd_str_chk(4, "MThd")) ERR("header id");
	if(rd_int(4) != 6) ERR("header size");
	if(rd_int(2) != 0) ERR("header format type");
	if(rd_int(2) != 1) ERR("header track num");
	if((v = rd_int(2)) & 0x8000) ERR("header division");
	return v; /* div4 */
}

double
note_to_freq(int note)
{
	return 440 * pow(2, (note - 69) / 12.0);
}

int
opt_idx(char *key, int ac, char **av)
{
	int i;

	for(i=1; i<ac; i++) if(strcmp(av[i], key) == 0) return i;
	return -1;
}

char *
opt_str(char *key, int ac, char **av, char *def)
{
	int i;

	i = opt_idx(key, ac, av);
	if(i < 0 || i+1 >= ac) return def;
	return av[i+1];
}

int
opt_int(char *key, int ac, char **av, int def)
{
	char *s;

	if((s = opt_str(key, ac, av, NULL)) == NULL) return def;
	return strtol(s, NULL, 0);
}

struct out_rec{
	int smp_freq, smp_cnt;
	int bit_len;
	int sign;
	int ch_num;
	FILE *fp;

	int base;
	int amp;
	int iv_min;
	int iv_max;
	double smp_t, sec;
};

void
out_init(struct out_rec *ot, int ac, char **av)
{
	char cmd[1024], *fn;

	ot->smp_freq = opt_int("-r", ac, av, 44100);
	ot->smp_cnt = 0;
	ot->bit_len = opt_int("-b", ac, av, 16);
	if(ot->bit_len != 8 && ot->bit_len != 16) ERR("bit_len");
	ot->sign = (opt_idx("-u", ac, av) < 0);
	ot->ch_num = opt_int("-c", ac, av, 2);

	ot->fp = stdout;
	cmd[0] = '\0';
	fn = "";
	if(opt_idx("-play", ac, av) >= 0){
		strcat(cmd, "play");
	}else if(opt_idx("-sox", ac, av) >= 0){
		strcat(cmd, "sox");
		fn = opt_str("-sox", ac, av, "-d");
	}
	if(cmd[0]){
		sprintf(cmd + strlen(cmd), " -t raw -r %d -b %d %s -c %d - %s",
			ot->smp_freq, ot->bit_len,
			ot->sign ? "-s" : "-u",
			ot->ch_num, fn);
		if((ot->fp = popen(cmd, "w")) == NULL) ERR("popen");
	}
	ot->amp = ot->bit_len == 8 ? 127 : 32767;
	ot->base = ot->sign ? 0 : ot->amp + 1;
	ot->iv_min = ot->base - (ot->amp + 1);
	ot->iv_max = ot->base + ot->amp;

	ot->smp_t = 1.0 / ot->smp_freq;
}

void
out_do(struct out_rec *ot, double v)
{
	int iv;

	iv = ot->base + (int)(v *ot->amp);
	if(iv > ot->iv_max) iv = ot->iv_max;
	if(iv < ot->iv_min) iv = ot->iv_min;
	switch(ot->bit_len){
	case 8:
		fputc(iv, ot->fp);
		break;
	case 16:
		fputc(iv & 0xff, ot->fp);
		fputc((iv >> 8) & 0xff, ot->fp);
		break;
	}
}

#define OFF		0
#define ON		1

#define WAVE_SIN	0
#define WAVE_SAW	1
#define WAVE_SQUARE	2
#define WAVE_NOISE	3

double
wave_out(int wave, double cycle)
{
	cycle -= (int)cycle;

	switch(wave){
	case WAVE_SIN:
		return sin(2 * M_PI * cycle);
	case WAVE_SAW:
		cycle *= 2;
		if(cycle > 1) cycle -= 2;
		return cycle;
	case WAVE_SQUARE:
		return cycle < 0.5 ? 1 : -1;
	case WAVE_NOISE:
		return ((double)rand() / RAND_MAX) * 2 - 1;
	}
	return 0;
}

struct vco_rec{
	int wave1, wave2;
	int tune; /* for vco2 */
	double mix;
	int ring;
};

struct modu_rec{
	int pitch1, pitch2, filter;
};

struct lfo_rec{
	int wave;
	double freq, delay;
};

struct env_rec{
	double attack;	/* sec */
	double decay;	/* sec */
	double sustain;	/* 0..1 */
	double release;	/* sec */
};

struct tone_rec{
	struct vco_rec vco;
	struct lpf_rec lpf;
	struct env_rec env;
	double level;
	struct modu_rec lfo_modu;
	struct lfo_rec lfo;
	struct modu_rec env_modu;
} tone_inf[] = {
	{	/* strings */
		{ WAVE_SAW, WAVE_SAW, 12, 0.5, OFF },
		{ 3000, 1.5 },
		{ 0.15, 0.5, 0.8, 0.5 },
		1.0,
		{ OFF, 12, OFF }, { WAVE_SIN, 4, 0.3 },
		{ OFF, OFF, OFF },
	},{	/* bass */
		{ WAVE_SAW, WAVE_SQUARE, OFF, 0.5, OFF },
		{ 1000, 1.5} ,
		{ 0.05, 0.2, 0.4, 0.2 },
		1.0,
		{ OFF, 60, OFF }, { WAVE_SIN, 1.5, 0.2 },
		{ OFF, OFF, OFF },
	},{	/* lead */
		{ WAVE_SQUARE, WAVE_SQUARE, 10, 0.5, OFF },
		{ 2000, 4 },
		{ 0.01, 0.2, 0.8, 0.3 },
		1.0,
		{ OFF, 1, 5 }, { WAVE_SIN, 4, 0.3 },
		{ OFF, OFF, OFF },
	},{	/* SIN */
		{ WAVE_SIN, WAVE_SIN, OFF, 0, OFF },
		{ 20000, 0.8 },
		{ 0, 0.3, 0.2, 0.3 },
		1.4,
		{ 25, OFF, OFF }, { WAVE_SIN, 6, 0.3 },
		{ OFF, OFF, OFF },
	}
}, drum_tone_inf[] = {
	{	/* bass */
		{ WAVE_SIN, WAVE_NOISE, OFF, 0.4, OFF },
		{ 400, 1 },
		{ 0.01, 0.18, 0, 0.18 },
		9.0,
		{ 100, OFF, 30 }, { WAVE_NOISE, 0, 0.5 },
		{ OFF, OFF, OFF },
	},{	/* snare */
		{ WAVE_SQUARE, WAVE_NOISE, OFF, 0.8, ON },
		{ 1500, 1.7 },
		{ 0, 0.4, 0.3, 0.4 },
		5,
		{ OFF, OFF, OFF, }, {},
		{ OFF, OFF, OFF },
	},{	/* tom */
		{ WAVE_SQUARE, WAVE_NOISE, OFF, 0.5, ON },
		{ 800, 2.5 },
		{ 0, 0.03, 0.1, 0.4 },
		5,
		{ OFF, OFF, OFF, }, {},
		{ 200, OFF, 1200 },
	},{	/* hi-hat close */
		{ WAVE_SQUARE, WAVE_SQUARE, 700, 0.9, ON },
		{ 16000, 2 },
		{ 0, 0.15, 0, 0.15 },
		0.6,
		{ OFF, OFF, OFF, }, {},
		{ OFF, OFF, OFF },
	},{	/* hi-hat open */
		{ WAVE_SQUARE, WAVE_SQUARE, 700, 0.9, ON },
		{ 16000, 2 },
		{ 0, 0, 1, 0.35 },
		0.6,
		{ OFF, OFF, OFF, }, {},
		{ OFF, OFF, OFF },
	},{	/* cymbal */
		{ WAVE_NOISE, WAVE_SQUARE, OFF, 0.8, ON },
		{ 4000, 2 },
		{ 0, 0.01, 0.2, 0.8 },
		9,
		{ OFF, OFF, OFF }, {},
		{ OFF, OFF, 600 },
	},{	/* side stick */
		{ WAVE_NOISE, WAVE_SQUARE, OFF, 0.2, OFF },
		{ 1700, 3 },
		{ 0, 0.012, 0.1, 0.7 },
		10,
		{ OFF, OFF, OFF }, {},
		{ OFF, OFF, OFF },
	}
};

struct tone_rec *
tone_get(int prog, int note, double *ret_freq)
{
	int idx;
	struct tone_rec *ret;

	idx = -1;
	if(prog <= 0){ /* drum part */
		switch(note){
		case 36: /* bass drum1 */
			idx = 0;
			note = 28;
			break;
		case 37: /* side stick */
			idx = 6;
			note = 110;
			break;
		case 40: /* electric snare */
			idx = 1;
			note = 69;
			break;
		case 41: /* low floor tom */
			idx = 2;
			note = 50;
			break;
		case 42: /* closed hi-hat */
			idx = 3;
			note = 115 + 8;
			break;
		case 46: /* open hi-hat */
			idx = 4;
			note = 115 + 8;
			break;
		case 49: /* crash cymbal 1 */
		case 57: /* crash cymbal 2 */
			idx = 5;
			note = 100;
			break;
		}
		ret = idx < 0 ? NULL : &drum_tone_inf[idx];
	}else{
		switch(prog){
		case 48: /* timpani */
		case 50: /* strings ensamble 2 */
			idx = 0;
			break;
		case 35: /* electric bass (pick) */
			idx = 1;
			break;
		case 79: /* whistle */
		case 81: /* lead 1 (square) */
		case 87: /* lead 7 (fifths) */
			idx = 2;
			break;
		case 24: /* tango accordion */
		case 67: /* tenor sax */
			idx = 3;
			break;
		}
		ret = idx < 0 ? NULL : &tone_inf[idx];
	}
	if(ret_freq) *ret_freq = note_to_freq(note);
	return ret;
}

#define MIDI_CH_N	16
struct ch_rec{
	int vol;
	int pan;
	int bend;
	int rpn;
	int bend_range;
	int prog;
} ch_inf[ MIDI_CH_N ];

#define CH_PROG(ch)	( (ch) == 9 ? 0 : ch_inf[ch].prog )

double
env_out(struct note_rec *nt, double sec)
{
	struct tone_rec *tn;
	struct env_rec *e;
	double v;

	if((tn = tone_get(CH_PROG(nt->ch), nt->note, NULL)) == NULL) return 0;
	e = &tn->env;
	if(nt->onoff){
		sec -= nt->on_sec;
		if(sec < e->attack){
			v = sec / e->attack;
			return log10(1 + v * 9);
		}
		sec -= e->attack;
		if(sec < e->decay){
			v = sec / e->decay;
			v = log10(1 + v * 9);
			return 1 - v * (1 - e->sustain);
		}
		return e->sustain;
	}
	sec -= nt->off_sec;
	if(sec < e->release){
		v = sec / e->release;
		v = log10(1 + v * 9);
		return (1 - v) * nt->off_v;
	}
	return 0;
}

void
modu_out(double v, struct modu_rec *modu, double *ret_arr)
{
	if(modu->pitch1) ret_arr[0] += v * modu->pitch1 / 100.0 / 12;
	if(modu->pitch2) ret_arr[1] += v * modu->pitch2 / 100.0 / 12;
	if(modu->filter) ret_arr[2] += v * modu->filter / 100.0 / 12;
}

double
lfo_out(struct lfo_rec *lfo, struct modu_rec *modu, double sec, double on_sec)
{
	double dsec;

	if(!(modu->pitch1 || modu->pitch2 || modu->filter)) return 0;
	if((dsec = sec - on_sec - lfo->delay) <= 0) return 0;
	return wave_out(lfo->wave, lfo->freq * dsec);
}

double
vco_out(int wave, struct vco_stat_rec *stat, double freq, double sec, double modu_v)
{
	if(modu_v != 0) freq *= pow(2, modu_v /*/ 12*/);
	vco_stat_update(stat, freq, sec);
	return wave_out(wave, stat->cycle);
}

double
vcf_out(struct lpf_rec *lpf, struct lpf_stat_rec *lpf_stat, struct out_rec *ot, double modu_v, double v)
{
	struct lpf_rec lpf_tmp;

	if(lpf_stat->idx < 0) lpf_init(lpf, lpf_stat, ot->smp_freq);
	if(modu_v != 0){
		lpf_tmp = *lpf;
		lpf_tmp.freq *= pow(2, modu_v /*/ 12*/);
		lpf_update(&lpf_tmp, lpf_stat, ot->smp_freq);
	}
	return lpf_out(lpf_stat, v);
}

int
note_out(struct out_rec *ot, struct note_rec *nt, double *vl, double *vr)
{
	double v, v1, v2, freq, pan, lfo_v, env_v, modu_v[3];
	int nch;
	struct tone_rec *tn;
	struct vco_rec *vco;

	nch = nt->ch;
	tn = tone_get(CH_PROG(nch), nt->note, &freq);
	if(tn == NULL) return 0;

	if(ch_inf[nch].bend != 0) freq *= pow(2, ch_inf[nch].bend / 8192.0 * ch_inf[nch].bend_range / 12);

	lfo_v = lfo_out(&tn->lfo, &tn->lfo_modu, ot->sec, nt->on_sec);
	env_v = env_out(nt, ot->sec);

	modu_v[0] = modu_v[1] = modu_v[2] = 0;
	modu_out(lfo_v, &tn->lfo_modu, modu_v);
	modu_out(env_v, &tn->env_modu, modu_v);

	vco = &tn->vco;
	v1 = vco_out(vco->wave1, &nt->vco_stat[0], freq, ot->sec, modu_v[0]);

	freq *= pow(2, (vco->tune / 100.0) / 12);
	v2 = vco_out(vco->wave2, &nt->vco_stat[1], freq, ot->sec, modu_v[1]);
	if(vco->ring){
		v = v1 * v2;
		v1 = (v1 + v2) / 2;
		v2 = v;
	}
	v = v1 * (1 - vco->mix) + v2 * vco->mix;

	v = vcf_out(&tn->lpf, &nt->lpf_stat, ot, modu_v[2], v);

	v *= env_v * tn->level;
	v *= nt->velo / 127.0;
	v *= ch_inf[nch].vol / (double)((1<<14)-1);
	if(ot->ch_num == 1){
		*vl += v;
	}else{
	pan = ch_inf[nch].pan / (double)(1<<14);
		*vl += (1 - pan) * v;
		*vr += pan * v;
	}
	return (nt->onoff == 0 && ot->sec - nt->off_sec >= tn->env.release);
}

void
data_out(struct out_rec *ot, double evt_sec)
{
	double vl, vr;
	int i;
	struct note_rec *nt;

	while((ot->sec = ot->smp_t * ot->smp_cnt) < evt_sec){
		vl = vr = 0;
		for(i=0; i<NOTE_BUF_N; i++){
			if(note_buf_is_free(i)) continue;
			nt = &note_buf[i];
			if(note_out(ot, nt, &vl, &vr)) note_buf_free(i);
		}
		out_do(ot, vl / 16);
		if(ot->ch_num > 1) out_do(ot, vr / 16);
		ot->smp_cnt++;
	}
}

void
note_onoff(int onoff, double evt_sec, int ch, int note, int velo)
{
	int i, j;
	struct vco_stat_rec *stat;

	if(onoff){
		if((i = note_buf_search(-1, -1, -1)) < 0){
			MSG("note_buf full");
			return;
		}
		note_buf[i].note = note;
		note_buf[i].ch = ch;
		note_buf[i].onoff = 1;
		note_buf[i].on_sec = evt_sec;
		note_buf[i].velo = velo;
		for(j=0; j<2; j++){
			stat = &note_buf[i].vco_stat[j];
			stat->cycle = 0;
			stat->sec = evt_sec;
		}
		note_buf[i].lpf_stat.idx = -1;
	}else{
		if((i = note_buf_search(ch, note, 1)) < 0) return;
		note_buf[i].off_v = env_out(&note_buf[i], evt_sec);
		note_buf[i].onoff = 0;
		note_buf[i].off_sec = evt_sec;
	}
}

void
msb_set(int *vp, int v)
{
	*vp &= ~(127<<7);
	*vp |= v<<7;
}

void
lsb_set(int *vp, int v)
{
	*vp &= ~127;
	*vp |= v;
}

void
bend_note_update(int ch, double sec)
{
	int i, j;
	struct note_rec *nt;
	struct vco_stat_rec *stat;

	for(i=0; i<NOTE_BUF_N; i++){
		if(note_buf_is_free(i)) continue;
		nt = &note_buf[i];
		if(nt->ch != ch) continue;
		for(j=0; j<2; j++){
			stat = &nt->vco_stat[j];
			vco_stat_update(stat, stat->freq, sec);
		}
	}
}

int
main(int ac, char **av)
{
	int div4, delta_sum;
	int i, n, v, hi, low, note, velo;
	int ch, type;
	double sec;
	struct out_rec otr;
	int tempo, tempo_delta_sum;
	double tempo_sec;

	out_init(&otr, ac, av);
	note_buf_init();
	for(i=0; i<MIDI_CH_N; i++){
		ch_inf[i].vol = 0;
		ch_inf[i].pan = 1<<(14-1);
		ch_inf[i].bend = 0;
		ch_inf[i].rpn = 0;
		ch_inf[i].bend_range = 2;
		ch_inf[i].prog =-1;
	}
	tempo = 500000;
	tempo_delta_sum = 0;
	tempo_sec = 0;

	div4 = header();

	if(!rd_str_chk(4, "MTrk")) ERR("track id");
	v = rd_int(4); /* skip */

	hi = low = 0;
	delta_sum = 0;
	while((v = rd_delta()) != EOF){
		delta_sum += v;
		sec = tempo_sec + (double)(delta_sum - tempo_delta_sum) / div4 * tempo * 0.000001;
		
		if((v = rd()) & 0x80){
			hi = (v >> 4) & 0xf;
			low  = v & 0xf;
		}else bk(v);

		data_out(&otr, sec);

		ch = low;
		switch(hi){
		case 8:
		case 9:
			note = rd();
			velo = rd();
			note_onoff(hi == 9, sec, ch, note, velo);
			break;
		case 0xb: /* control change */
			type = rd();
			v = rd();
			switch(type){
			case 7: /* channel volume msb */
				msb_set(&ch_inf[ch].vol, v);
				break;
			case 39: /* channel volume lsb */
				lsb_set(&ch_inf[ch].vol, v);
				break;
			case 10: /* pan msb */
				msb_set(&ch_inf[ch].pan, v);
				break;
			case 42: /* pan lsb */
				lsb_set(&ch_inf[ch].pan, v);
				break;
			case 100: /* rpn lsb */
				lsb_set(&ch_inf[ch].rpn, v);
				break;
			case 101: /* rpn msb */
				msb_set(&ch_inf[ch].rpn, v);
				break;
			case 6: /* data entry msb */
				switch(ch_inf[ch].rpn){
				case 0: /* pitch bend range */
					ch_inf[ch].bend_range = v;
					break;
				}
				break;
			}
			break;
		case 0xa:
			rd();
			rd();
			break;
		case 0xe: /* pitch wheel change */
			bend_note_update(ch, sec);
			v = rd();
			v |= rd() << 7;
			ch_inf[ch].bend = v - 8192;
			break;
		case 0xc: /* program number */
			v = rd();
			ch_inf[ch].prog = v;
			break;
		case 0xd:
			rd();
			break;
		case 0xf:
			type = rd();
			switch(low){
			case 0:
				while(rd() != 0xf7);
				break;
			case 1:
			case 3:
				rd();
				break;
			case 2:
				rd();
				rd();
				break;
			case 0xf: /* meta */
				n = rd();
				switch(type){
				case 0x51: /* set tempo */
					v = rd_int(n);
					tempo = v;
					tempo_delta_sum = delta_sum;
					tempo_sec = sec;
					break;
				default:
					for(i=0; i<n; i++) rd();
					break;
				}
				break;
			default:
				break;
			}
			break;
		}
	}
	if(otr.fp != stdout) pclose(otr.fp);
	return 0;
}

/* EOF */


#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <math.h>

#define MSG(s) fprintf(stderr, "%s() %s L%d : %s\n", __func__, __FILE__, __LINE__, s)
#define ERR(s) do{ fprintf(stderr, "ERR "); MSG(s); exit(1); }while(0)

int bk_buf = -1;

int
rd(void)
{
	int v;

	if((v = bk_buf) < 0) return getchar();
	bk_buf = -1;
	return v;
}

void
bk(int v)
{
	if(bk_buf >= 0) ERR("give up");
	bk_buf = v;
}

void
rd_str(int n, char *s)
{
	int i;

	for(i=0; i<n; i++) s[i] = rd();
	s[i] = '\0';
}

int
rd_str_chk(int n, char *s)
{
	char buf[256];

	rd_str(n, buf);
	return strcmp(buf, s) == 0;
}

int
rd_int(int n) /* big endian */
{
	int i, v;

	v = 0;
	for(i=0; i<n; i++) v = (v << 8) | rd();
	return v;
}

int
rd_delta(void)
{
	int v, c;

	v = 0;
	do{
		if((c = rd()) == EOF) return EOF;
		v = (v << 7) | (c & 0x7f);
	}while(c & 0x80);
	return v;
}


struct lpf_rec{
	double freq, Q;
};

struct lpf_stat_rec{
	int idx;
	double in[4], out[4];
	double a0, a1, a2, b0, b1, b2, div_a0;
};

void
lpf_update(struct lpf_rec *lpf, struct lpf_stat_rec *stat, int smp_freq)
{
	double w0, alpha;

	w0 = 2 * M_PI * lpf->freq / smp_freq;
	alpha = sin(w0) / (2 * lpf->Q);
	stat->b1 = 1 - cos(w0);
	stat->b0 = stat->b2 = stat->b1 * 0.5;
	stat->a0 = 1 + alpha;
	stat->a1 = -2 * cos(w0);
	stat->a2 = 1 - alpha;
	if(stat->a0 != 0) stat->div_a0 = 1 / stat->a0;
}

void
lpf_init(struct lpf_rec *lpf, struct lpf_stat_rec *stat, int smp_freq)
{
	int i;

	for(i=0; i<4; i++) stat->in[i] = stat->out[i] = 0;
	stat->idx = 0;

	lpf_update(lpf, stat, smp_freq);
}

double
lpf_out(struct lpf_stat_rec *stat, double in)
{
	double *out_p;
	int i_1, i_2;

	stat->in[stat->idx] = in;
	out_p = &stat->out[stat->idx];

	if(stat->a0 != 0){
		i_1 = (stat->idx + 4 - 1) & 3;
		i_2 = (i_1 + 4 - 1) & 3;
		*out_p = (stat->b0 * in
			+ stat->b1 * stat->in[i_1]
			+ stat->b2 * stat->in[i_2]
			- stat->a1 * stat->out[i_1]
			- stat->a2 * stat->out[i_2] ) * stat->div_a0;
	}else{
		*out_p = 0;
	}
	stat->idx = (stat->idx + 1) & 3;
	return *out_p;
}


#define NOTE_BUF_N	256

struct vco_stat_rec{
	double cycle, freq, sec;
};

void
vco_stat_update(struct vco_stat_rec *stat, double freq, double sec)
{
	stat->cycle += freq * (sec - stat->sec);	
	stat->freq = freq;
	stat->sec = sec;
}

struct note_rec{
	int ch;
	int note;
	int onoff;
	double on_sec;
	double off_sec;
	int velo;
	struct vco_stat_rec vco_stat[2];
	double off_v;
	struct lpf_stat_rec lpf_stat;
} note_buf[NOTE_BUF_N];

int
note_buf_is_free(int i)
{
	return note_buf[i].ch < 0;
}

void
note_buf_free(int i)
{
	note_buf[i].ch = -1;
}

void
note_buf_init(void)
{
	int i;

	for(i=0; i<NOTE_BUF_N; i++) note_buf_free(i);
}

int
note_buf_search(int ch, int note, int onoff)
{
	int i;

	for(i=0; i<NOTE_BUF_N; i++) {
		if( (ch < 0 && note_buf[i].ch < 0) ||
		    (note_buf[i].ch == ch &&
		     note_buf[i].note == note &&
		     note_buf[i].onoff == onoff) ) return i;
	}
	return -1;
}

int
header(void)
{
	int v;

	if(!rd_str_chk(4, "MThd")) ERR("header id");
	if(rd_int(4) != 6) ERR("header size");
	if(rd_int(2) != 0) ERR("header format type");
	if(rd_int(2) != 1) ERR("header track num");
	if((v = rd_int(2)) & 0x8000) ERR("header division");
	return v; /* div4 */
}

double
note_to_freq(int note)
{
	return 440 * pow(2, (note - 69) / 12.0);
}

int
opt_idx(char *key, int ac, char **av)
{
	int i;

	for(i=1; i<ac; i++) if(strcmp(av[i], key) == 0) return i;
	return -1;
}

char *
opt_str(char *key, int ac, char **av, char *def)
{
	int i;

	i = opt_idx(key, ac, av);
	if(i < 0 || i+1 >= ac) return def;
	return av[i+1];
}

int
opt_int(char *key, int ac, char **av, int def)
{
	char *s;

	if((s = opt_str(key, ac, av, NULL)) == NULL) return def;
	return strtol(s, NULL, 0);
}

struct out_rec{
	int smp_freq, smp_cnt;
	int bit_len;
	int sign;
	int ch_num;
	FILE *fp;

	int base;
	int amp;
	int iv_min;
	int iv_max;
	double smp_t, sec;
};

void
out_init(struct out_rec *ot, int ac, char **av)
{
	char cmd[1024], *fn;

	ot->smp_freq = opt_int("-r", ac, av, 44100);
	ot->smp_cnt = 0;
	ot->bit_len = opt_int("-b", ac, av, 16);
	if(ot->bit_len != 8 && ot->bit_len != 16) ERR("bit_len");
	ot->sign = (opt_idx("-u", ac, av) < 0);
	ot->ch_num = opt_int("-c", ac, av, 2);

	ot->fp = stdout;
	cmd[0] = '\0';
	fn = "";
	if(opt_idx("-play", ac, av) >= 0){
		strcat(cmd, "play");
	}else if(opt_idx("-sox", ac, av) >= 0){
		strcat(cmd, "sox");
		fn = opt_str("-sox", ac, av, "-d");
	}
	if(cmd[0]){
		sprintf(cmd + strlen(cmd), " -t raw -r %d -b %d %s -c %d - %s",
			ot->smp_freq, ot->bit_len,
			ot->sign ? "-s" : "-u",
			ot->ch_num, fn);
		if((ot->fp = popen(cmd, "w")) == NULL) ERR("popen");
	}
	ot->amp = ot->bit_len == 8 ? 127 : 32767;
	ot->base = ot->sign ? 0 : ot->amp + 1;
	ot->iv_min = ot->base - (ot->amp + 1);
	ot->iv_max = ot->base + ot->amp;

	ot->smp_t = 1.0 / ot->smp_freq;
}

void
out_do(struct out_rec *ot, double v)
{
	int iv;

	iv = ot->base + (int)(v *ot->amp);
	if(iv > ot->iv_max) iv = ot->iv_max;
	if(iv < ot->iv_min) iv = ot->iv_min;
	switch(ot->bit_len){
	case 8:
		fputc(iv, ot->fp);
		break;
	case 16:
		fputc(iv & 0xff, ot->fp);
		fputc((iv >> 8) & 0xff, ot->fp);
		break;
	}
}

#define OFF		0
#define ON		1

#define WAVE_SIN	0
#define WAVE_SAW	1
#define WAVE_SQUARE	2
#define WAVE_NOISE	3

double
wave_out(int wave, double cycle)
{
	cycle -= (int)cycle;

	switch(wave){
	case WAVE_SIN:
		return sin(2 * M_PI * cycle);
	case WAVE_SAW:
		cycle *= 2;
		if(cycle > 1) cycle -= 2;
		return cycle;
	case WAVE_SQUARE:
		return cycle < 0.5 ? 1 : -1;
	case WAVE_NOISE:
		return ((double)rand() / RAND_MAX) * 2 - 1;
	}
	return 0;
}

struct vco_rec{
	int wave1, wave2;
	int tune; /* for vco2 */
	double mix;
	int ring;
};

struct modu_rec{
	int pitch1, pitch2, filter;
};

struct lfo_rec{
	int wave;
	double freq, delay;
};

struct env_rec{
	double attack;	/* sec */
	double decay;	/* sec */
	double sustain;	/* 0..1 */
	double release;	/* sec */
};

struct tone_rec{
	struct vco_rec vco;
	struct lpf_rec lpf;
	struct env_rec env;
	double level;
	struct modu_rec lfo_modu;
	struct lfo_rec lfo;
	struct modu_rec env_modu;
	// エンベロープ変調用のメンバを追加
	
} tone_inf[] = {
	{	/* strings */
		{ WAVE_SAW, WAVE_SAW, 12, 0.5, OFF },
		{ 3000, 1.5 },
		{ 0.15, 0.5, 0.8, 0.5 },
		1.0,
		{ OFF, 12, OFF }, { WAVE_SIN, 4, 0.3 },
		{ OFF, OFF, OFF },
	},{	/* bass */
		{ WAVE_SAW, WAVE_SQUARE, OFF, 0.5, OFF },
		{ 1000, 1.5} ,
		{ 0.05, 0.2, 0.4, 0.2 },
		1.0,
		{ OFF, 60, OFF }, { WAVE_SIN, 1.5, 0.2 },
		{ OFF, OFF, OFF },
	},{	/* lead */
		{ WAVE_SQUARE, WAVE_SQUARE, 10, 0.5, OFF },
		{ 2000, 4 },
		{ 0.01, 0.2, 0.8, 0.3 },
		1.0,
		{ OFF, 1, 5 }, { WAVE_SIN, 4, 0.3 },
		{ OFF, OFF, OFF },
	},{	/* SIN */
		{ WAVE_SIN, WAVE_SIN, OFF, 0, OFF },
		{ 20000, 0.8 },
		{ 0, 0.3, 0.2, 0.3 },
		1.4,
		{ 25, OFF, OFF }, { WAVE_SIN, 6, 0.3 },
		{ OFF, OFF, OFF },
	}
}, drum_tone_inf[] = {
	{	/* bass */
		{ WAVE_SIN, WAVE_NOISE, OFF, 0.4, OFF },
		{ 400, 1 },
		{ 0.01, 0.18, 0, 0.18 },
		9.0,
		{ 100, OFF, 30 }, { WAVE_NOISE, 0, 0.5 },
		{ OFF, OFF, OFF },
	},{	/* snare */
		{ WAVE_SQUARE, WAVE_NOISE, OFF, 0.8, ON },
		{ 1500, 1.7 },
		{ 0, 0.4, 0.3, 0.4 },
		5,
		{ OFF, OFF, OFF, }, {},
		{ OFF, OFF, OFF },
	},{	/* tom */
		{ WAVE_SQUARE, WAVE_NOISE, OFF, 0.5, ON },
		{ 800, 2.5 },
		{ 0, 0.03, 0.1, 0.4 },
		5,
		{ OFF, OFF, OFF, }, {},
		{ 200, OFF, 1200 },
	},{	/* hi-hat close */
		{ WAVE_SQUARE, WAVE_SQUARE, 700, 0.9, ON },
		{ 16000, 2 },
		{ 0, 0.15, 0, 0.15 },
		0.6,
		{ OFF, OFF, OFF, }, {},
		{ OFF, OFF, OFF },
	},{	/* hi-hat open */
		{ WAVE_SQUARE, WAVE_SQUARE, 700, 0.9, ON },
		{ 16000, 2 },
		{ 0, 0, 1, 0.35 },
		0.6,
		{ OFF, OFF, OFF, }, {},
		{ OFF, OFF, OFF },
	},{	/* cymbal */
		{ WAVE_NOISE, WAVE_SQUARE, OFF, 0.8, ON },
		{ 4000, 2 },
		{ 0, 0.01, 0.2, 0.8 },
		9,
		{ OFF, OFF, OFF }, {},
		{ OFF, OFF, 600 },
	},{	/* side stick */
		{ WAVE_NOISE, WAVE_SQUARE, OFF, 0.2, OFF },
		{ 1700, 3 },
		{ 0, 0.012, 0.1, 0.7 },
		10,
		{ OFF, OFF, OFF }, {},
		{ OFF, OFF, OFF },
	}
};

struct tone_rec *
tone_get(int prog, int note, double *ret_freq)
{
	int idx;
	struct tone_rec *ret;

	idx = -1;
	if(prog <= 0){ /* drum part */
		switch(note){
		case 36: /* bass drum1 */
			idx = 0;
			note = 28;
			break;
		case 37: /* side stick */
			idx = 6;
			note = 110;
			break;
			// サイド・スティック用の設定を追加
			
		case 40: /* electric snare */
			idx = 1;
			note = 69;
			break;
		case 41: /* low floor tom */
			idx = 2;
			note = 50;
			break;
		case 42: /* closed hi-hat */
			idx = 3;
			note = 115 + 8;
			break;
		case 46: /* open hi-hat */
			idx = 4;
			note = 115 + 8;
			break;
		case 49: /* crash cymbal 1 */
		case 57: /* crash cymbal 2 */
			idx = 5;
			note = 100;
			break;
		}
		ret = idx < 0 ? NULL : &drum_tone_inf[idx];
	}else{
		switch(prog){
		case 48: /* timpani */
		case 50: /* strings ensamble 2 */
			idx = 0;
			break;
		case 35: /* electric bass (pick) */
			idx = 1;
			break;
		case 79: /* whistle */
		case 81: /* lead 1 (square) */
		case 87: /* lead 7 (fifths) */
			idx = 2;
			break;
		case 24: /* tango accordion */
		case 67: /* tenor sax */
			idx = 3;
			break;
		}
		ret = idx < 0 ? NULL : &tone_inf[idx];
	}
	if(ret_freq) *ret_freq = note_to_freq(note);
	return ret;
}

#define MIDI_CH_N	16
struct ch_rec{
	int vol;
	int pan;
	int bend;
	int rpn;
	int bend_range;
	int prog;
} ch_inf[ MIDI_CH_N ];

#define CH_PROG(ch)	( (ch) == 9 ? 0 : ch_inf[ch].prog )

double
env_out(struct note_rec *nt, double sec)
{
	struct tone_rec *tn;
	struct env_rec *e;
	double v;

	if((tn = tone_get(CH_PROG(nt->ch), nt->note, NULL)) == NULL) return 0;
	e = &tn->env;
	if(nt->onoff){
		sec -= nt->on_sec;
		if(sec < e->attack){
			v = sec / e->attack;
			return log10(1 + v * 9);
		}
		sec -= e->attack;
		if(sec < e->decay){
			v = sec / e->decay;
			v = log10(1 + v * 9);
			return 1 - v * (1 - e->sustain);
		}
		return e->sustain;
	}
	sec -= nt->off_sec;
	if(sec < e->release){
		v = sec / e->release;
		v = log10(1 + v * 9);
		return (1 - v) * nt->off_v;
	}
	return 0;
}

void
modu_out(double v, struct modu_rec *modu, double *ret_arr)
{
	if(modu->pitch1) ret_arr[0] += v * modu->pitch1 / 100.0 / 12;
	if(modu->pitch2) ret_arr[1] += v * modu->pitch2 / 100.0 / 12;
	if(modu->filter) ret_arr[2] += v * modu->filter / 100.0 / 12;
}

double
lfo_out(struct lfo_rec *lfo, struct modu_rec *modu, double sec, double on_sec)
{
	double dsec;

	if(!(modu->pitch1 || modu->pitch2 || modu->filter)) return 0;
	if((dsec = sec - on_sec - lfo->delay) <= 0) return 0;
	return wave_out(lfo->wave, lfo->freq * dsec);
}

double
vco_out(int wave, struct vco_stat_rec *stat, double freq, double sec, double modu_v)
{
	if(modu_v != 0) freq *= pow(2, modu_v /*/ 12*/);
	vco_stat_update(stat, freq, sec);
	return wave_out(wave, stat->cycle);
}

double
vcf_out(struct lpf_rec *lpf, struct lpf_stat_rec *lpf_stat, struct out_rec *ot, double modu_v, double v)
{
	struct lpf_rec lpf_tmp;

	if(lpf_stat->idx < 0) lpf_init(lpf, lpf_stat, ot->smp_freq);
	if(modu_v != 0){
		lpf_tmp = *lpf;
		lpf_tmp.freq *= pow(2, modu_v /*/ 12*/);
		lpf_update(&lpf_tmp, lpf_stat, ot->smp_freq);
	}
	return lpf_out(lpf_stat, v);
}

int
note_out(struct out_rec *ot, struct note_rec *nt, double *vl, double *vr)
{
	double v, v1, v2, freq, pan, lfo_v, env_v, modu_v[3];
	int nch;
	struct tone_rec *tn;
	struct vco_rec *vco;

	nch = nt->ch;
	tn = tone_get(CH_PROG(nch), nt->note, &freq);
	if(tn == NULL) return 0;

	if(ch_inf[nch].bend != 0) freq *= pow(2, ch_inf[nch].bend / 8192.0 * ch_inf[nch].bend_range / 12);

	lfo_v = lfo_out(&tn->lfo, &tn->lfo_modu, ot->sec, nt->on_sec);
	env_v = env_out(nt, ot->sec);

	modu_v[0] = modu_v[1] = modu_v[2] = 0;
	modu_out(lfo_v, &tn->lfo_modu, modu_v);
	modu_out(env_v, &tn->env_modu, modu_v);
	// エンベロープによる変調分の処理を追加
	
	vco = &tn->vco;
	v1 = vco_out(vco->wave1, &nt->vco_stat[0], freq, ot->sec, modu_v[0]);

	freq *= pow(2, (vco->tune / 100.0) / 12);
	v2 = vco_out(vco->wave2, &nt->vco_stat[1], freq, ot->sec, modu_v[1]);
	if(vco->ring){
		v = v1 * v2;
		v1 = (v1 + v2) / 2;
		v2 = v;
	}
	v = v1 * (1 - vco->mix) + v2 * vco->mix;

	v = vcf_out(&tn->lpf, &nt->lpf_stat, ot, modu_v[2], v);

	v *= env_v * tn->level;
	v *= nt->velo / 127.0;
	v *= ch_inf[nch].vol / (double)((1<<14)-1);
	if(ot->ch_num == 1){
		*vl += v;
	}else{
	pan = ch_inf[nch].pan / (double)(1<<14);
		*vl += (1 - pan) * v;
		*vr += pan * v;
	}
	return (nt->onoff == 0 && ot->sec - nt->off_sec >= tn->env.release);
}

void
data_out(struct out_rec *ot, double evt_sec)
{
	double vl, vr;
	int i;
	struct note_rec *nt;

	while((ot->sec = ot->smp_t * ot->smp_cnt) < evt_sec){
		vl = vr = 0;
		for(i=0; i<NOTE_BUF_N; i++){
			if(note_buf_is_free(i)) continue;
			nt = &note_buf[i];
			if(note_out(ot, nt, &vl, &vr)) note_buf_free(i);
		}
		out_do(ot, vl / 16);
		if(ot->ch_num > 1) out_do(ot, vr / 16);
		ot->smp_cnt++;
	}
}

void
note_onoff(int onoff, double evt_sec, int ch, int note, int velo)
{
	int i, j;
	struct vco_stat_rec *stat;

	if(onoff){
		if((i = note_buf_search(-1, -1, -1)) < 0){
			MSG("note_buf full");
			return;
		}
		note_buf[i].note = note;
		note_buf[i].ch = ch;
		note_buf[i].onoff = 1;
		note_buf[i].on_sec = evt_sec;
		note_buf[i].velo = velo;
		for(j=0; j<2; j++){
			stat = &note_buf[i].vco_stat[j];
			stat->cycle = 0;
			stat->sec = evt_sec;
		}
		note_buf[i].lpf_stat.idx = -1;
	}else{
		if((i = note_buf_search(ch, note, 1)) < 0) return;
		note_buf[i].off_v = env_out(&note_buf[i], evt_sec);
		note_buf[i].onoff = 0;
		note_buf[i].off_sec = evt_sec;
		// しれっと修正
		
	}
}

void
msb_set(int *vp, int v)
{
	*vp &= ~(127<<7);
	*vp |= v<<7;
}

void
lsb_set(int *vp, int v)
{
	*vp &= ~127;
	*vp |= v;
}

void
bend_note_update(int ch, double sec)
{
	int i, j;
	struct note_rec *nt;
	struct vco_stat_rec *stat;

	for(i=0; i<NOTE_BUF_N; i++){
		if(note_buf_is_free(i)) continue;
		nt = &note_buf[i];
		if(nt->ch != ch) continue;
		for(j=0; j<2; j++){
			stat = &nt->vco_stat[j];
			vco_stat_update(stat, stat->freq, sec);
		}
	}
}

int
main(int ac, char **av)
{
	int div4, delta_sum;
	int i, n, v, hi, low, note, velo;
	int ch, type;
	double sec;
	struct out_rec otr;
	int tempo, tempo_delta_sum;
	double tempo_sec;

	out_init(&otr, ac, av);
	note_buf_init();
	for(i=0; i<MIDI_CH_N; i++){
		ch_inf[i].vol = 0;
		ch_inf[i].pan = 1<<(14-1);
		ch_inf[i].bend = 0;
		ch_inf[i].rpn = 0;
		ch_inf[i].bend_range = 2;
		ch_inf[i].prog =-1;
	}
	tempo = 500000;
	tempo_delta_sum = 0;
	tempo_sec = 0;

	div4 = header();

	if(!rd_str_chk(4, "MTrk")) ERR("track id");
	v = rd_int(4); /* skip */

	hi = low = 0;
	delta_sum = 0;
	while((v = rd_delta()) != EOF){
		delta_sum += v;
		sec = tempo_sec + (double)(delta_sum - tempo_delta_sum) / div4 * tempo * 0.000001;
		
		if((v = rd()) & 0x80){
			hi = (v >> 4) & 0xf;
			low  = v & 0xf;
		}else bk(v);

		data_out(&otr, sec);

		ch = low;
		switch(hi){
		case 8:
		case 9:
			note = rd();
			velo = rd();
			note_onoff(hi == 9, sec, ch, note, velo);
			break;
		case 0xb: /* control change */
			type = rd();
			v = rd();
			switch(type){
			case 7: /* channel volume msb */
				msb_set(&ch_inf[ch].vol, v);
				break;
			case 39: /* channel volume lsb */
				lsb_set(&ch_inf[ch].vol, v);
				break;
			case 10: /* pan msb */
				msb_set(&ch_inf[ch].pan, v);
				break;
			case 42: /* pan lsb */
				lsb_set(&ch_inf[ch].pan, v);
				break;
			case 100: /* rpn lsb */
				lsb_set(&ch_inf[ch].rpn, v);
				break;
			case 101: /* rpn msb */
				msb_set(&ch_inf[ch].rpn, v);
				break;
			case 6: /* data entry msb */
				switch(ch_inf[ch].rpn){
				case 0: /* pitch bend range */
					ch_inf[ch].bend_range = v;
					break;
				}
				break;
			}
			break;
		case 0xa:
			rd();
			rd();
			break;
		case 0xe: /* pitch wheel change */
			bend_note_update(ch, sec);
			v = rd();
			v |= rd() << 7;
			ch_inf[ch].bend = v - 8192;
			break;
		case 0xc: /* program number */
			v = rd();
			ch_inf[ch].prog = v;
			break;
		case 0xd:
			rd();
			break;
		case 0xf:
			type = rd();
			switch(low){
			case 0:
				while(rd() != 0xf7);
				break;
			case 1:
			case 3:
				rd();
				break;
			case 2:
				rd();
				rd();
				break;
			case 0xf: /* meta */
				n = rd();
				switch(type){
				case 0x51: /* set tempo */
					v = rd_int(n);
					tempo = v;
					tempo_delta_sum = delta_sum;
					tempo_sec = sec;
					break;
				default:
					for(i=0; i<n; i++) rd();
					break;
				}
				break;
			default:
				break;
			}
			break;
		}
	}
	if(otr.fp != stdout) pclose(otr.fp);
	return 0;
}

/* EOF */


prog19.c 解説

prog18.c からの変更箇所のみ

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <math.h>

#define MSG(s) fprintf(stderr, "%s() %s L%d : %s\n", __func__, __FILE__, __LINE__, s)
#define ERR(s) do{ fprintf(stderr, "ERR "); MSG(s); exit(1); }while(0)

int bk_buf = -1;

int
rd(void)
{
	int v;

	if((v = bk_buf) < 0) return getchar();
	bk_buf = -1;
	return v;
}

void
bk(int v)
{
	if(bk_buf >= 0) ERR("give up");
	bk_buf = v;
}

void
rd_str(int n, char *s)
{
	int i;

	for(i=0; i<n; i++) s[i] = rd();
	s[i] = '\0';
}

int
rd_str_chk(int n, char *s)
{
	char buf[256];

	rd_str(n, buf);
	return strcmp(buf, s) == 0;
}

int
rd_int(int n) /* big endian */
{
	int i, v;

	v = 0;
	for(i=0; i<n; i++) v = (v << 8) | rd();
	return v;
}

int
rd_delta(void)
{
	int v, c;

	v = 0;
	do{
		if((c = rd()) == EOF) return EOF;
		v = (v << 7) | (c & 0x7f);
	}while(c & 0x80);
	return v;
}


struct lpf_rec{
	double freq, Q;
};

struct lpf_stat_rec{
	int idx;
	double in[4], out[4];
	double a0, a1, a2, b0, b1, b2, div_a0;
};

void
lpf_update(struct lpf_rec *lpf, struct lpf_stat_rec *stat, int smp_freq)
{
	double w0, alpha;

	w0 = 2 * M_PI * lpf->freq / smp_freq;
	alpha = sin(w0) / (2 * lpf->Q);
	stat->b1 = 1 - cos(w0);
	stat->b0 = stat->b2 = stat->b1 * 0.5;
	stat->a0 = 1 + alpha;
	stat->a1 = -2 * cos(w0);
	stat->a2 = 1 - alpha;
	if(stat->a0 != 0) stat->div_a0 = 1 / stat->a0;
}

void
lpf_init(struct lpf_rec *lpf, struct lpf_stat_rec *stat, int smp_freq)
{
	int i;

	for(i=0; i<4; i++) stat->in[i] = stat->out[i] = 0;
	stat->idx = 0;

	lpf_update(lpf, stat, smp_freq);
}

double
lpf_out(struct lpf_stat_rec *stat, double in)
{
	double *out_p;
	int i_1, i_2;

	stat->in[stat->idx] = in;
	out_p = &stat->out[stat->idx];

	if(stat->a0 != 0){
		i_1 = (stat->idx + 4 - 1) & 3;
		i_2 = (i_1 + 4 - 1) & 3;
		*out_p = (stat->b0 * in
			+ stat->b1 * stat->in[i_1]
			+ stat->b2 * stat->in[i_2]
			- stat->a1 * stat->out[i_1]
			- stat->a2 * stat->out[i_2] ) * stat->div_a0;
	}else{
		*out_p = 0;
	}
	stat->idx = (stat->idx + 1) & 3;
	return *out_p;
}


#define NOTE_BUF_N	256

struct vco_stat_rec{
	double cycle, freq, sec;
};

void
vco_stat_update(struct vco_stat_rec *stat, double freq, double sec)
{
	stat->cycle += freq * (sec - stat->sec);	
	stat->freq = freq;
	stat->sec = sec;
}

#define DELAY_BUF_N	(44100 * 5 / 10) /* max 0.5 sec */

struct note_rec{
	int ch;
	int note;
	int onoff;
	double on_sec;
	double off_sec;
	int velo;
	struct vco_stat_rec vco_stat[2];
	double off_v;
	struct lpf_stat_rec lpf_stat;
	int fst_smp_cnt;
	double delay_buf[ DELAY_BUF_N ];
} note_buf[NOTE_BUF_N];

int
note_buf_is_free(int i)
{
	return note_buf[i].ch < 0;
}

void
note_buf_free(int i)
{
	note_buf[i].ch = -1;
}

void
note_buf_init(void)
{
	int i;

	for(i=0; i<NOTE_BUF_N; i++) note_buf_free(i);
}

int
note_buf_search(int ch, int note, int onoff)
{
	int i;

	for(i=0; i<NOTE_BUF_N; i++) {
		if( (ch < 0 && note_buf[i].ch < 0) ||
		    (note_buf[i].ch == ch &&
		     note_buf[i].note == note &&
		     note_buf[i].onoff == onoff) ) return i;
	}
	return -1;
}

int
header(void)
{
	int v;

	if(!rd_str_chk(4, "MThd")) ERR("header id");
	if(rd_int(4) != 6) ERR("header size");
	if(rd_int(2) != 0) ERR("header format type");
	if(rd_int(2) != 1) ERR("header track num");
	if((v = rd_int(2)) & 0x8000) ERR("header division");
	return v; /* div4 */
}

double
note_to_freq(int note)
{
	return 440 * pow(2, (note - 69) / 12.0);
}

int
opt_idx(char *key, int ac, char **av)
{
	int i;

	for(i=1; i<ac; i++) if(strcmp(av[i], key) == 0) return i;
	return -1;
}

char *
opt_str(char *key, int ac, char **av, char *def)
{
	int i;

	i = opt_idx(key, ac, av);
	if(i < 0 || i+1 >= ac) return def;
	return av[i+1];
}

int
opt_int(char *key, int ac, char **av, int def)
{
	char *s;

	if((s = opt_str(key, ac, av, NULL)) == NULL) return def;
	return strtol(s, NULL, 0);
}

struct out_rec{
	int smp_freq, smp_cnt;
	int bit_len;
	int sign;
	int ch_num;
	FILE *fp;

	int base;
	int amp;
	int iv_min;
	int iv_max;
	double smp_t, sec;
};

void
out_init(struct out_rec *ot, int ac, char **av)
{
	char cmd[1024], *fn;

	ot->smp_freq = opt_int("-r", ac, av, 44100);
	ot->smp_cnt = 0;
	ot->bit_len = opt_int("-b", ac, av, 16);
	if(ot->bit_len != 8 && ot->bit_len != 16) ERR("bit_len");
	ot->sign = (opt_idx("-u", ac, av) < 0);
	ot->ch_num = opt_int("-c", ac, av, 2);

	ot->fp = stdout;
	cmd[0] = '\0';
	fn = "";
	if(opt_idx("-play", ac, av) >= 0){
		strcat(cmd, "play");
	}else if(opt_idx("-sox", ac, av) >= 0){
		strcat(cmd, "sox");
		fn = opt_str("-sox", ac, av, "-d");
	}
	if(cmd[0]){
		sprintf(cmd + strlen(cmd), " -t raw -r %d -b %d %s -c %d - %s",
			ot->smp_freq, ot->bit_len,
			ot->sign ? "-s" : "-u",
			ot->ch_num, fn);
		if((ot->fp = popen(cmd, "w")) == NULL) ERR("popen");
	}
	ot->amp = ot->bit_len == 8 ? 127 : 32767;
	ot->base = ot->sign ? 0 : ot->amp + 1;
	ot->iv_min = ot->base - (ot->amp + 1);
	ot->iv_max = ot->base + ot->amp;

	ot->smp_t = 1.0 / ot->smp_freq;
}

void
out_do(struct out_rec *ot, double v)
{
	int iv;

	iv = ot->base + (int)(v *ot->amp);
	if(iv > ot->iv_max) iv = ot->iv_max;
	if(iv < ot->iv_min) iv = ot->iv_min;
	switch(ot->bit_len){
	case 8:
		fputc(iv, ot->fp);
		break;
	case 16:
		fputc(iv & 0xff, ot->fp);
		fputc((iv >> 8) & 0xff, ot->fp);
		break;
	}
}

#define OFF		0
#define ON		1

#define WAVE_SIN	0
#define WAVE_SAW	1
#define WAVE_SQUARE	2
#define WAVE_NOISE	3

double
wave_out(int wave, double cycle)
{
	cycle -= (int)cycle;

	switch(wave){
	case WAVE_SIN:
		return sin(2 * M_PI * cycle);
	case WAVE_SAW:
		cycle *= 2;
		if(cycle > 1) cycle -= 2;
		return cycle;
	case WAVE_SQUARE:
		return cycle < 0.5 ? 1 : -1;
	case WAVE_NOISE:
		return ((double)rand() / RAND_MAX) * 2 - 1;
	}
	return 0;
}

struct vco_rec{
	int wave1, wave2;
	int tune; /* for vco2 */
	double mix;
	int ring;
};

struct modu_rec{
	int pitch1, pitch2, filter;
};

struct lfo_rec{
	int wave;
	double freq, delay;
};

struct env_rec{
	double attack;	/* sec */
	double decay;	/* sec */
	double sustain;	/* 0..1 */
	double release;	/* sec */
};

struct delay_rec{
	int onoff;
	double sec, gain;
};

struct tone_rec{
	struct vco_rec vco;
	struct lpf_rec lpf;
	struct env_rec env;
	double level;
	struct modu_rec lfo_modu;
	struct lfo_rec lfo;
	struct modu_rec env_modu;
	struct delay_rec delay;
	int chorus;
} tone_inf[] = {
	{	/* strings */
		{ WAVE_SAW, WAVE_SAW, 12, 0.5, OFF },
		{ 3000, 1.5 },
		{ 0.15, 0.5, 0.8, 0.5 },
		1.0,
		{ OFF, 12, OFF }, { WAVE_SIN, 4, 0.3 },
		{ OFF, OFF, OFF },
		{ OFF, }, ON,
	},{	/* bass */
		{ WAVE_SAW, WAVE_SQUARE, OFF, 0.5, OFF },
		{ 1000, 1.5} ,
		{ 0.05, 0.2, 0.4, 0.2 },
		1.0,
		{ OFF, 60, OFF }, { WAVE_SIN, 1.5, 0.2 },
		{ OFF, OFF, OFF },
		{ OFF, }, ON,
	},{	/* lead */
		{ WAVE_SQUARE, WAVE_SQUARE, 10, 0.5, OFF },
		{ 2000, 4 },
		{ 0.01, 0.2, 0.8, 0.3 },
		1.0,
		{ OFF, 1, 5 }, { WAVE_SIN, 4, 0.3 },
		{ OFF, OFF, OFF },
		{ ON, 0.2, 0.4}, OFF,
	},{	/* SIN */
		{ WAVE_SIN, WAVE_SIN, OFF, 0, OFF },
		{ 20000, 0.8 },
		{ 0, 0.3, 0.2, 0.3 },
		1.4,
		{ 25, OFF, OFF }, { WAVE_SIN, 6, 0.3 },
		{ OFF, OFF, OFF },
		{ OFF, }, OFF,
	}
}, drum_tone_inf[] = {
	{	/* bass */
		{ WAVE_SIN, WAVE_NOISE, OFF, 0.4, OFF },
		{ 400, 1 },
		{ 0.01, 0.18, 0, 0.18 },
		9.0,
		{ 100, OFF, 30 }, { WAVE_NOISE, 0, 0.5 },
		{ OFF, OFF, OFF },
		{ OFF, }, OFF,
	},{	/* snare */
		{ WAVE_SQUARE, WAVE_NOISE, OFF, 0.8, ON },
		{ 1500, 1.7 },
		{ 0, 0.4, 0.3, 0.4 },
		5,
		{ OFF, OFF, OFF, }, {},
		{ OFF, OFF, OFF },
		{ OFF, }, OFF,
	},{	/* tom */
		{ WAVE_SQUARE, WAVE_NOISE, OFF, 0.5, ON },
		{ 800, 2.5 },
		{ 0, 0.03, 0.1, 0.4 },
		5,
		{ OFF, OFF, OFF, }, {},
		{ 200, OFF, 1200 },
		{ OFF, }, OFF,
	},{	/* hi-hat close */
		{ WAVE_SQUARE, WAVE_SQUARE, 700, 0.9, ON },
		{ 16000, 2 },
		{ 0, 0.15, 0, 0.15 },
		0.6,
		{ OFF, OFF, OFF, }, {},
		{ OFF, OFF, OFF },
		{ OFF, }, OFF,
	},{	/* hi-hat open */
		{ WAVE_SQUARE, WAVE_SQUARE, 700, 0.9, ON },
		{ 16000, 2 },
		{ 0, 0, 1, 0.35 },
		0.6,
		{ OFF, OFF, OFF, }, {},
		{ OFF, OFF, OFF },
		{ OFF, }, OFF,
	},{	/* cymbal */
		{ WAVE_NOISE, WAVE_SQUARE, OFF, 0.8, ON },
		{ 4000, 2 },
		{ 0, 0.01, 0.2, 0.8 },
		9,
		{ OFF, OFF, OFF }, {},
		{ OFF, OFF, 600 },
		{ OFF, }, OFF,
	},{	/* side stick */
		{ WAVE_NOISE, WAVE_SQUARE, OFF, 0.2, OFF },
		{ 1700, 3 },
		{ 0, 0.012, 0.1, 0.7 },
		10,
		{ OFF, OFF, OFF }, {},
		{ OFF, OFF, OFF },
		{ OFF, }, OFF,
	}
};

struct tone_rec *
tone_get(int prog, int note, double *ret_freq)
{
	int idx;
	struct tone_rec *ret;

	idx = -1;
	if(prog <= 0){ /* drum part */
		switch(note){
		case 36: /* bass drum1 */
			idx = 0;
			note = 28;
			break;
		case 37: /* side stick */
			idx = 6;
			note = 110;
			break;
		case 40: /* electric snare */
			idx = 1;
			note = 69;
			break;
		case 41: /* low floor tom */
			idx = 2;
			note = 50;
			break;
		case 42: /* closed hi-hat */
			idx = 3;
			note = 115 + 8;
			break;
		case 46: /* open hi-hat */
			idx = 4;
			note = 115 + 8;
			break;
		case 49: /* crash cymbal 1 */
		case 57: /* crash cymbal 2 */
			idx = 5;
			note = 100;
			break;
		}
		ret = idx < 0 ? NULL : &drum_tone_inf[idx];
	}else{
		switch(prog){
		case 48: /* timpani */
		case 50: /* strings ensamble 2 */
			idx = 0;
			break;
		case 35: /* electric bass (pick) */
			idx = 1;
			break;
		case 79: /* whistle */
		case 81: /* lead 1 (square) */
		case 87: /* lead 7 (fifths) */
			idx = 2;
			break;
		case 24: /* tango accordion */
		case 67: /* tenor sax */
			idx = 3;
			break;
		}
		ret = idx < 0 ? NULL : &tone_inf[idx];
	}
	if(ret_freq) *ret_freq = note_to_freq(note);
	return ret;
}

#define MIDI_CH_N	16
struct ch_rec{
	int vol;
	int pan;
	int bend;
	int rpn;
	int bend_range;
	int prog;
} ch_inf[ MIDI_CH_N ];

#define CH_PROG(ch)	( (ch) == 9 ? 0 : ch_inf[ch].prog )

double
env_out(struct note_rec *nt, double sec)
{
	struct tone_rec *tn;
	struct env_rec *e;
	double v;

	if((tn = tone_get(CH_PROG(nt->ch), nt->note, NULL)) == NULL) return 0;
	e = &tn->env;
	if(nt->onoff){
		sec -= nt->on_sec;
		if(sec < e->attack){
			v = sec / e->attack;
			return log10(1 + v * 9);
		}
		sec -= e->attack;
		if(sec < e->decay){
			v = sec / e->decay;
			v = log10(1 + v * 9);
			return 1 - v * (1 - e->sustain);
		}
		return e->sustain;
	}
	sec -= nt->off_sec;
	if(sec < e->release){
		v = sec / e->release;
		v = log10(1 + v * 9);
		return (1 - v) * nt->off_v;
	}
	return 0;
}

void
modu_out(double v, struct modu_rec *modu, double *ret_arr)
{
	if(modu->pitch1) ret_arr[0] += v * modu->pitch1 / 100.0 / 12;
	if(modu->pitch2) ret_arr[1] += v * modu->pitch2 / 100.0 / 12;
	if(modu->filter) ret_arr[2] += v * modu->filter / 100.0 / 12;
}

double
lfo_out(struct lfo_rec *lfo, struct modu_rec *modu, double sec, double on_sec)
{
	double dsec;

	if(!(modu->pitch1 || modu->pitch2 || modu->filter)) return 0;
	if((dsec = sec - on_sec - lfo->delay) <= 0) return 0;
	return wave_out(lfo->wave, lfo->freq * dsec);
}

double
vco_out(int wave, struct vco_stat_rec *stat, double freq, double sec, double modu_v)
{
	if(modu_v != 0) freq *= pow(2, modu_v /*/ 12*/);
	vco_stat_update(stat, freq, sec);
	return wave_out(wave, stat->cycle);
}

double
vcf_out(struct lpf_rec *lpf, struct lpf_stat_rec *lpf_stat, struct out_rec *ot, double modu_v, double v)
{
	struct lpf_rec lpf_tmp;

	if(lpf_stat->idx < 0) lpf_init(lpf, lpf_stat, ot->smp_freq);
	if(modu_v != 0){
		lpf_tmp = *lpf;
		lpf_tmp.freq *= pow(2, modu_v /*/ 12*/);
		lpf_update(&lpf_tmp, lpf_stat, ot->smp_freq);
	}
	return lpf_out(lpf_stat, v);
}

void
delay_buf_set(struct out_rec *ot, struct note_rec *nt, double v)
{
	nt->delay_buf[ (ot->smp_cnt - nt->fst_smp_cnt) % DELAY_BUF_N ] = v;
}

double
delay_buf_lookup(struct out_rec *ot, struct note_rec *nt, double sec)
{
	double cycle, v1, v2;
	int idx;

	cycle = ot->smp_freq * sec - nt->fst_smp_cnt;
	idx = (int)cycle;
	cycle -= idx;
	v1 = nt->delay_buf[ idx % DELAY_BUF_N ];
	v2 = nt->delay_buf[ (idx + 1 ) % DELAY_BUF_N ];
	return v1 * (1 - cycle) + v2 * cycle;
}

double
delay_out(struct out_rec *ot, struct note_rec *nt, struct delay_rec *delay)
{
	if(ot->sec - nt->on_sec < delay->sec) return 0;
	return delay_buf_lookup(ot, nt, ot->sec - delay->sec) * delay->gain;
}

double
chorus_out(struct out_rec *ot, struct note_rec *nt)
{
	double dsec, bak_sec;

	dsec = ot->sec - nt->on_sec;
	bak_sec = 0.01 + 0.001 * sin(2 * M_PI * 0.8 * dsec);
	if(dsec < bak_sec) return 0;
	return delay_buf_lookup(ot, nt, ot->sec - bak_sec);
}

int
delay_fin_chk(struct note_rec *nt, struct out_rec *ot)
{
	int i, n, j;
	double note_freq, v;

	note_freq = nt->vco_stat[0].freq;
	n = ot->smp_freq / note_freq;
	for(i=0; i<n; i++){
		j = (ot->smp_cnt - nt->fst_smp_cnt - i + DELAY_BUF_N) % DELAY_BUF_N;
		v = nt->delay_buf[j];
		if(v < 0) v = -v;
		if(v > 0.0001) break;
	}
	return i >= n;
}

int
note_out(struct out_rec *ot, struct note_rec *nt, double *vl, double *vr)
{
	double v, v1, v2, freq, pan, lfo_v, env_v, modu_v[3];
	int nch;
	struct tone_rec *tn;
	struct vco_rec *vco;

	nch = nt->ch;
	tn = tone_get(CH_PROG(nch), nt->note, &freq);
	if(tn == NULL) return 0;

	if(nt->fst_smp_cnt < 0) nt->fst_smp_cnt = ot->smp_cnt;

	if(ch_inf[nch].bend != 0) freq *= pow(2, ch_inf[nch].bend / 8192.0 * ch_inf[nch].bend_range / 12);

	lfo_v = lfo_out(&tn->lfo, &tn->lfo_modu, ot->sec, nt->on_sec);
	env_v = env_out(nt, ot->sec);

	modu_v[0] = modu_v[1] = modu_v[2] = 0;
	modu_out(lfo_v, &tn->lfo_modu, modu_v);
	modu_out(env_v, &tn->env_modu, modu_v);

	vco = &tn->vco;
	v1 = vco_out(vco->wave1, &nt->vco_stat[0], freq, ot->sec, modu_v[0]);

	freq *= pow(2, (vco->tune / 100.0) / 12);
	v2 = vco_out(vco->wave2, &nt->vco_stat[1], freq, ot->sec, modu_v[1]);
	if(vco->ring){
		v = v1 * v2;
		v1 = (v1 + v2) / 2;
		v2 = v;
	}
	v = v1 * (1 - vco->mix) + v2 * vco->mix;

	v = vcf_out(&tn->lpf, &nt->lpf_stat, ot, modu_v[2], v);

	v *= env_v * tn->level;

	if(tn->delay.onoff) v += delay_out(ot, nt, &tn->delay);
	delay_buf_set(ot, nt, v);
	if(tn->chorus) v += chorus_out(ot, nt);

	v *= nt->velo / 127.0;
	v *= ch_inf[nch].vol / (double)((1<<14)-1);
	if(ot->ch_num == 1){
		*vl += v;
	}else{
	pan = ch_inf[nch].pan / (double)(1<<14);
		*vl += (1 - pan) * v;
		*vr += pan * v;
	}
	return (nt->onoff == 0 && ot->sec - nt->off_sec >= tn->env.release &&
		(!tn->delay.onoff || delay_fin_chk(nt, ot)));
}

void
data_out(struct out_rec *ot, double evt_sec)
{
	double vl, vr;
	int i;
	struct note_rec *nt;

	while((ot->sec = ot->smp_t * ot->smp_cnt) < evt_sec){
		vl = vr = 0;
		for(i=0; i<NOTE_BUF_N; i++){
			if(note_buf_is_free(i)) continue;
			nt = &note_buf[i];
			if(note_out(ot, nt, &vl, &vr)) note_buf_free(i);
		}
		out_do(ot, vl / 16);
		if(ot->ch_num > 1) out_do(ot, vr / 16);
		ot->smp_cnt++;
	}
}

void
note_onoff(int onoff, double evt_sec, int ch, int note, int velo)
{
	int i, j;
	struct vco_stat_rec *stat;

	if(onoff){
		if((i = note_buf_search(-1, -1, -1)) < 0){
			MSG("note_buf full");
			return;
		}
		note_buf[i].note = note;
		note_buf[i].ch = ch;
		note_buf[i].onoff = 1;
		note_buf[i].on_sec = evt_sec;
		note_buf[i].velo = velo;
		for(j=0; j<2; j++){
			stat = &note_buf[i].vco_stat[j];
			stat->cycle = 0;
			stat->sec = evt_sec;
		}
		note_buf[i].lpf_stat.idx = -1;
		note_buf[i].fst_smp_cnt = -1;
	}else{
		if((i = note_buf_search(ch, note, 1)) < 0) return;
		note_buf[i].off_v = env_out(&note_buf[i], evt_sec);
		note_buf[i].onoff = 0;
		note_buf[i].off_sec = evt_sec;
	}
}

void
msb_set(int *vp, int v)
{
	*vp &= ~(127<<7);
	*vp |= v<<7;
}

void
lsb_set(int *vp, int v)
{
	*vp &= ~127;
	*vp |= v;
}

void
bend_note_update(int ch, double sec)
{
	int i, j;
	struct note_rec *nt;
	struct vco_stat_rec *stat;

	for(i=0; i<NOTE_BUF_N; i++){
		if(note_buf_is_free(i)) continue;
		nt = &note_buf[i];
		if(nt->ch != ch) continue;
		for(j=0; j<2; j++){
			stat = &nt->vco_stat[j];
			vco_stat_update(stat, stat->freq, sec);
		}
	}
}

int
main(int ac, char **av)
{
	int div4, delta_sum;
	int i, n, v, hi, low, note, velo;
	int ch, type;
	double sec;
	struct out_rec otr;
	int tempo, tempo_delta_sum;
	double tempo_sec;

	out_init(&otr, ac, av);
	note_buf_init();
	for(i=0; i<MIDI_CH_N; i++){
		ch_inf[i].vol = 0;
		ch_inf[i].pan = 1<<(14-1);
		ch_inf[i].bend = 0;
		ch_inf[i].rpn = 0;
		ch_inf[i].bend_range = 2;
		ch_inf[i].prog =-1;
	}
	tempo = 500000;
	tempo_delta_sum = 0;
	tempo_sec = 0;

	div4 = header();

	if(!rd_str_chk(4, "MTrk")) ERR("track id");
	v = rd_int(4); /* skip */

	hi = low = 0;
	delta_sum = 0;
	while((v = rd_delta()) != EOF){
		delta_sum += v;
		sec = tempo_sec + (double)(delta_sum - tempo_delta_sum) / div4 * tempo * 0.000001;
		
		if((v = rd()) & 0x80){
			hi = (v >> 4) & 0xf;
			low  = v & 0xf;
		}else bk(v);

		data_out(&otr, sec);

		ch = low;
		switch(hi){
		case 8:
		case 9:
			note = rd();
			velo = rd();
			note_onoff(hi == 9, sec, ch, note, velo);
			break;
		case 0xb: /* control change */
			type = rd();
			v = rd();
			switch(type){
			case 7: /* channel volume msb */
				msb_set(&ch_inf[ch].vol, v);
				break;
			case 39: /* channel volume lsb */
				lsb_set(&ch_inf[ch].vol, v);
				break;
			case 10: /* pan msb */
				msb_set(&ch_inf[ch].pan, v);
				break;
			case 42: /* pan lsb */
				lsb_set(&ch_inf[ch].pan, v);
				break;
			case 100: /* rpn lsb */
				lsb_set(&ch_inf[ch].rpn, v);
				break;
			case 101: /* rpn msb */
				msb_set(&ch_inf[ch].rpn, v);
				break;
			case 6: /* data entry msb */
				switch(ch_inf[ch].rpn){
				case 0: /* pitch bend range */
					ch_inf[ch].bend_range = v;
					break;
				}
				break;
			}
			break;
		case 0xa:
			rd();
			rd();
			break;
		case 0xe: /* pitch wheel change */
			bend_note_update(ch, sec);
			v = rd();
			v |= rd() << 7;
			ch_inf[ch].bend = v - 8192;
			break;
		case 0xc: /* program number */
			v = rd();
			ch_inf[ch].prog = v;
			break;
		case 0xd:
			rd();
			break;
		case 0xf:
			type = rd();
			switch(low){
			case 0:
				while(rd() != 0xf7);
				break;
			case 1:
			case 3:
				rd();
				break;
			case 2:
				rd();
				rd();
				break;
			case 0xf: /* meta */
				n = rd();
				switch(type){
				case 0x51: /* set tempo */
					v = rd_int(n);
					tempo = v;
					tempo_delta_sum = delta_sum;
					tempo_sec = sec;
					break;
				default:
					for(i=0; i<n; i++) rd();
					break;
				}
				break;
			default:
				break;
			}
			break;
		}
	}
	if(otr.fp != stdout) pclose(otr.fp);
	return 0;
}

/* EOF */


#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <math.h>

#define MSG(s) fprintf(stderr, "%s() %s L%d : %s\n", __func__, __FILE__, __LINE__, s)
#define ERR(s) do{ fprintf(stderr, "ERR "); MSG(s); exit(1); }while(0)

int bk_buf = -1;

int
rd(void)
{
	int v;

	if((v = bk_buf) < 0) return getchar();
	bk_buf = -1;
	return v;
}

void
bk(int v)
{
	if(bk_buf >= 0) ERR("give up");
	bk_buf = v;
}

void
rd_str(int n, char *s)
{
	int i;

	for(i=0; i<n; i++) s[i] = rd();
	s[i] = '\0';
}

int
rd_str_chk(int n, char *s)
{
	char buf[256];

	rd_str(n, buf);
	return strcmp(buf, s) == 0;
}

int
rd_int(int n) /* big endian */
{
	int i, v;

	v = 0;
	for(i=0; i<n; i++) v = (v << 8) | rd();
	return v;
}

int
rd_delta(void)
{
	int v, c;

	v = 0;
	do{
		if((c = rd()) == EOF) return EOF;
		v = (v << 7) | (c & 0x7f);
	}while(c & 0x80);
	return v;
}


struct lpf_rec{
	double freq, Q;
};

struct lpf_stat_rec{
	int idx;
	double in[4], out[4];
	double a0, a1, a2, b0, b1, b2, div_a0;
};

void
lpf_update(struct lpf_rec *lpf, struct lpf_stat_rec *stat, int smp_freq)
{
	double w0, alpha;

	w0 = 2 * M_PI * lpf->freq / smp_freq;
	alpha = sin(w0) / (2 * lpf->Q);
	stat->b1 = 1 - cos(w0);
	stat->b0 = stat->b2 = stat->b1 * 0.5;
	stat->a0 = 1 + alpha;
	stat->a1 = -2 * cos(w0);
	stat->a2 = 1 - alpha;
	if(stat->a0 != 0) stat->div_a0 = 1 / stat->a0;
}

void
lpf_init(struct lpf_rec *lpf, struct lpf_stat_rec *stat, int smp_freq)
{
	int i;

	for(i=0; i<4; i++) stat->in[i] = stat->out[i] = 0;
	stat->idx = 0;

	lpf_update(lpf, stat, smp_freq);
}

double
lpf_out(struct lpf_stat_rec *stat, double in)
{
	double *out_p;
	int i_1, i_2;

	stat->in[stat->idx] = in;
	out_p = &stat->out[stat->idx];

	if(stat->a0 != 0){
		i_1 = (stat->idx + 4 - 1) & 3;
		i_2 = (i_1 + 4 - 1) & 3;
		*out_p = (stat->b0 * in
			+ stat->b1 * stat->in[i_1]
			+ stat->b2 * stat->in[i_2]
			- stat->a1 * stat->out[i_1]
			- stat->a2 * stat->out[i_2] ) * stat->div_a0;
	}else{
		*out_p = 0;
	}
	stat->idx = (stat->idx + 1) & 3;
	return *out_p;
}


#define NOTE_BUF_N	256

struct vco_stat_rec{
	double cycle, freq, sec;
};

void
vco_stat_update(struct vco_stat_rec *stat, double freq, double sec)
{
	stat->cycle += freq * (sec - stat->sec);	
	stat->freq = freq;
	stat->sec = sec;
}

#define DELAY_BUF_N	(44100 * 5 / 10) /* max 0.5 sec */
// エフェクタのディレイ用のバッファ長 (サンプル数)
// サンプリング周波数が44100 Hzとして 0.5秒分

struct note_rec{
	int ch;
	int note;
	int onoff;
	double on_sec;
	double off_sec;
	int velo;
	struct vco_stat_rec vco_stat[2];
	double off_v;
	struct lpf_stat_rec lpf_stat;
	int fst_smp_cnt;
	// 鍵盤オンから最初にデータ出力したときの
	// サンプリングカウントの記録を追加
	
	double delay_buf[ DELAY_BUF_N ];
	//  エフェクタのディレイ用のバッファを追加
	
} note_buf[NOTE_BUF_N];

int
note_buf_is_free(int i)
{
	return note_buf[i].ch < 0;
}

void
note_buf_free(int i)
{
	note_buf[i].ch = -1;
}

void
note_buf_init(void)
{
	int i;

	for(i=0; i<NOTE_BUF_N; i++) note_buf_free(i);
}

int
note_buf_search(int ch, int note, int onoff)
{
	int i;

	for(i=0; i<NOTE_BUF_N; i++) {
		if( (ch < 0 && note_buf[i].ch < 0) ||
		    (note_buf[i].ch == ch &&
		     note_buf[i].note == note &&
		     note_buf[i].onoff == onoff) ) return i;
	}
	return -1;
}

int
header(void)
{
	int v;

	if(!rd_str_chk(4, "MThd")) ERR("header id");
	if(rd_int(4) != 6) ERR("header size");
	if(rd_int(2) != 0) ERR("header format type");
	if(rd_int(2) != 1) ERR("header track num");
	if((v = rd_int(2)) & 0x8000) ERR("header division");
	return v; /* div4 */
}

double
note_to_freq(int note)
{
	return 440 * pow(2, (note - 69) / 12.0);
}

int
opt_idx(char *key, int ac, char **av)
{
	int i;

	for(i=1; i<ac; i++) if(strcmp(av[i], key) == 0) return i;
	return -1;
}

char *
opt_str(char *key, int ac, char **av, char *def)
{
	int i;

	i = opt_idx(key, ac, av);
	if(i < 0 || i+1 >= ac) return def;
	return av[i+1];
}

int
opt_int(char *key, int ac, char **av, int def)
{
	char *s;

	if((s = opt_str(key, ac, av, NULL)) == NULL) return def;
	return strtol(s, NULL, 0);
}

struct out_rec{
	int smp_freq, smp_cnt;
	int bit_len;
	int sign;
	int ch_num;
	FILE *fp;

	int base;
	int amp;
	int iv_min;
	int iv_max;
	double smp_t, sec;
};

void
out_init(struct out_rec *ot, int ac, char **av)
{
	char cmd[1024], *fn;

	ot->smp_freq = opt_int("-r", ac, av, 44100);
	ot->smp_cnt = 0;
	ot->bit_len = opt_int("-b", ac, av, 16);
	if(ot->bit_len != 8 && ot->bit_len != 16) ERR("bit_len");
	ot->sign = (opt_idx("-u", ac, av) < 0);
	ot->ch_num = opt_int("-c", ac, av, 2);

	ot->fp = stdout;
	cmd[0] = '\0';
	fn = "";
	if(opt_idx("-play", ac, av) >= 0){
		strcat(cmd, "play");
	}else if(opt_idx("-sox", ac, av) >= 0){
		strcat(cmd, "sox");
		fn = opt_str("-sox", ac, av, "-d");
	}
	if(cmd[0]){
		sprintf(cmd + strlen(cmd), " -t raw -r %d -b %d %s -c %d - %s",
			ot->smp_freq, ot->bit_len,
			ot->sign ? "-s" : "-u",
			ot->ch_num, fn);
		if((ot->fp = popen(cmd, "w")) == NULL) ERR("popen");
	}
	ot->amp = ot->bit_len == 8 ? 127 : 32767;
	ot->base = ot->sign ? 0 : ot->amp + 1;
	ot->iv_min = ot->base - (ot->amp + 1);
	ot->iv_max = ot->base + ot->amp;

	ot->smp_t = 1.0 / ot->smp_freq;
}

void
out_do(struct out_rec *ot, double v)
{
	int iv;

	iv = ot->base + (int)(v *ot->amp);
	if(iv > ot->iv_max) iv = ot->iv_max;
	if(iv < ot->iv_min) iv = ot->iv_min;
	switch(ot->bit_len){
	case 8:
		fputc(iv, ot->fp);
		break;
	case 16:
		fputc(iv & 0xff, ot->fp);
		fputc((iv >> 8) & 0xff, ot->fp);
		break;
	}
}

#define OFF		0
#define ON		1

#define WAVE_SIN	0
#define WAVE_SAW	1
#define WAVE_SQUARE	2
#define WAVE_NOISE	3

double
wave_out(int wave, double cycle)
{
	cycle -= (int)cycle;

	switch(wave){
	case WAVE_SIN:
		return sin(2 * M_PI * cycle);
	case WAVE_SAW:
		cycle *= 2;
		if(cycle > 1) cycle -= 2;
		return cycle;
	case WAVE_SQUARE:
		return cycle < 0.5 ? 1 : -1;
	case WAVE_NOISE:
		return ((double)rand() / RAND_MAX) * 2 - 1;
	}
	return 0;
}

struct vco_rec{
	int wave1, wave2;
	int tune; /* for vco2 */
	double mix;
	int ring;
};

struct modu_rec{
	int pitch1, pitch2, filter;
};

struct lfo_rec{
	int wave;
	double freq, delay;
};

struct env_rec{
	double attack;	/* sec */
	double decay;	/* sec */
	double sustain;	/* 0..1 */
	double release;	/* sec */
};

struct delay_rec{
	int onoff;
	double sec, gain;
};
// エフェクタのディレイ用の構造体の定義を追加
//
// onoff は、ディレイ有効/無効のフラグ
// sec は、遅らせる時間(秒)
// gain は、遅らせた音を足し込むときの係数

struct tone_rec{
	struct vco_rec vco;
	struct lpf_rec lpf;
	struct env_rec env;
	double level;
	struct modu_rec lfo_modu;
	struct lfo_rec lfo;
	struct modu_rec env_modu;
	struct delay_rec delay;
	// エフェクタのディレイ用のパラメータを追加
	
	int chorus;
	// エフェクタのコーラスのON/OFFパラメータを追加
	
} tone_inf[] = {
	{	/* strings */
		{ WAVE_SAW, WAVE_SAW, 12, 0.5, OFF },
		{ 3000, 1.5 },
		{ 0.15, 0.5, 0.8, 0.5 },
		1.0,
		{ OFF, 12, OFF }, { WAVE_SIN, 4, 0.3 },
		{ OFF, OFF, OFF },
		{ OFF, }, ON,
	},{	/* bass */
		{ WAVE_SAW, WAVE_SQUARE, OFF, 0.5, OFF },
		{ 1000, 1.5} ,
		{ 0.05, 0.2, 0.4, 0.2 },
		1.0,
		{ OFF, 60, OFF }, { WAVE_SIN, 1.5, 0.2 },
		{ OFF, OFF, OFF },
		{ OFF, }, ON,
	},{	/* lead */
		{ WAVE_SQUARE, WAVE_SQUARE, 10, 0.5, OFF },
		{ 2000, 4 },
		{ 0.01, 0.2, 0.8, 0.3 },
		1.0,
		{ OFF, 1, 5 }, { WAVE_SIN, 4, 0.3 },
		{ OFF, OFF, OFF },
		{ ON, 0.2, 0.4}, OFF,
	},{	/* SIN */
		{ WAVE_SIN, WAVE_SIN, OFF, 0, OFF },
		{ 20000, 0.8 },
		{ 0, 0.3, 0.2, 0.3 },
		1.4,
		{ 25, OFF, OFF }, { WAVE_SIN, 6, 0.3 },
		{ OFF, OFF, OFF },
		{ OFF, }, OFF,
	}
}, drum_tone_inf[] = {
	{	/* bass */
		{ WAVE_SIN, WAVE_NOISE, OFF, 0.4, OFF },
		{ 400, 1 },
		{ 0.01, 0.18, 0, 0.18 },
		9.0,
		{ 100, OFF, 30 }, { WAVE_NOISE, 0, 0.5 },
		{ OFF, OFF, OFF },
		{ OFF, }, OFF,
	},{	/* snare */
		{ WAVE_SQUARE, WAVE_NOISE, OFF, 0.8, ON },
		{ 1500, 1.7 },
		{ 0, 0.4, 0.3, 0.4 },
		5,
		{ OFF, OFF, OFF, }, {},
		{ OFF, OFF, OFF },
		{ OFF, }, OFF,
	},{	/* tom */
		{ WAVE_SQUARE, WAVE_NOISE, OFF, 0.5, ON },
		{ 800, 2.5 },
		{ 0, 0.03, 0.1, 0.4 },
		5,
		{ OFF, OFF, OFF, }, {},
		{ 200, OFF, 1200 },
		{ OFF, }, OFF,
	},{	/* hi-hat close */
		{ WAVE_SQUARE, WAVE_SQUARE, 700, 0.9, ON },
		{ 16000, 2 },
		{ 0, 0.15, 0, 0.15 },
		0.6,
		{ OFF, OFF, OFF, }, {},
		{ OFF, OFF, OFF },
		{ OFF, }, OFF,
	},{	/* hi-hat open */
		{ WAVE_SQUARE, WAVE_SQUARE, 700, 0.9, ON },
		{ 16000, 2 },
		{ 0, 0, 1, 0.35 },
		0.6,
		{ OFF, OFF, OFF, }, {},
		{ OFF, OFF, OFF },
		{ OFF, }, OFF,
	},{	/* cymbal */
		{ WAVE_NOISE, WAVE_SQUARE, OFF, 0.8, ON },
		{ 4000, 2 },
		{ 0, 0.01, 0.2, 0.8 },
		9,
		{ OFF, OFF, OFF }, {},
		{ OFF, OFF, 600 },
		{ OFF, }, OFF,
	},{	/* side stick */
		{ WAVE_NOISE, WAVE_SQUARE, OFF, 0.2, OFF },
		{ 1700, 3 },
		{ 0, 0.012, 0.1, 0.7 },
		10,
		{ OFF, OFF, OFF }, {},
		{ OFF, OFF, OFF },
		{ OFF, }, OFF,
	}
};

struct tone_rec *
tone_get(int prog, int note, double *ret_freq)
{
	int idx;
	struct tone_rec *ret;

	idx = -1;
	if(prog <= 0){ /* drum part */
		switch(note){
		case 36: /* bass drum1 */
			idx = 0;
			note = 28;
			break;
		case 37: /* side stick */
			idx = 6;
			note = 110;
			break;
		case 40: /* electric snare */
			idx = 1;
			note = 69;
			break;
		case 41: /* low floor tom */
			idx = 2;
			note = 50;
			break;
		case 42: /* closed hi-hat */
			idx = 3;
			note = 115 + 8;
			break;
		case 46: /* open hi-hat */
			idx = 4;
			note = 115 + 8;
			break;
		case 49: /* crash cymbal 1 */
		case 57: /* crash cymbal 2 */
			idx = 5;
			note = 100;
			break;
		}
		ret = idx < 0 ? NULL : &drum_tone_inf[idx];
	}else{
		switch(prog){
		case 48: /* timpani */
		case 50: /* strings ensamble 2 */
			idx = 0;
			break;
		case 35: /* electric bass (pick) */
			idx = 1;
			break;
		case 79: /* whistle */
		case 81: /* lead 1 (square) */
		case 87: /* lead 7 (fifths) */
			idx = 2;
			break;
		case 24: /* tango accordion */
		case 67: /* tenor sax */
			idx = 3;
			break;
		}
		ret = idx < 0 ? NULL : &tone_inf[idx];
	}
	if(ret_freq) *ret_freq = note_to_freq(note);
	return ret;
}

#define MIDI_CH_N	16
struct ch_rec{
	int vol;
	int pan;
	int bend;
	int rpn;
	int bend_range;
	int prog;
} ch_inf[ MIDI_CH_N ];

#define CH_PROG(ch)	( (ch) == 9 ? 0 : ch_inf[ch].prog )

double
env_out(struct note_rec *nt, double sec)
{
	struct tone_rec *tn;
	struct env_rec *e;
	double v;

	if((tn = tone_get(CH_PROG(nt->ch), nt->note, NULL)) == NULL) return 0;
	e = &tn->env;
	if(nt->onoff){
		sec -= nt->on_sec;
		if(sec < e->attack){
			v = sec / e->attack;
			return log10(1 + v * 9);
		}
		sec -= e->attack;
		if(sec < e->decay){
			v = sec / e->decay;
			v = log10(1 + v * 9);
			return 1 - v * (1 - e->sustain);
		}
		return e->sustain;
	}
	sec -= nt->off_sec;
	if(sec < e->release){
		v = sec / e->release;
		v = log10(1 + v * 9);
		return (1 - v) * nt->off_v;
	}
	return 0;
}

void
modu_out(double v, struct modu_rec *modu, double *ret_arr)
{
	if(modu->pitch1) ret_arr[0] += v * modu->pitch1 / 100.0 / 12;
	if(modu->pitch2) ret_arr[1] += v * modu->pitch2 / 100.0 / 12;
	if(modu->filter) ret_arr[2] += v * modu->filter / 100.0 / 12;
}

double
lfo_out(struct lfo_rec *lfo, struct modu_rec *modu, double sec, double on_sec)
{
	double dsec;

	if(!(modu->pitch1 || modu->pitch2 || modu->filter)) return 0;
	if((dsec = sec - on_sec - lfo->delay) <= 0) return 0;
	return wave_out(lfo->wave, lfo->freq * dsec);
}

double
vco_out(int wave, struct vco_stat_rec *stat, double freq, double sec, double modu_v)
{
	if(modu_v != 0) freq *= pow(2, modu_v /*/ 12*/);
	vco_stat_update(stat, freq, sec);
	return wave_out(wave, stat->cycle);
}

double
vcf_out(struct lpf_rec *lpf, struct lpf_stat_rec *lpf_stat, struct out_rec *ot, double modu_v, double v)
{
	struct lpf_rec lpf_tmp;

	if(lpf_stat->idx < 0) lpf_init(lpf, lpf_stat, ot->smp_freq);
	if(modu_v != 0){
		lpf_tmp = *lpf;
		lpf_tmp.freq *= pow(2, modu_v /*/ 12*/);
		lpf_update(&lpf_tmp, lpf_stat, ot->smp_freq);
	}
	return lpf_out(lpf_stat, v);
}

void
delay_buf_set(struct out_rec *ot, struct note_rec *nt, double v)
{
	// エフェクタのディレイ用のバッファへの値の設定
	//
	// 現在の出力値 v を、適切なバッファの位置へ書き込む
	
	nt->delay_buf[ (ot->smp_cnt - nt->fst_smp_cnt) % DELAY_BUF_N ] = v;
}

double
delay_buf_lookup(struct out_rec *ot, struct note_rec *nt, double sec)
{
	double cycle, v1, v2;
	int idx;

	// エフェクタのディレイ用のバッファの値の参照
	//
	// バッファに記録された、指定時刻(秒) sec のときの値を
	// 算出して返す
	// sec 前後の2つの出力値から算出する
	
	cycle = ot->smp_freq * sec - nt->fst_smp_cnt;
	idx = (int)cycle;
	cycle -= idx;
	v1 = nt->delay_buf[ idx % DELAY_BUF_N ];
	v2 = nt->delay_buf[ (idx + 1 ) % DELAY_BUF_N ];
	return v1 * (1 - cycle) + v2 * cycle;
}

double
delay_out(struct out_rec *ot, struct note_rec *nt, struct delay_rec *delay)
{
	// エフェクタのディレイ用のパラメータで、バッファの値を参照し、
	// ディレイの結果の出力を返す
	
	if(ot->sec - nt->on_sec < delay->sec) return 0;
	return delay_buf_lookup(ot, nt, ot->sec - delay->sec) * delay->gain;
}

double
chorus_out(struct out_rec *ot, struct note_rec *nt)
{
	// エフェクタのコーラスの結果の出力を返す
	//
	// エフェクタのディレイ用のバッファを利用
	// 基本的に1回きりのディレイで
	// 遅延は 0.01 秒を中心に、0.8 Hz で +0.001秒から-0.001秒の幅で揺らす
	// (パラメータは適当 :-p)
	
	double dsec, bak_sec;

	dsec = ot->sec - nt->on_sec;
	bak_sec = 0.01 + 0.001 * sin(2 * M_PI * 0.8 * dsec);
	if(dsec < bak_sec) return 0;
	return delay_buf_lookup(ot, nt, ot->sec - bak_sec);
}

int
delay_fin_chk(struct note_rec *nt, struct out_rec *ot)
{
	int i, n, j;
	double note_freq, v;

	// エフェクタのディレイ効果の終了判定
	//
	// ディレイによる残響音が終わったかどうか判定する
	// バッファ上の現在の出力位置から、鳴らす音の1周期分を遡って参照し
	// 出力値が全て 0.0001 以下まで収束してたら、終了とする
	
	note_freq = nt->vco_stat[0].freq;
	n = ot->smp_freq / note_freq;
	for(i=0; i<n; i++){
		j = (ot->smp_cnt - nt->fst_smp_cnt - i + DELAY_BUF_N) % DELAY_BUF_N;
		v = nt->delay_buf[j];
		if(v < 0) v = -v;
		if(v > 0.0001) break;
	}
	return i >= n;
}

int
note_out(struct out_rec *ot, struct note_rec *nt, double *vl, double *vr)
{
	double v, v1, v2, freq, pan, lfo_v, env_v, modu_v[3];
	int nch;
	struct tone_rec *tn;
	struct vco_rec *vco;

	nch = nt->ch;
	tn = tone_get(CH_PROG(nch), nt->note, &freq);
	if(tn == NULL) return 0;

	if(nt->fst_smp_cnt < 0) nt->fst_smp_cnt = ot->smp_cnt;
	// 鍵盤オンから最初にデータ出力したときの
	// サンプリングカウントを記録
	
	if(ch_inf[nch].bend != 0) freq *= pow(2, ch_inf[nch].bend / 8192.0 * ch_inf[nch].bend_range / 12);

	lfo_v = lfo_out(&tn->lfo, &tn->lfo_modu, ot->sec, nt->on_sec);
	env_v = env_out(nt, ot->sec);

	modu_v[0] = modu_v[1] = modu_v[2] = 0;
	modu_out(lfo_v, &tn->lfo_modu, modu_v);
	modu_out(env_v, &tn->env_modu, modu_v);

	vco = &tn->vco;
	v1 = vco_out(vco->wave1, &nt->vco_stat[0], freq, ot->sec, modu_v[0]);

	freq *= pow(2, (vco->tune / 100.0) / 12);
	v2 = vco_out(vco->wave2, &nt->vco_stat[1], freq, ot->sec, modu_v[1]);
	if(vco->ring){
		v = v1 * v2;
		v1 = (v1 + v2) / 2;
		v2 = v;
	}
	v = v1 * (1 - vco->mix) + v2 * vco->mix;

	v = vcf_out(&tn->lpf, &nt->lpf_stat, ot, modu_v[2], v);

	v *= env_v * tn->level;

	if(tn->delay.onoff) v += delay_out(ot, nt, &tn->delay);
	// エフェクタのディレイが有効ならば、
	// ディレイの結果の出力を足し込む
	
	delay_buf_set(ot, nt, v);
	// 出力値をエフェクタのディレイ用のバッファに書き込む
	
	if(tn->chorus) v += chorus_out(ot, nt);
	// エフェクタのコーラスが有効ならば、
	// コーラスの結果の出力を足し込む
	
	v *= nt->velo / 127.0;
	v *= ch_inf[nch].vol / (double)((1<<14)-1);
	if(ot->ch_num == 1){
		*vl += v;
	}else{
	pan = ch_inf[nch].pan / (double)(1<<14);
		*vl += (1 - pan) * v;
		*vr += pan * v;
	}
	return (nt->onoff == 0 && ot->sec - nt->off_sec >= tn->env.release &&
		(!tn->delay.onoff || delay_fin_chk(nt, ot)));
		// 鍵盤情報のバッファを削除するための、
		// 終了判定に、エフェクタのディレイが有効の場合の
		// 判定処理を追加
		
}

void
data_out(struct out_rec *ot, double evt_sec)
{
	double vl, vr;
	int i;
	struct note_rec *nt;

	while((ot->sec = ot->smp_t * ot->smp_cnt) < evt_sec){
		vl = vr = 0;
		for(i=0; i<NOTE_BUF_N; i++){
			if(note_buf_is_free(i)) continue;
			nt = &note_buf[i];
			if(note_out(ot, nt, &vl, &vr)) note_buf_free(i);
		}
		out_do(ot, vl / 16);
		if(ot->ch_num > 1) out_do(ot, vr / 16);
		ot->smp_cnt++;
	}
}

void
note_onoff(int onoff, double evt_sec, int ch, int note, int velo)
{
	int i, j;
	struct vco_stat_rec *stat;

	if(onoff){
		if((i = note_buf_search(-1, -1, -1)) < 0){
			MSG("note_buf full");
			return;
		}
		note_buf[i].note = note;
		note_buf[i].ch = ch;
		note_buf[i].onoff = 1;
		note_buf[i].on_sec = evt_sec;
		note_buf[i].velo = velo;
		for(j=0; j<2; j++){
			stat = &note_buf[i].vco_stat[j];
			stat->cycle = 0;
			stat->sec = evt_sec;
		}
		note_buf[i].lpf_stat.idx = -1;
		note_buf[i].fst_smp_cnt = -1;
		// 鍵盤オンから最初にデータ出力したときの
		// サンプリングカウントを、未設定状態として初期化
		
	}else{
		if((i = note_buf_search(ch, note, 1)) < 0) return;
		note_buf[i].off_v = env_out(&note_buf[i], evt_sec);
		note_buf[i].onoff = 0;
		note_buf[i].off_sec = evt_sec;
	}
}

void
msb_set(int *vp, int v)
{
	*vp &= ~(127<<7);
	*vp |= v<<7;
}

void
lsb_set(int *vp, int v)
{
	*vp &= ~127;
	*vp |= v;
}

void
bend_note_update(int ch, double sec)
{
	int i, j;
	struct note_rec *nt;
	struct vco_stat_rec *stat;

	for(i=0; i<NOTE_BUF_N; i++){
		if(note_buf_is_free(i)) continue;
		nt = &note_buf[i];
		if(nt->ch != ch) continue;
		for(j=0; j<2; j++){
			stat = &nt->vco_stat[j];
			vco_stat_update(stat, stat->freq, sec);
		}
	}
}

int
main(int ac, char **av)
{
	int div4, delta_sum;
	int i, n, v, hi, low, note, velo;
	int ch, type;
	double sec;
	struct out_rec otr;
	int tempo, tempo_delta_sum;
	double tempo_sec;

	out_init(&otr, ac, av);
	note_buf_init();
	for(i=0; i<MIDI_CH_N; i++){
		ch_inf[i].vol = 0;
		ch_inf[i].pan = 1<<(14-1);
		ch_inf[i].bend = 0;
		ch_inf[i].rpn = 0;
		ch_inf[i].bend_range = 2;
		ch_inf[i].prog =-1;
	}
	tempo = 500000;
	tempo_delta_sum = 0;
	tempo_sec = 0;

	div4 = header();

	if(!rd_str_chk(4, "MTrk")) ERR("track id");
	v = rd_int(4); /* skip */

	hi = low = 0;
	delta_sum = 0;
	while((v = rd_delta()) != EOF){
		delta_sum += v;
		sec = tempo_sec + (double)(delta_sum - tempo_delta_sum) / div4 * tempo * 0.000001;
		
		if((v = rd()) & 0x80){
			hi = (v >> 4) & 0xf;
			low  = v & 0xf;
		}else bk(v);

		data_out(&otr, sec);

		ch = low;
		switch(hi){
		case 8:
		case 9:
			note = rd();
			velo = rd();
			note_onoff(hi == 9, sec, ch, note, velo);
			break;
		case 0xb: /* control change */
			type = rd();
			v = rd();
			switch(type){
			case 7: /* channel volume msb */
				msb_set(&ch_inf[ch].vol, v);
				break;
			case 39: /* channel volume lsb */
				lsb_set(&ch_inf[ch].vol, v);
				break;
			case 10: /* pan msb */
				msb_set(&ch_inf[ch].pan, v);
				break;
			case 42: /* pan lsb */
				lsb_set(&ch_inf[ch].pan, v);
				break;
			case 100: /* rpn lsb */
				lsb_set(&ch_inf[ch].rpn, v);
				break;
			case 101: /* rpn msb */
				msb_set(&ch_inf[ch].rpn, v);
				break;
			case 6: /* data entry msb */
				switch(ch_inf[ch].rpn){
				case 0: /* pitch bend range */
					ch_inf[ch].bend_range = v;
					break;
				}
				break;
			}
			break;
		case 0xa:
			rd();
			rd();
			break;
		case 0xe: /* pitch wheel change */
			bend_note_update(ch, sec);
			v = rd();
			v |= rd() << 7;
			ch_inf[ch].bend = v - 8192;
			break;
		case 0xc: /* program number */
			v = rd();
			ch_inf[ch].prog = v;
			break;
		case 0xd:
			rd();
			break;
		case 0xf:
			type = rd();
			switch(low){
			case 0:
				while(rd() != 0xf7);
				break;
			case 1:
			case 3:
				rd();
				break;
			case 2:
				rd();
				rd();
				break;
			case 0xf: /* meta */
				n = rd();
				switch(type){
				case 0x51: /* set tempo */
					v = rd_int(n);
					tempo = v;
					tempo_delta_sum = delta_sum;
					tempo_sec = sec;
					break;
				default:
					for(i=0; i<n; i++) rd();
					break;
				}
				break;
			default:
				break;
			}
			break;
		}
	}
	if(otr.fp != stdout) pclose(otr.fp);
	return 0;
}

/* EOF */


prog20.c 解説

tmp4.c からの変更箇所のみ

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <math.h>

#define MSG(s) fprintf(stderr, "%s() %s L%d : %s\n", __func__, __FILE__, __LINE__, s)
#define ERR(s) do{ fprintf(stderr, "ERR "); MSG(s); exit(1); }while(0)

int bk_buf = -1;

int
rd(void)
{
	int v;

	if((v = bk_buf) < 0) return getchar();
	bk_buf = -1;
	return v;
}

void
bk(int v)
{
	if(bk_buf >= 0) ERR("give up");
	bk_buf = v;
}

void
rd_str(int n, char *s)
{
	int i;

	for(i=0; i<n; i++) s[i] = rd();
	s[i] = '\0';
}

int
rd_str_chk(int n, char *s)
{
	char buf[256];

	rd_str(n, buf);
	return strcmp(buf, s) == 0;
}

int
rd_int(int n) /* big endian */
{
	int i, v;

	v = 0;
	for(i=0; i<n; i++) v = (v << 8) | rd();
	return v;
}

int
rd_delta(void)
{
	int v, c;

	v = 0;
	do{
		if((c = rd()) == EOF) return EOF;
		v = (v << 7) | (c & 0x7f);
	}while(c & 0x80);
	return v;
}


int
opt_idx(char *key, int ac, char **av)
{
	int i;

	for(i=1; i<ac; i++) if(strcmp(av[i], key) == 0) return i;
	return -1;
}

char *
opt_str(char *key, int ac, char **av, char *def)
{
	int i;

	i = opt_idx(key, ac, av);
	if(i < 0 || i+1 >= ac) return def;
	return av[i+1];
}

int
opt_int(char *key, int ac, char **av, int def)
{
	char *s;

	if((s = opt_str(key, ac, av, NULL)) == NULL) return def;
	return strtol(s, NULL, 0);
}

struct out_rec{
	int smp_freq, smp_cnt;
	int bit_len;
	int sign;
	int ch_num;
	FILE *fp;

	int base;
	int amp;
	int iv_min;
	int iv_max;
	double smp_t, sec;
};

void
out_init(struct out_rec *ot, int ac, char **av)
{
	char cmd[1024], *fn;

	ot->smp_freq = opt_int("-r", ac, av, 44100);
	ot->smp_cnt = 0;
	ot->bit_len = opt_int("-b", ac, av, 16);
	if(ot->bit_len != 8 && ot->bit_len != 16) ERR("bit_len");
	ot->sign = (opt_idx("-u", ac, av) < 0);
	ot->ch_num = opt_int("-c", ac, av, 2);

	ot->fp = stdout;
	cmd[0] = '\0';
	fn = "";
	if(opt_idx("-play", ac, av) >= 0){
		strcat(cmd, "play");
	}else if(opt_idx("-sox", ac, av) >= 0){
		strcat(cmd, "sox");
		fn = opt_str("-sox", ac, av, "-d");
	}
	if(cmd[0]){
		sprintf(cmd + strlen(cmd), " -t raw -r %d -b %d %s -c %d - %s",
			ot->smp_freq, ot->bit_len,
			ot->sign ? "-s" : "-u",
			ot->ch_num, fn);
		if((ot->fp = popen(cmd, "w")) == NULL) ERR("popen");
	}
	ot->amp = ot->bit_len == 8 ? 127 : 32767;
	ot->base = ot->sign ? 0 : ot->amp + 1;
	ot->iv_min = ot->base - (ot->amp + 1);
	ot->iv_max = ot->base + ot->amp;

	ot->smp_t = 1.0 / ot->smp_freq;
}

void
out_do(struct out_rec *ot, double v)
{
	int iv;

	iv = ot->base + (int)(v * ot->amp);
	if(iv > ot->iv_max) iv = ot->iv_max;
	if(iv < ot->iv_min) iv = ot->iv_min;
	switch(ot->bit_len){
	case 8:
		fputc(iv, ot->fp);
		break;
	case 16:
		fputc(iv & 0xff, ot->fp);
		fputc((iv >> 8) & 0xff, ot->fp);
		break;
	}
}

struct lpf_rec{
	double freq, Q;
};

struct lpf_stat_rec{
	int idx;
	double in[4], out[4];
	double a0, a1, a2, b0, b1, b2, div_a0;
};

void
lpf_update(struct lpf_rec *lpf, struct lpf_stat_rec *stat, struct out_rec *ot)
{
	double w0, alpha;

	w0 = 2 * M_PI * lpf->freq * ot->smp_t;
	alpha = sin(w0) / (2 * lpf->Q);
	stat->b1 = 1 - cos(w0);
	stat->b0 = stat->b2 = stat->b1 * 0.5;
	stat->a0 = 1 + alpha;
	stat->a1 = -2 * cos(w0);
	stat->a2 = 1 - alpha;
	if(stat->a0 != 0) stat->div_a0 = 1 / stat->a0;
}

void
lpf_init(struct lpf_rec *lpf, struct lpf_stat_rec *stat, struct out_rec *ot)
{
	int i;

	for(i=0; i<4; i++) stat->in[i] = stat->out[i] = 0;
	stat->idx = 0;

	lpf_update(lpf, stat, ot);
}

double
lpf_out(struct lpf_stat_rec *stat, double in)
{
	double *out_p;
	int i_1, i_2;

	stat->in[stat->idx] = in;
	out_p = &stat->out[stat->idx];

	if(stat->a0 != 0){
		i_1 = (stat->idx + 4 - 1) & 3;
		i_2 = (i_1 + 4 - 1) & 3;
		*out_p = (stat->b0 * in
			+ stat->b1 * stat->in[i_1]
			+ stat->b2 * stat->in[i_2]
			- stat->a1 * stat->out[i_1]
			- stat->a2 * stat->out[i_2] ) * stat->div_a0;
	}else{
		*out_p = 0;
	}
	stat->idx = (stat->idx + 1) & 3;
	return *out_p;
}


#define NOTE_BUF_N	256

struct vco_stat_rec{
	double cycle, freq, sec;
};

void
vco_stat_update(struct vco_stat_rec *stat, double freq, double sec)
{
	stat->cycle += freq * (sec - stat->sec);	
	stat->freq = freq;
	stat->sec = sec;
}

#define DELAY_BUF_N	(44100 * 5 / 10) /* max 0.5 sec */

struct note_rec{
	int ch;
	int note;
	int onoff;
	double on_sec;
	double off_sec;
	int velo;
	struct vco_stat_rec vco_stat[2];
	double off_v;
	struct lpf_stat_rec lpf_stat;
	int fst_smp_cnt;
	double delay_buf[2][ DELAY_BUF_N ];
} note_buf[NOTE_BUF_N];

int
note_buf_is_free(int i)
{
	return note_buf[i].ch < 0;
}

void
note_buf_free(int i)
{
	note_buf[i].ch = -1;
}

void
note_buf_init(void)
{
	int i;

	for(i=0; i<NOTE_BUF_N; i++) note_buf_free(i);
}

int
note_buf_search(int ch, int note, int onoff)
{
	int i;

	for(i=0; i<NOTE_BUF_N; i++) {
		if( (ch < 0 && note_buf[i].ch < 0) ||
		    (note_buf[i].ch == ch &&
		     note_buf[i].note == note &&
		     note_buf[i].onoff == onoff) ) return i;
	}
	return -1;
}

int
header(void)
{
	int v;

	if(!rd_str_chk(4, "MThd")) ERR("header id");
	if(rd_int(4) != 6) ERR("header size");
	if(rd_int(2) != 0) ERR("header format type");
	if(rd_int(2) != 1) ERR("header track num");
	if((v = rd_int(2)) & 0x8000) ERR("header division");
	return v; /* div4 */
}

double
note_to_freq(int note)
{
	return 440 * pow(2, (note - 69) / 12.0);
}

#define OFF		0
#define ON		1

#define WAVE_SIN	0
#define WAVE_SAW	1
#define WAVE_SQUARE	2
#define WAVE_NOISE	3

double
wave_out(int wave, double cycle)
{
	cycle -= (int)cycle;

	switch(wave){
	case WAVE_SIN:
		return sin(2 * M_PI * cycle);
	case WAVE_SAW:
		cycle *= 2;
		if(cycle > 1) cycle -= 2;
		return cycle;
	case WAVE_SQUARE:
		return cycle < 0.5 ? 1 : -1;
	case WAVE_NOISE:
		return ((double)rand() / RAND_MAX) * 2 - 1;
	}
	return 0;
}

struct vco_rec{
	int wave1, wave2;
	int tune; /* for vco2 */
	double mix;
	int ring;
};

struct modu_rec{
	int pitch1, pitch2, filter;
};

struct lfo_rec{
	int wave;
	double freq, delay;
};

struct env_rec{
	double attack;	/* sec */
	double decay;	/* sec */
	double sustain;	/* 0..1 */
	double release;	/* sec */
};

struct delay_rec{
	int onoff;
	double sec, gain;
};

struct tone_rec{
	struct vco_rec vco;
	struct lpf_rec lpf;
	struct env_rec env;
	double level;
	struct modu_rec lfo_modu;
	struct lfo_rec lfo;
	struct modu_rec env_modu;
	struct delay_rec delay;
	int chorus;
} tone_inf[] = {
	{	/* strings */
		{ WAVE_SAW, WAVE_SAW, 12, 0.5, OFF },
		{ 3000, 1.5 },
		{ 0.15, 0.5, 0.8, 0.5 },
		1.0,
		{ OFF, 12, OFF }, { WAVE_SIN, 4, 0.3 },
		{ OFF, OFF, OFF },
		{ OFF, }, ON,
	},{	/* bass */
		{ WAVE_SAW, WAVE_SQUARE, OFF, 0.5, OFF },
		{ 1000, 1.5} ,
		{ 0.05, 0.2, 0.4, 0.2 },
		1.0,
		{ OFF, 60, OFF }, { WAVE_SIN, 1.5, 0.2 },
		{ OFF, OFF, OFF },
		{ OFF, }, ON,
	},{	/* lead */
		{ WAVE_SQUARE, WAVE_SQUARE, 10, 0.5, OFF },
		{ 2000, 4 },
		{ 0.01, 0.2, 0.8, 0.3 },
		1.0,
		{ OFF, 1, 5 }, { WAVE_SIN, 4, 0.3 },
		{ OFF, OFF, OFF },
		{ ON, 0.2, 0.4}, OFF,
	},{	/* SIN */
		{ WAVE_SIN, WAVE_SIN, OFF, 0, OFF },
		{ 20000, 0.8 },
		{ 0, 0.3, 0.2, 0.3 },
		1.4,
		{ 25, OFF, OFF }, { WAVE_SIN, 6, 0.3 },
		{ OFF, OFF, OFF },
		{ OFF, }, OFF,
	}
}, drum_tone_inf[] = {
	{	/* bass */
		{ WAVE_SIN, WAVE_NOISE, OFF, 0.4, OFF },
		{ 400, 1 },
		{ 0.01, 0.18, 0, 0.18 },
		9.0,
		{ 100, OFF, 30 }, { WAVE_NOISE, 0, 0.5 },
		{ OFF, OFF, OFF },
		{ OFF, }, OFF,
	},{	/* snare */
		{ WAVE_SQUARE, WAVE_NOISE, OFF, 0.8, ON },
		{ 1500, 1.7 },
		{ 0, 0.4, 0.3, 0.4 },
		5,
		{ OFF, OFF, OFF, }, {},
		{ OFF, OFF, OFF },
		{ OFF, }, OFF,
	},{	/* tom */
		{ WAVE_SQUARE, WAVE_NOISE, OFF, 0.5, ON },
		{ 800, 2.5 },
		{ 0, 0.03, 0.1, 0.4 },
		5,
		{ OFF, OFF, OFF, }, {},
		{ 200, OFF, 1200 },
		{ OFF, }, OFF,
	},{	/* hi-hat close */
		{ WAVE_SQUARE, WAVE_SQUARE, 700, 0.9, ON },
		{ 16000, 2 },
		{ 0, 0.15, 0, 0.15 },
		0.6,
		{ OFF, OFF, OFF, }, {},
		{ OFF, OFF, OFF },
		{ OFF, }, OFF,
	},{	/* hi-hat open */
		{ WAVE_SQUARE, WAVE_SQUARE, 700, 0.9, ON },
		{ 16000, 2 },
		{ 0, 0, 1, 0.35 },
		0.6,
		{ OFF, OFF, OFF, }, {},
		{ OFF, OFF, OFF },
		{ OFF, }, OFF,
	},{	/* cymbal */
		{ WAVE_NOISE, WAVE_SQUARE, OFF, 0.8, ON },
		{ 4000, 2 },
		{ 0, 0.01, 0.2, 0.8 },
		9,
		{ OFF, OFF, OFF }, {},
		{ OFF, OFF, 600 },
		{ OFF, }, OFF,
	},{	/* side stick */
		{ WAVE_NOISE, WAVE_SQUARE, OFF, 0.2, OFF },
		{ 1700, 3 },
		{ 0, 0.012, 0.1, 0.7 },
		10,
		{ OFF, OFF, OFF }, {},
		{ OFF, OFF, OFF },
		{ OFF, }, OFF,
	}
};

struct tone_rec *
tone_get(int prog, int note, double *ret_freq)
{
	int idx;
	struct tone_rec *ret;

	idx = -1;
	if(prog <= 0){ /* drum part */
		switch(note){
		case 36: /* bass drum1 */
			idx = 0;
			note = 28;
			break;
		case 37: /* side stick */
			idx = 6;
			note = 110;
			break;
		case 40: /* electric snare */
			idx = 1;
			note = 69;
			break;
		case 41: /* low floor tom */
			idx = 2;
			note = 50;
			break;
		case 42: /* closed hi-hat */
			idx = 3;
			note = 115 + 8;
			break;
		case 46: /* open hi-hat */
			idx = 4;
			note = 115 + 8;
			break;
		case 49: /* crash cymbal 1 */
		case 57: /* crash cymbal 2 */
			idx = 5;
			note = 100;
			break;
		}
		ret = idx < 0 ? NULL : &drum_tone_inf[idx];
	}else{
		switch(prog){
		case 48: /* timpani */
		case 50: /* strings ensamble 2 */
			idx = 0;
			break;
		case 35: /* electric bass (pick) */
			idx = 1;
			break;
		case 79: /* whistle */
		case 81: /* lead 1 (square) */
		case 87: /* lead 7 (fifths) */
			idx = 2;
			break;
		case 24: /* tango accordion */
		case 67: /* tenor sax */
			idx = 3;
			break;
		}
		ret = idx < 0 ? NULL : &tone_inf[idx];
	}
	if(ret_freq) *ret_freq = note_to_freq(note);
	return ret;
}

#define MIDI_CH_N	16
struct ch_rec{
	int vol;
	int pan;
	int bend;
	int rpn;
	int bend_range;
	int prog;
} ch_inf[ MIDI_CH_N ];

#define CH_PROG(ch)	( (ch) == 9 ? 0 : ch_inf[ch].prog )

double
env_out(struct note_rec *nt, double sec)
{
	struct tone_rec *tn;
	struct env_rec *e;
	double v;

	if((tn = tone_get(CH_PROG(nt->ch), nt->note, NULL)) == NULL) return 0;
	e = &tn->env;
	if(nt->onoff){
		sec -= nt->on_sec;
		if(sec < e->attack){
			v = sec / e->attack;
			return log10(1 + v * 9);
		}
		sec -= e->attack;
		if(sec < e->decay){
			v = sec / e->decay;
			v = log10(1 + v * 9);
			return 1 - v * (1 - e->sustain);
		}
		return e->sustain;
	}
	sec -= nt->off_sec;
	if(sec < e->release){
		v = sec / e->release;
		v = log10(1 + v * 9);
		return (1 - v) * nt->off_v;
	}
	return 0;
}

void
modu_out(double v, struct modu_rec *modu, double *ret_arr)
{
	if(modu->pitch1) ret_arr[0] += v * modu->pitch1 * (1.0 / 1200);
	if(modu->pitch2) ret_arr[1] += v * modu->pitch2 * (1.0 / 1200);
	if(modu->filter) ret_arr[2] += v * modu->filter * (1.0 / 1200);
}

double
lfo_out(struct lfo_rec *lfo, struct modu_rec *modu, double sec, double on_sec)
{
	double dsec;

	if(!(modu->pitch1 || modu->pitch2 || modu->filter)) return 0;
	if((dsec = sec - on_sec - lfo->delay) <= 0) return 0;
	return wave_out(lfo->wave, lfo->freq * dsec);
}

double
vco_out(int wave, struct vco_stat_rec *stat, double freq, double sec, double modu_v)
{
	if(modu_v != 0) freq *= pow(2, modu_v);
	vco_stat_update(stat, freq, sec);
	return wave_out(wave, stat->cycle);
}

double
vcf_out(struct lpf_rec *lpf, struct lpf_stat_rec *lpf_stat, struct out_rec *ot, double modu_v, double v)
{
	struct lpf_rec lpf_tmp;

	if(lpf_stat->idx < 0) lpf_init(lpf, lpf_stat, ot);
	if(modu_v != 0){
		lpf_tmp = *lpf;
		lpf_tmp.freq *= pow(2, modu_v);
		lpf_update(&lpf_tmp, lpf_stat, ot);
	}
	return lpf_out(lpf_stat, v);
}

void
delay_buf_set(struct out_rec *ot, struct note_rec *nt, double v, double env_v)
{
	int i;

	i = (ot->smp_cnt - nt->fst_smp_cnt) % DELAY_BUF_N;
	nt->delay_buf[0][i] = v;
	nt->delay_buf[1][i] = env_v;
}

#define MIX(a, b, rate)		( (a) * (1 - (rate)) + (b) * (rate) )

double
tbl_lookup(double *tbl, int n, double d_idx)
{
	int i;

	i = (int)d_idx;
	d_idx -= i;
	i %= n;
	return MIX(tbl[i], tbl[(i+1)%n], d_idx);
}

double
delay_buf_lookup(struct out_rec *ot, struct note_rec *nt, double sec, double *ret_env_v)
{
	double cycle;

	cycle = ot->smp_freq * sec - nt->fst_smp_cnt;
	if(ret_env_v) *ret_env_v = tbl_lookup(nt->delay_buf[1], DELAY_BUF_N, cycle);
	return tbl_lookup(nt->delay_buf[0], DELAY_BUF_N, cycle);
}

double
delay_out(struct out_rec *ot, struct note_rec *nt, struct delay_rec *delay, double *ret_env_v)
{
	double v;

	if(ot->sec - nt->on_sec < delay->sec) return 0;
	v = delay_buf_lookup(ot, nt, ot->sec - delay->sec, ret_env_v) * delay->gain;
	if(ret_env_v) *ret_env_v *= delay->gain;
	return v;
}

double
chorus_out(struct out_rec *ot, struct note_rec *nt)
{
	double dsec, bak_sec;

	dsec = ot->sec - nt->on_sec;
	bak_sec = 0.01 + 0.001 * sin(2 * M_PI * 0.8 * dsec);
	if(dsec < bak_sec) return 0;
	return delay_buf_lookup(ot, nt, ot->sec - bak_sec, NULL);
}

double
tone_out(struct out_rec *ot, struct note_rec *nt, struct tone_rec *tn, double freq, double env_v)
{
	double v, v1, v2, lfo_v, modu_v[3];
	struct vco_rec *vco;

	lfo_v = lfo_out(&tn->lfo, &tn->lfo_modu, ot->sec, nt->on_sec);

	modu_v[0] = modu_v[1] = modu_v[2] = 0;
	modu_out(lfo_v, &tn->lfo_modu, modu_v);
	modu_out(env_v, &tn->env_modu, modu_v);

	vco = &tn->vco;
	v1 = vco_out(vco->wave1, &nt->vco_stat[0], freq, ot->sec, modu_v[0]);

	modu_v[1] += vco->tune * (1.0 / 1200);
	v2 = vco_out(vco->wave2, &nt->vco_stat[1], freq, ot->sec, modu_v[1]);
	if(vco->ring){
		v = v1 * v2;
		v1 = (v1 + v2) * 0.5;
		v2 = v;
	}
	v = MIX(v1, v2, vco->mix);

	v = vcf_out(&tn->lpf, &nt->lpf_stat, ot, modu_v[2], v);

	v *= env_v * tn->level;
	return v;
}

int
note_out(struct out_rec *ot, struct note_rec *nt, double *vl, double *vr)
{
	double v, freq, pan, env_v, d_env_v;
	int nch;
	struct tone_rec *tn;

	nch = nt->ch;
	tn = tone_get(CH_PROG(nch), nt->note, &freq);
	if(tn == NULL) return 0;

	if(nt->fst_smp_cnt < 0) nt->fst_smp_cnt = ot->smp_cnt;

	if(ch_inf[nch].bend != 0) freq *= pow(2, ch_inf[nch].bend * ch_inf[nch].bend_range * (1.0 / (8192 * 12)));

	env_v = env_out(nt, ot->sec);
	v = (env_v > 0) ? tone_out(ot, nt, tn, freq, env_v) : 0;

	d_env_v = 0;
	if(tn->delay.onoff) v += delay_out(ot, nt, &tn->delay, &d_env_v);
	d_env_v += env_v;
	delay_buf_set(ot, nt, v, d_env_v);
	if(tn->chorus) v += chorus_out(ot, nt);

	v *= (nt->velo * (1.0 / 127)) * (ch_inf[nch].vol * (1.0 / ((1<<14)-1)));
	if(ot->ch_num == 1){
		*vl += v;
	}else{
		pan = ch_inf[nch].pan * (1.0 / (1<<14));
		*vl += (1 - pan) * v;
		*vr += pan * v;
	}
	return nt->onoff == 0 && ot->sec - nt->off_sec >= tn->env.release &&
		(!tn->delay.onoff || d_env_v < 0.01);
}

void
data_out(struct out_rec *ot, double evt_sec)
{
	double vl, vr;
	int i;
	struct note_rec *nt;

	while((ot->sec = ot->smp_t * ot->smp_cnt) < evt_sec){
		vl = vr = 0;
		for(i=0; i<NOTE_BUF_N; i++){
			if(note_buf_is_free(i)) continue;
			nt = &note_buf[i];
			if(note_out(ot, nt, &vl, &vr)) note_buf_free(i);
		}
		out_do(ot, vl * (1.0 / 16));
		if(ot->ch_num > 1) out_do(ot, vr * (1.0 / 16));
		ot->smp_cnt++;
	}
}

void
note_onoff(int onoff, double evt_sec, int ch, int note, int velo)
{
	int i, j;
	struct vco_stat_rec *stat;

	if(onoff){
		if((i = note_buf_search(-1, -1, -1)) < 0){
			MSG("note_buf full");
			return;
		}
		note_buf[i].note = note;
		note_buf[i].ch = ch;
		note_buf[i].onoff = 1;
		note_buf[i].on_sec = evt_sec;
		note_buf[i].velo = velo;
		for(j=0; j<2; j++){
			stat = &note_buf[i].vco_stat[j];
			stat->cycle = 0;
			stat->sec = evt_sec;
		}
		note_buf[i].lpf_stat.idx = -1;
		note_buf[i].fst_smp_cnt = -1;
	}else{
		if((i = note_buf_search(ch, note, 1)) < 0) return;
		note_buf[i].off_v = env_out(&note_buf[i], evt_sec);
		note_buf[i].onoff = 0;
		note_buf[i].off_sec = evt_sec;
	}
}

void
msb_set(int *vp, int v)
{
	*vp &= ~(127<<7);
	*vp |= v<<7;
}

void
lsb_set(int *vp, int v)
{
	*vp &= ~127;
	*vp |= v;
}

void
bend_note_update(int ch, double sec)
{
	int i, j;
	struct note_rec *nt;
	struct vco_stat_rec *stat;

	for(i=0; i<NOTE_BUF_N; i++){
		if(note_buf_is_free(i)) continue;
		nt = &note_buf[i];
		if(nt->ch != ch) continue;
		for(j=0; j<2; j++){
			stat = &nt->vco_stat[j];
			vco_stat_update(stat, stat->freq, sec);
		}
	}
}

int
main(int ac, char **av)
{
	int div4, delta_sum;
	int i, n, v, hi, low, note, velo;
	int ch, type;
	double sec;
	struct out_rec otr;
	int tempo, tempo_delta_sum;
	double tempo_sec;

	out_init(&otr, ac, av);
	note_buf_init();
	for(i=0; i<MIDI_CH_N; i++){
		ch_inf[i].vol = 0;
		ch_inf[i].pan = 1<<(14-1);
		ch_inf[i].bend = 0;
		ch_inf[i].rpn = 0;
		ch_inf[i].bend_range = 2;
		ch_inf[i].prog =-1;
	}
	tempo = 500000;
	tempo_delta_sum = 0;
	tempo_sec = 0;

	div4 = header();

	if(!rd_str_chk(4, "MTrk")) ERR("track id");
	v = rd_int(4); /* skip */

	hi = low = 0;
	delta_sum = 0;
	while((v = rd_delta()) != EOF){
		delta_sum += v;
		sec = tempo_sec + (double)(delta_sum - tempo_delta_sum) / div4 * tempo * 0.000001;
		
		if((v = rd()) & 0x80){
			hi = (v >> 4) & 0xf;
			low  = v & 0xf;
		}else bk(v);

		data_out(&otr, sec);

		ch = low;
		switch(hi){
		case 8:
		case 9:
			note = rd();
			velo = rd();
			note_onoff(hi == 9, sec, ch, note, velo);
			break;
		case 0xb: /* control change */
			type = rd();
			v = rd();
			switch(type){
			case 7: /* channel volume msb */
				msb_set(&ch_inf[ch].vol, v);
				break;
			case 39: /* channel volume lsb */
				lsb_set(&ch_inf[ch].vol, v);
				break;
			case 10: /* pan msb */
				msb_set(&ch_inf[ch].pan, v);
				break;
			case 42: /* pan lsb */
				lsb_set(&ch_inf[ch].pan, v);
				break;
			case 100: /* rpn lsb */
				lsb_set(&ch_inf[ch].rpn, v);
				break;
			case 101: /* rpn msb */
				msb_set(&ch_inf[ch].rpn, v);
				break;
			case 6: /* data entry msb */
				switch(ch_inf[ch].rpn){
				case 0: /* pitch bend range */
					ch_inf[ch].bend_range = v;
					break;
				}
				break;
			}
			break;
		case 0xa:
			rd();
			rd();
			break;
		case 0xe: /* pitch wheel change */
			bend_note_update(ch, sec);
			v = rd();
			v |= rd() << 7;
			ch_inf[ch].bend = v - 8192;
			break;
		case 0xc: /* program number */
			v = rd();
			ch_inf[ch].prog = v;
			break;
		case 0xd:
			rd();
			break;
		case 0xf:
			type = rd();
			switch(low){
			case 0:
				while(rd() != 0xf7);
				break;
			case 1:
			case 3:
				rd();
				break;
			case 2:
				rd();
				rd();
				break;
			case 0xf: /* meta */
				n = rd();
				switch(type){
				case 0x51: /* set tempo */
					v = rd_int(n);
					tempo = v;
					tempo_delta_sum = delta_sum;
					tempo_sec = sec;
					break;
				default:
					for(i=0; i<n; i++) rd();
					break;
				}
				break;
			default:
				break;
			}
			break;
		}
	}
	if(otr.fp != stdout) pclose(otr.fp);
	return 0;
}

/* EOF */


#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <math.h>

#define MSG(s) fprintf(stderr, "%s() %s L%d : %s\n", __func__, __FILE__, __LINE__, s)
#define ERR(s) do{ fprintf(stderr, "ERR "); MSG(s); exit(1); }while(0)

int bk_buf = -1;

int
rd(void)
{
	int v;

	if((v = bk_buf) < 0) return getchar();
	bk_buf = -1;
	return v;
}

void
bk(int v)
{
	if(bk_buf >= 0) ERR("give up");
	bk_buf = v;
}

void
rd_str(int n, char *s)
{
	int i;

	for(i=0; i<n; i++) s[i] = rd();
	s[i] = '\0';
}

int
rd_str_chk(int n, char *s)
{
	char buf[256];

	rd_str(n, buf);
	return strcmp(buf, s) == 0;
}

int
rd_int(int n) /* big endian */
{
	int i, v;

	v = 0;
	for(i=0; i<n; i++) v = (v << 8) | rd();
	return v;
}

int
rd_delta(void)
{
	int v, c;

	v = 0;
	do{
		if((c = rd()) == EOF) return EOF;
		v = (v << 7) | (c & 0x7f);
	}while(c & 0x80);
	return v;
}


int
opt_idx(char *key, int ac, char **av)
{
	int i;

	for(i=1; i<ac; i++) if(strcmp(av[i], key) == 0) return i;
	return -1;
}

char *
opt_str(char *key, int ac, char **av, char *def)
{
	int i;

	i = opt_idx(key, ac, av);
	if(i < 0 || i+1 >= ac) return def;
	return av[i+1];
}

int
opt_int(char *key, int ac, char **av, int def)
{
	char *s;

	if((s = opt_str(key, ac, av, NULL)) == NULL) return def;
	return strtol(s, NULL, 0);
}

struct out_rec{
	int smp_freq, smp_cnt;
	int bit_len;
	int sign;
	int ch_num;
	FILE *fp;

	int base;
	int amp;
	int iv_min;
	int iv_max;
	double smp_t, sec;
};

void
out_init(struct out_rec *ot, int ac, char **av)
{
	char cmd[1024], *fn;

	ot->smp_freq = opt_int("-r", ac, av, 44100);
	ot->smp_cnt = 0;
	ot->bit_len = opt_int("-b", ac, av, 16);
	if(ot->bit_len != 8 && ot->bit_len != 16) ERR("bit_len");
	ot->sign = (opt_idx("-u", ac, av) < 0);
	ot->ch_num = opt_int("-c", ac, av, 2);

	ot->fp = stdout;
	cmd[0] = '\0';
	fn = "";
	if(opt_idx("-play", ac, av) >= 0){
		strcat(cmd, "play");
	}else if(opt_idx("-sox", ac, av) >= 0){
		strcat(cmd, "sox");
		fn = opt_str("-sox", ac, av, "-d");
	}
	if(cmd[0]){
		sprintf(cmd + strlen(cmd), " -t raw -r %d -b %d %s -c %d - %s",
			ot->smp_freq, ot->bit_len,
			ot->sign ? "-s" : "-u",
			ot->ch_num, fn);
		if((ot->fp = popen(cmd, "w")) == NULL) ERR("popen");
	}
	ot->amp = ot->bit_len == 8 ? 127 : 32767;
	ot->base = ot->sign ? 0 : ot->amp + 1;
	ot->iv_min = ot->base - (ot->amp + 1);
	ot->iv_max = ot->base + ot->amp;

	ot->smp_t = 1.0 / ot->smp_freq;
}

void
out_do(struct out_rec *ot, double v)
{
	int iv;

	iv = ot->base + (int)(v * ot->amp);
	if(iv > ot->iv_max) iv = ot->iv_max;
	if(iv < ot->iv_min) iv = ot->iv_min;
	switch(ot->bit_len){
	case 8:
		fputc(iv, ot->fp);
		break;
	case 16:
		fputc(iv & 0xff, ot->fp);
		fputc((iv >> 8) & 0xff, ot->fp);
		break;
	}
}

struct lpf_rec{
	double freq, Q;
};

struct lpf_stat_rec{
	int idx;
	double in[4], out[4];
	double a0, a1, a2, b0, b1, b2, div_a0;
};

void
lpf_update(struct lpf_rec *lpf, struct lpf_stat_rec *stat, struct out_rec *ot)
{
	double w0, alpha;

	w0 = 2 * M_PI * lpf->freq * ot->smp_t;
	alpha = sin(w0) / (2 * lpf->Q);
	stat->b1 = 1 - cos(w0);
	stat->b0 = stat->b2 = stat->b1 * 0.5;
	stat->a0 = 1 + alpha;
	stat->a1 = -2 * cos(w0);
	stat->a2 = 1 - alpha;
	if(stat->a0 != 0) stat->div_a0 = 1 / stat->a0;
}

void
lpf_init(struct lpf_rec *lpf, struct lpf_stat_rec *stat, struct out_rec *ot)
{
	int i;

	for(i=0; i<4; i++) stat->in[i] = stat->out[i] = 0;
	stat->idx = 0;

	lpf_update(lpf, stat, ot);
}

double
lpf_out(struct lpf_stat_rec *stat, double in)
{
	double *out_p;
	int i_1, i_2;

	stat->in[stat->idx] = in;
	out_p = &stat->out[stat->idx];

	if(stat->a0 != 0){
		i_1 = (stat->idx + 4 - 1) & 3;
		i_2 = (i_1 + 4 - 1) & 3;
		*out_p = (stat->b0 * in
			+ stat->b1 * stat->in[i_1]
			+ stat->b2 * stat->in[i_2]
			- stat->a1 * stat->out[i_1]
			- stat->a2 * stat->out[i_2] ) * stat->div_a0;
	}else{
		*out_p = 0;
	}
	stat->idx = (stat->idx + 1) & 3;
	return *out_p;
}


#define NOTE_BUF_N	256

struct vco_stat_rec{
	double cycle, freq, sec;
};

void
vco_stat_update(struct vco_stat_rec *stat, double freq, double sec)
{
	stat->cycle += freq * (sec - stat->sec);	
	stat->freq = freq;
	stat->sec = sec;
}

#define DELAY_BUF_N	(44100 * 5 / 10) /* max 0.5 sec */

struct note_rec{
	int ch;
	int note;
	int onoff;
	double on_sec;
	double off_sec;
	int velo;
	struct vco_stat_rec vco_stat[2];
	double off_v;
	struct lpf_stat_rec lpf_stat;
	int fst_smp_cnt;
	double delay_buf[2][ DELAY_BUF_N ];
	// 出力波形用以外にエンベロープ出力用を追加するため
	// [2] に
	
} note_buf[NOTE_BUF_N];

int
note_buf_is_free(int i)
{
	return note_buf[i].ch < 0;
}

void
note_buf_free(int i)
{
	note_buf[i].ch = -1;
}

void
note_buf_init(void)
{
	int i;

	for(i=0; i<NOTE_BUF_N; i++) note_buf_free(i);
}

int
note_buf_search(int ch, int note, int onoff)
{
	int i;

	for(i=0; i<NOTE_BUF_N; i++) {
		if( (ch < 0 && note_buf[i].ch < 0) ||
		    (note_buf[i].ch == ch &&
		     note_buf[i].note == note &&
		     note_buf[i].onoff == onoff) ) return i;
	}
	return -1;
}

int
header(void)
{
	int v;

	if(!rd_str_chk(4, "MThd")) ERR("header id");
	if(rd_int(4) != 6) ERR("header size");
	if(rd_int(2) != 0) ERR("header format type");
	if(rd_int(2) != 1) ERR("header track num");
	if((v = rd_int(2)) & 0x8000) ERR("header division");
	return v; /* div4 */
}

double
note_to_freq(int note)
{
	return 440 * pow(2, (note - 69) / 12.0);
}

#define OFF		0
#define ON		1

#define WAVE_SIN	0
#define WAVE_SAW	1
#define WAVE_SQUARE	2
#define WAVE_NOISE	3

double
wave_out(int wave, double cycle)
{
	cycle -= (int)cycle;

	switch(wave){
	case WAVE_SIN:
		return sin(2 * M_PI * cycle);
	case WAVE_SAW:
		cycle *= 2;
		if(cycle > 1) cycle -= 2;
		return cycle;
	case WAVE_SQUARE:
		return cycle < 0.5 ? 1 : -1;
	case WAVE_NOISE:
		return ((double)rand() / RAND_MAX) * 2 - 1;
	}
	return 0;
}

struct vco_rec{
	int wave1, wave2;
	int tune; /* for vco2 */
	double mix;
	int ring;
};

struct modu_rec{
	int pitch1, pitch2, filter;
};

struct lfo_rec{
	int wave;
	double freq, delay;
};

struct env_rec{
	double attack;	/* sec */
	double decay;	/* sec */
	double sustain;	/* 0..1 */
	double release;	/* sec */
};

struct delay_rec{
	int onoff;
	double sec, gain;
};

struct tone_rec{
	struct vco_rec vco;
	struct lpf_rec lpf;
	struct env_rec env;
	double level;
	struct modu_rec lfo_modu;
	struct lfo_rec lfo;
	struct modu_rec env_modu;
	struct delay_rec delay;
	int chorus;
} tone_inf[] = {
	{	/* strings */
		{ WAVE_SAW, WAVE_SAW, 12, 0.5, OFF },
		{ 3000, 1.5 },
		{ 0.15, 0.5, 0.8, 0.5 },
		1.0,
		{ OFF, 12, OFF }, { WAVE_SIN, 4, 0.3 },
		{ OFF, OFF, OFF },
		{ OFF, }, ON,
	},{	/* bass */
		{ WAVE_SAW, WAVE_SQUARE, OFF, 0.5, OFF },
		{ 1000, 1.5} ,
		{ 0.05, 0.2, 0.4, 0.2 },
		1.0,
		{ OFF, 60, OFF }, { WAVE_SIN, 1.5, 0.2 },
		{ OFF, OFF, OFF },
		{ OFF, }, ON,
	},{	/* lead */
		{ WAVE_SQUARE, WAVE_SQUARE, 10, 0.5, OFF },
		{ 2000, 4 },
		{ 0.01, 0.2, 0.8, 0.3 },
		1.0,
		{ OFF, 1, 5 }, { WAVE_SIN, 4, 0.3 },
		{ OFF, OFF, OFF },
		{ ON, 0.2, 0.4}, OFF,
	},{	/* SIN */
		{ WAVE_SIN, WAVE_SIN, OFF, 0, OFF },
		{ 20000, 0.8 },
		{ 0, 0.3, 0.2, 0.3 },
		1.4,
		{ 25, OFF, OFF }, { WAVE_SIN, 6, 0.3 },
		{ OFF, OFF, OFF },
		{ OFF, }, OFF,
	}
}, drum_tone_inf[] = {
	{	/* bass */
		{ WAVE_SIN, WAVE_NOISE, OFF, 0.4, OFF },
		{ 400, 1 },
		{ 0.01, 0.18, 0, 0.18 },
		9.0,
		{ 100, OFF, 30 }, { WAVE_NOISE, 0, 0.5 },
		{ OFF, OFF, OFF },
		{ OFF, }, OFF,
	},{	/* snare */
		{ WAVE_SQUARE, WAVE_NOISE, OFF, 0.8, ON },
		{ 1500, 1.7 },
		{ 0, 0.4, 0.3, 0.4 },
		5,
		{ OFF, OFF, OFF, }, {},
		{ OFF, OFF, OFF },
		{ OFF, }, OFF,
	},{	/* tom */
		{ WAVE_SQUARE, WAVE_NOISE, OFF, 0.5, ON },
		{ 800, 2.5 },
		{ 0, 0.03, 0.1, 0.4 },
		5,
		{ OFF, OFF, OFF, }, {},
		{ 200, OFF, 1200 },
		{ OFF, }, OFF,
	},{	/* hi-hat close */
		{ WAVE_SQUARE, WAVE_SQUARE, 700, 0.9, ON },
		{ 16000, 2 },
		{ 0, 0.15, 0, 0.15 },
		0.6,
		{ OFF, OFF, OFF, }, {},
		{ OFF, OFF, OFF },
		{ OFF, }, OFF,
	},{	/* hi-hat open */
		{ WAVE_SQUARE, WAVE_SQUARE, 700, 0.9, ON },
		{ 16000, 2 },
		{ 0, 0, 1, 0.35 },
		0.6,
		{ OFF, OFF, OFF, }, {},
		{ OFF, OFF, OFF },
		{ OFF, }, OFF,
	},{	/* cymbal */
		{ WAVE_NOISE, WAVE_SQUARE, OFF, 0.8, ON },
		{ 4000, 2 },
		{ 0, 0.01, 0.2, 0.8 },
		9,
		{ OFF, OFF, OFF }, {},
		{ OFF, OFF, 600 },
		{ OFF, }, OFF,
	},{	/* side stick */
		{ WAVE_NOISE, WAVE_SQUARE, OFF, 0.2, OFF },
		{ 1700, 3 },
		{ 0, 0.012, 0.1, 0.7 },
		10,
		{ OFF, OFF, OFF }, {},
		{ OFF, OFF, OFF },
		{ OFF, }, OFF,
	}
};

struct tone_rec *
tone_get(int prog, int note, double *ret_freq)
{
	int idx;
	struct tone_rec *ret;

	idx = -1;
	if(prog <= 0){ /* drum part */
		switch(note){
		case 36: /* bass drum1 */
			idx = 0;
			note = 28;
			break;
		case 37: /* side stick */
			idx = 6;
			note = 110;
			break;
		case 40: /* electric snare */
			idx = 1;
			note = 69;
			break;
		case 41: /* low floor tom */
			idx = 2;
			note = 50;
			break;
		case 42: /* closed hi-hat */
			idx = 3;
			note = 115 + 8;
			break;
		case 46: /* open hi-hat */
			idx = 4;
			note = 115 + 8;
			break;
		case 49: /* crash cymbal 1 */
		case 57: /* crash cymbal 2 */
			idx = 5;
			note = 100;
			break;
		}
		ret = idx < 0 ? NULL : &drum_tone_inf[idx];
	}else{
		switch(prog){
		case 48: /* timpani */
		case 50: /* strings ensamble 2 */
			idx = 0;
			break;
		case 35: /* electric bass (pick) */
			idx = 1;
			break;
		case 79: /* whistle */
		case 81: /* lead 1 (square) */
		case 87: /* lead 7 (fifths) */
			idx = 2;
			break;
		case 24: /* tango accordion */
		case 67: /* tenor sax */
			idx = 3;
			break;
		}
		ret = idx < 0 ? NULL : &tone_inf[idx];
	}
	if(ret_freq) *ret_freq = note_to_freq(note);
	return ret;
}

#define MIDI_CH_N	16
struct ch_rec{
	int vol;
	int pan;
	int bend;
	int rpn;
	int bend_range;
	int prog;
} ch_inf[ MIDI_CH_N ];

#define CH_PROG(ch)	( (ch) == 9 ? 0 : ch_inf[ch].prog )

double
env_out(struct note_rec *nt, double sec)
{
	struct tone_rec *tn;
	struct env_rec *e;
	double v;

	if((tn = tone_get(CH_PROG(nt->ch), nt->note, NULL)) == NULL) return 0;
	e = &tn->env;
	if(nt->onoff){
		sec -= nt->on_sec;
		if(sec < e->attack){
			v = sec / e->attack;
			return log10(1 + v * 9);
		}
		sec -= e->attack;
		if(sec < e->decay){
			v = sec / e->decay;
			v = log10(1 + v * 9);
			return 1 - v * (1 - e->sustain);
		}
		return e->sustain;
	}
	sec -= nt->off_sec;
	if(sec < e->release){
		v = sec / e->release;
		v = log10(1 + v * 9);
		return (1 - v) * nt->off_v;
	}
	return 0;
}

void
modu_out(double v, struct modu_rec *modu, double *ret_arr)
{
	if(modu->pitch1) ret_arr[0] += v * modu->pitch1 * (1.0 / 1200);
	if(modu->pitch2) ret_arr[1] += v * modu->pitch2 * (1.0 / 1200);
	if(modu->filter) ret_arr[2] += v * modu->filter * (1.0 / 1200);
}

double
lfo_out(struct lfo_rec *lfo, struct modu_rec *modu, double sec, double on_sec)
{
	double dsec;

	if(!(modu->pitch1 || modu->pitch2 || modu->filter)) return 0;
	if((dsec = sec - on_sec - lfo->delay) <= 0) return 0;
	return wave_out(lfo->wave, lfo->freq * dsec);
}

double
vco_out(int wave, struct vco_stat_rec *stat, double freq, double sec, double modu_v)
{
	if(modu_v != 0) freq *= pow(2, modu_v);
	vco_stat_update(stat, freq, sec);
	return wave_out(wave, stat->cycle);
}

double
vcf_out(struct lpf_rec *lpf, struct lpf_stat_rec *lpf_stat, struct out_rec *ot, double modu_v, double v)
{
	struct lpf_rec lpf_tmp;

	if(lpf_stat->idx < 0) lpf_init(lpf, lpf_stat, ot);
	if(modu_v != 0){
		lpf_tmp = *lpf;
		lpf_tmp.freq *= pow(2, modu_v);
		lpf_update(&lpf_tmp, lpf_stat, ot);
	}
	return lpf_out(lpf_stat, v);
}

void
delay_buf_set(struct out_rec *ot, struct note_rec *nt, double v, double env_v)
{
	// エンベロープ出力の引数を追加
	
	int i;

	i = (ot->smp_cnt - nt->fst_smp_cnt) % DELAY_BUF_N;
	nt->delay_buf[0][i] = v;
	nt->delay_buf[1][i] = env_v;
	// エンベロープ出力も [1] に記録する
	
}

#define MIX(a, b, rate)		( (a) * (1 - (rate)) + (b) * (rate) )
// 混合用のマクロ定義を追加

double
tbl_lookup(double *tbl, int n, double d_idx)
{
	// リングバッファ参照用
	//
	// tbl はバッファ
	// n はバッファ長
	// d_idx は、バッファの位置 (小数)
	// バッファの位置の値を前後の値から、混合して算出し返す
	
	int i;

	i = (int)d_idx;
	d_idx -= i;
	i %= n;
	return MIX(tbl[i], tbl[(i+1)%n], d_idx);
}

double
delay_buf_lookup(struct out_rec *ot, struct note_rec *nt, double sec, double *ret_env_v)
{
	// エンベロープ出力を返すために、末尾に引数を追加
	// 不要なら NULL を指定する
	// 
	// 追加した tbl_lookup() を使うよう変更
	
	double cycle;

	cycle = ot->smp_freq * sec - nt->fst_smp_cnt;
	if(ret_env_v) *ret_env_v = tbl_lookup(nt->delay_buf[1], DELAY_BUF_N, cycle);
	return tbl_lookup(nt->delay_buf[0], DELAY_BUF_N, cycle);
}

double
delay_out(struct out_rec *ot, struct note_rec *nt, struct delay_rec *delay, double *ret_env_v)
{
	// エンベロープ出力を返すために、末尾に引数を追加
	// 不要なら NULL を指定する
	
	double v;

	if(ot->sec - nt->on_sec < delay->sec) return 0;
	v = delay_buf_lookup(ot, nt, ot->sec - delay->sec, ret_env_v) * delay->gain;
	if(ret_env_v) *ret_env_v *= delay->gain;
	return v;
}

double
chorus_out(struct out_rec *ot, struct note_rec *nt)
{
	double dsec, bak_sec;

	dsec = ot->sec - nt->on_sec;
	bak_sec = 0.01 + 0.001 * sin(2 * M_PI * 0.8 * dsec);
	if(dsec < bak_sec) return 0;
	return delay_buf_lookup(ot, nt, ot->sec - bak_sec, NULL);
	// この処理ではエンベロープ出力は不要なので、NULL を指定
	
}

double
tone_out(struct out_rec *ot, struct note_rec *nt, struct tone_rec *tn, double freq, double env_v)
{
	// 旧note_out() 関数の VCO, VCF, VCA の主要部分を切り出して
	// tone_out() 関数とした
	// エンベロープが 0 に達した後は、この処理は不要で、
	// エフェクタの処理だけすればいい
	
	double v, v1, v2, lfo_v, modu_v[3];
	struct vco_rec *vco;

	lfo_v = lfo_out(&tn->lfo, &tn->lfo_modu, ot->sec, nt->on_sec);

	modu_v[0] = modu_v[1] = modu_v[2] = 0;
	modu_out(lfo_v, &tn->lfo_modu, modu_v);
	modu_out(env_v, &tn->env_modu, modu_v);

	vco = &tn->vco;
	v1 = vco_out(vco->wave1, &nt->vco_stat[0], freq, ot->sec, modu_v[0]);

	modu_v[1] += vco->tune * (1.0 / 1200);
	v2 = vco_out(vco->wave2, &nt->vco_stat[1], freq, ot->sec, modu_v[1]);
	if(vco->ring){
		v = v1 * v2;
		v1 = (v1 + v2) * 0.5;
		v2 = v;
	}
	v = MIX(v1, v2, vco->mix);

	v = vcf_out(&tn->lpf, &nt->lpf_stat, ot, modu_v[2], v);

	v *= env_v * tn->level;
	return v;
}

int
note_out(struct out_rec *ot, struct note_rec *nt, double *vl, double *vr)
{
	// 主要な処理は tone_out() 関数に移動した
	// 最初にエンベロープ出力をみて、主要な処理が必要か
	// 判定するように変更
	
	double v, freq, pan, env_v, d_env_v;
	int nch;
	struct tone_rec *tn;

	nch = nt->ch;
	tn = tone_get(CH_PROG(nch), nt->note, &freq);
	if(tn == NULL) return 0;

	if(nt->fst_smp_cnt < 0) nt->fst_smp_cnt = ot->smp_cnt;

	if(ch_inf[nch].bend != 0) freq *= pow(2, ch_inf[nch].bend * ch_inf[nch].bend_range * (1.0 / (8192 * 12)));

	env_v = env_out(nt, ot->sec);
	v = (env_v > 0) ? tone_out(ot, nt, tn, freq, env_v) : 0;

	d_env_v = 0;
	if(tn->delay.onoff) v += delay_out(ot, nt, &tn->delay, &d_env_v);
	d_env_v += env_v;
	delay_buf_set(ot, nt, v, d_env_v);
	// エンベロープ出力も、ディレイ処理して、リングバッファに記録
	
	if(tn->chorus) v += chorus_out(ot, nt);

	v *= (nt->velo * (1.0 / 127)) * (ch_inf[nch].vol * (1.0 / ((1<<14)-1)));
	if(ot->ch_num == 1){
		*vl += v;
	}else{
		pan = ch_inf[nch].pan * (1.0 / (1<<14));
		*vl += (1 - pan) * v;
		*vr += pan * v;
	}
	return nt->onoff == 0 && ot->sec - nt->off_sec >= tn->env.release &&
		(!tn->delay.onoff || d_env_v < 0.01);
	// 従来のややこしい減衰判定をなくして、
	// ディレイ処理込みのエンベロープ出力結果から、
	// 減衰を判定するように変更
	
}

void
data_out(struct out_rec *ot, double evt_sec)
{
	double vl, vr;
	int i;
	struct note_rec *nt;

	while((ot->sec = ot->smp_t * ot->smp_cnt) < evt_sec){
		vl = vr = 0;
		for(i=0; i<NOTE_BUF_N; i++){
			if(note_buf_is_free(i)) continue;
			nt = &note_buf[i];
			if(note_out(ot, nt, &vl, &vr)) note_buf_free(i);
		}
		out_do(ot, vl * (1.0 / 16));
		if(ot->ch_num > 1) out_do(ot, vr * (1.0 / 16));
		ot->smp_cnt++;
	}
}

void
note_onoff(int onoff, double evt_sec, int ch, int note, int velo)
{
	int i, j;
	struct vco_stat_rec *stat;

	if(onoff){
		if((i = note_buf_search(-1, -1, -1)) < 0){
			MSG("note_buf full");
			return;
		}
		note_buf[i].note = note;
		note_buf[i].ch = ch;
		note_buf[i].onoff = 1;
		note_buf[i].on_sec = evt_sec;
		note_buf[i].velo = velo;
		for(j=0; j<2; j++){
			stat = &note_buf[i].vco_stat[j];
			stat->cycle = 0;
			stat->sec = evt_sec;
		}
		note_buf[i].lpf_stat.idx = -1;
		note_buf[i].fst_smp_cnt = -1;
	}else{
		if((i = note_buf_search(ch, note, 1)) < 0) return;
		note_buf[i].off_v = env_out(&note_buf[i], evt_sec);
		note_buf[i].onoff = 0;
		note_buf[i].off_sec = evt_sec;
	}
}

void
msb_set(int *vp, int v)
{
	*vp &= ~(127<<7);
	*vp |= v<<7;
}

void
lsb_set(int *vp, int v)
{
	*vp &= ~127;
	*vp |= v;
}

void
bend_note_update(int ch, double sec)
{
	int i, j;
	struct note_rec *nt;
	struct vco_stat_rec *stat;

	for(i=0; i<NOTE_BUF_N; i++){
		if(note_buf_is_free(i)) continue;
		nt = &note_buf[i];
		if(nt->ch != ch) continue;
		for(j=0; j<2; j++){
			stat = &nt->vco_stat[j];
			vco_stat_update(stat, stat->freq, sec);
		}
	}
}

int
main(int ac, char **av)
{
	int div4, delta_sum;
	int i, n, v, hi, low, note, velo;
	int ch, type;
	double sec;
	struct out_rec otr;
	int tempo, tempo_delta_sum;
	double tempo_sec;

	out_init(&otr, ac, av);
	note_buf_init();
	for(i=0; i<MIDI_CH_N; i++){
		ch_inf[i].vol = 0;
		ch_inf[i].pan = 1<<(14-1);
		ch_inf[i].bend = 0;
		ch_inf[i].rpn = 0;
		ch_inf[i].bend_range = 2;
		ch_inf[i].prog =-1;
	}
	tempo = 500000;
	tempo_delta_sum = 0;
	tempo_sec = 0;

	div4 = header();

	if(!rd_str_chk(4, "MTrk")) ERR("track id");
	v = rd_int(4); /* skip */

	hi = low = 0;
	delta_sum = 0;
	while((v = rd_delta()) != EOF){
		delta_sum += v;
		sec = tempo_sec + (double)(delta_sum - tempo_delta_sum) / div4 * tempo * 0.000001;
		
		if((v = rd()) & 0x80){
			hi = (v >> 4) & 0xf;
			low  = v & 0xf;
		}else bk(v);

		data_out(&otr, sec);

		ch = low;
		switch(hi){
		case 8:
		case 9:
			note = rd();
			velo = rd();
			note_onoff(hi == 9, sec, ch, note, velo);
			break;
		case 0xb: /* control change */
			type = rd();
			v = rd();
			switch(type){
			case 7: /* channel volume msb */
				msb_set(&ch_inf[ch].vol, v);
				break;
			case 39: /* channel volume lsb */
				lsb_set(&ch_inf[ch].vol, v);
				break;
			case 10: /* pan msb */
				msb_set(&ch_inf[ch].pan, v);
				break;
			case 42: /* pan lsb */
				lsb_set(&ch_inf[ch].pan, v);
				break;
			case 100: /* rpn lsb */
				lsb_set(&ch_inf[ch].rpn, v);
				break;
			case 101: /* rpn msb */
				msb_set(&ch_inf[ch].rpn, v);
				break;
			case 6: /* data entry msb */
				switch(ch_inf[ch].rpn){
				case 0: /* pitch bend range */
					ch_inf[ch].bend_range = v;
					break;
				}
				break;
			}
			break;
		case 0xa:
			rd();
			rd();
			break;
		case 0xe: /* pitch wheel change */
			bend_note_update(ch, sec);
			v = rd();
			v |= rd() << 7;
			ch_inf[ch].bend = v - 8192;
			break;
		case 0xc: /* program number */
			v = rd();
			ch_inf[ch].prog = v;
			break;
		case 0xd:
			rd();
			break;
		case 0xf:
			type = rd();
			switch(low){
			case 0:
				while(rd() != 0xf7);
				break;
			case 1:
			case 3:
				rd();
				break;
			case 2:
				rd();
				rd();
				break;
			case 0xf: /* meta */
				n = rd();
				switch(type){
				case 0x51: /* set tempo */
					v = rd_int(n);
					tempo = v;
					tempo_delta_sum = delta_sum;
					tempo_sec = sec;
					break;
				default:
					for(i=0; i<n; i++) rd();
					break;
				}
				break;
			default:
				break;
			}
			break;
		}
	}
	if(otr.fp != stdout) pclose(otr.fp);
	return 0;
}

/* EOF */


prog21.c 解説

prog20.c からの変更箇所のみ

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <math.h>

#define MSG(s) fprintf(stderr, "%s() %s L%d : %s\n", __func__, __FILE__, __LINE__, s)
#define ERR(s) do{ fprintf(stderr, "ERR "); MSG(s); exit(1); }while(0)

int bk_buf = -1;

int
rd(void)
{
	int v;

	if((v = bk_buf) < 0) return getchar();
	bk_buf = -1;
	return v;
}

void
bk(int v)
{
	if(bk_buf >= 0) ERR("give up");
	bk_buf = v;
}

void
rd_str(int n, char *s)
{
	int i;

	for(i=0; i<n; i++) s[i] = rd();
	s[i] = '\0';
}

int
rd_str_chk(int n, char *s)
{
	char buf[256];

	rd_str(n, buf);
	return strcmp(buf, s) == 0;
}

int
rd_int(int n) /* big endian */
{
	int i, v;

	v = 0;
	for(i=0; i<n; i++) v = (v << 8) | rd();
	return v;
}

int
rd_delta(void)
{
	int v, c;

	v = 0;
	do{
		if((c = rd()) == EOF) return EOF;
		v = (v << 7) | (c & 0x7f);
	}while(c & 0x80);
	return v;
}


int
opt_idx(char *key, int ac, char **av)
{
	int i;

	for(i=1; i<ac; i++) if(strcmp(av[i], key) == 0) return i;
	return -1;
}

char *
opt_str(char *key, int ac, char **av, char *def)
{
	int i;

	i = opt_idx(key, ac, av);
	if(i < 0 || i+1 >= ac) return def;
	return av[i+1];
}

int
opt_int(char *key, int ac, char **av, int def)
{
	char *s;

	if((s = opt_str(key, ac, av, NULL)) == NULL) return def;
	return strtol(s, NULL, 0);
}

struct out_rec{
	int smp_freq, smp_cnt;
	int bit_len;
	int sign;
	int ch_num;
	FILE *fp;

	int base;
	int amp;
	int iv_min;
	int iv_max;
	double smp_t, sec;
};

int
sox_version(void)
{
	FILE *fp;
	int v1, v2, v3;

	if((fp = popen("sox --version | sed -e 's/^.*v//'", "r")) == NULL) return -1;
	fscanf(fp, "%d.%d.%d", &v1, &v2, &v3);
	pclose(fp);
	return v1*10000 + v2*100 + v3;
}

char *
sox_bit_len_fmt(int bit_len)
{
	return sox_version() >= 140400 ? 
		(bit_len == 8 ? "-b 8" : "-b 16") : 
		(bit_len == 8 ? "-b" : "-w");
}

void
out_init(struct out_rec *ot, int ac, char **av)
{
	char cmd[1024], *fn;

	ot->smp_freq = opt_int("-r", ac, av, 44100);
	ot->smp_cnt = 0;
	ot->bit_len = opt_int("-b", ac, av, 16);
	if(ot->bit_len != 8 && ot->bit_len != 16) ERR("bit_len");
	ot->sign = (opt_idx("-u", ac, av) < 0);
	ot->ch_num = opt_int("-c", ac, av, 2);

	ot->fp = stdout;
	cmd[0] = '\0';
	fn = "";
	if(opt_idx("-play", ac, av) >= 0){
		strcat(cmd, "play");
	}else if(opt_idx("-sox", ac, av) >= 0){
		strcat(cmd, "sox");
		fn = opt_str("-sox", ac, av, "-d");
	}
	if(cmd[0]){
		sprintf(cmd + strlen(cmd), " -t raw -r %d %s %s -c %d - %s",
			ot->smp_freq, sox_bit_len_fmt(ot->bit_len),
			ot->sign ? "-s" : "-u",
			ot->ch_num, fn);
		if((ot->fp = popen(cmd, "w")) == NULL) ERR("popen");
	}
	ot->amp = ot->bit_len == 8 ? 127 : 32767;
	ot->base = ot->sign ? 0 : ot->amp + 1;
	ot->iv_min = ot->base - (ot->amp + 1);
	ot->iv_max = ot->base + ot->amp;

	ot->smp_t = 1.0 / ot->smp_freq;
}

void
out_do(struct out_rec *ot, double v)
{
	int iv;

	iv = ot->base + (int)(v * ot->amp);
	if(iv > ot->iv_max) iv = ot->iv_max;
	if(iv < ot->iv_min) iv = ot->iv_min;
	switch(ot->bit_len){
	case 8:
		fputc(iv, ot->fp);
		break;
	case 16:
		fputc(iv & 0xff, ot->fp);
		fputc((iv >> 8) & 0xff, ot->fp);
		break;
	}
}

#define OFF		0
#define ON		1

#define LPF		1
#define HPF		2
#define BPF		3

struct filter_rec{
	int type; /* OFF, LPF, HPF, BPF */
	double freq, Q;
};

struct filter_stat_rec{
	int idx;
	double in[4], out[4];
	double a0, a1, a2, b0, b1, b2, div_a0;
};

void
filter_update(struct filter_rec *fl, struct filter_stat_rec *stat, struct out_rec *ot)
{
	double w0, alpha, cos_w0;

	if(fl->type == OFF) return;

	w0 = 2 * M_PI * fl->freq * ot->smp_t;
	cos_w0 = cos(w0);
	alpha = sin(w0) / (2 * fl->Q);

	switch(fl->type){
	case LPF:
		stat->b1 = 1 - cos_w0;
		stat->b0 = stat->b2 = stat->b1 * 0.5;
		break;
	case HPF:
		stat->b1 = -(1 + cos_w0);
		stat->b0 = stat->b2 = -stat->b1 * 0.5;
		break;
	case BPF:
		stat->b0 = fl->Q * alpha;
		stat->b1 = 0;
		stat->b2 = -stat->b0;
		break;
	}
	stat->a0 = 1 + alpha;
	stat->a1 = -2 * cos_w0;
	stat->a2 = 1 - alpha;
	if(stat->a0 != 0) stat->div_a0 = 1 / stat->a0;
}

void
filter_init(struct filter_rec *fl, struct filter_stat_rec *stat, struct out_rec *ot)
{
	int i;

	for(i=0; i<4; i++) stat->in[i] = stat->out[i] = 0;
	stat->idx = 0;

	filter_update(fl, stat, ot);
}

double
filter_out(struct filter_stat_rec *stat, double in)
{
	double *out_p;
	int i_1, i_2;

	stat->in[stat->idx] = in;
	out_p = &stat->out[stat->idx];

	if(stat->a0 != 0){
		i_1 = (stat->idx + 4 - 1) & 3;
		i_2 = (i_1 + 4 - 1) & 3;
		*out_p = (stat->b0 * in
			+ stat->b1 * stat->in[i_1]
			+ stat->b2 * stat->in[i_2]
			- stat->a1 * stat->out[i_1]
			- stat->a2 * stat->out[i_2] ) * stat->div_a0;
	}else{
		*out_p = 0;
	}
	stat->idx = (stat->idx + 1) & 3;
	return *out_p;
}


#define NOTE_BUF_N	256

struct vco_stat_rec{
	double cycle, freq, sec;
};

void
vco_stat_update(struct vco_stat_rec *stat, double freq, double sec)
{
	stat->cycle += freq * (sec - stat->sec);	
	stat->freq = freq;
	stat->sec = sec;
}

#define DELAY_BUF_N	(44100 * 5 / 10) /* max 0.5 sec */

struct note_rec{
	int ch;
	int note;
	int onoff;
	double on_sec;
	double off_sec;
	int velo;
	struct vco_stat_rec vco_stat[2];
	double off_v;
	struct filter_stat_rec filter_stat[2];
	int fst_smp_cnt;
	double delay_buf[2][ DELAY_BUF_N ];
} note_buf[NOTE_BUF_N];

int
note_buf_is_free(int i)
{
	return note_buf[i].ch < 0;
}

void
note_buf_free(int i)
{
	note_buf[i].ch = -1;
}

void
note_buf_init(void)
{
	int i;

	for(i=0; i<NOTE_BUF_N; i++) note_buf_free(i);
}

int
note_buf_search(int ch, int note, int onoff)
{
	int i;

	for(i=0; i<NOTE_BUF_N; i++) {
		if( (ch < 0 && note_buf[i].ch < 0) ||
		    (note_buf[i].ch == ch &&
		     note_buf[i].note == note &&
		     note_buf[i].onoff == onoff) ) return i;
	}
	return -1;
}

int
header(void)
{
	int v;

	if(!rd_str_chk(4, "MThd")) ERR("header id");
	if(rd_int(4) != 6) ERR("header size");
	if(rd_int(2) != 0) ERR("header format type");
	if(rd_int(2) != 1) ERR("header track num");
	if((v = rd_int(2)) & 0x8000) ERR("header division");
	return v; /* div4 */
}

double
note_to_freq(int note)
{
	return 440 * pow(2, (note - 69) / 12.0);
}

#define WAVE_SIN	0
#define WAVE_SAW	1
#define WAVE_SQUARE	2
#define WAVE_NOISE	3

double
wave_out(int wave, double cycle)
{
	cycle -= (int)cycle;

	switch(wave){
	case WAVE_SIN:
		return sin(2 * M_PI * cycle);
	case WAVE_SAW:
		cycle *= 2;
		if(cycle > 1) cycle -= 2;
		return cycle;
	case WAVE_SQUARE:
		return cycle < 0.5 ? 1 : -1;
	case WAVE_NOISE:
		return ((double)rand() / RAND_MAX) * 2 - 1;
	}
	return 0;
}

struct vco_rec{
	int wave1, wave2;
	int tune; /* for vco2 */
	double mix;
	int ring;
};

struct modu_rec{
	int pitch1, pitch2, filter1, filter2;
};

struct lfo_rec{
	int wave;
	double freq, delay;
};

struct env_rec{
	double attack;	/* sec */
	double decay;	/* sec */
	double sustain;	/* 0..1 */
	double release;	/* sec */
};

struct delay_rec{
	int onoff;
	double sec, gain;
};

struct tone_rec{
	struct vco_rec vco;
	struct filter_rec fl1, fl2;
	struct env_rec env;
	double level;
	struct modu_rec lfo_modu;
	struct lfo_rec lfo;
	struct modu_rec env_modu;
	struct delay_rec delay;
	int chorus;
} tone_inf[] = {
	{	/* strings */
		{ WAVE_SAW, WAVE_SAW, 12, 0.5, OFF },
		{ LPF, 3000, 1.5 }, { OFF, },
		{ 0.15, 0.5, 0.8, 0.5 },
		1.0,
		{ OFF, 12, OFF, OFF }, { WAVE_SIN, 4, 0.3 },
		{ OFF, OFF, OFF, OFF },
		{ OFF, }, ON,
	},{	/* bass */
		{ WAVE_SAW, WAVE_SQUARE, OFF, 0.5, OFF },
		{ LPF, 1000, 1.5 }, { OFF, },
		{ 0.05, 0.2, 0.4, 0.2 },
		1.0,
		{ OFF, 60, OFF, OFF }, { WAVE_SIN, 1.5, 0.2 },
		{ OFF, OFF, OFF, OFF },
		{ OFF, }, ON,
	},{	/* lead */
		{ WAVE_SQUARE, WAVE_SQUARE, 10, 0.5, OFF },
		{ LPF, 2000, 4 }, { OFF, },
		{ 0.01, 0.2, 0.8, 0.3 },
		1.0,
		{ OFF, 1, 5, OFF }, { WAVE_SIN, 4, 0.3 },
		{ OFF, OFF, OFF, OFF },
		{ ON, 0.2, 0.4}, OFF,
	},{	/* SIN */
		{ WAVE_SIN, WAVE_SIN, OFF, 0, OFF },
		{ LPF, 20000, 0.8 }, { OFF, },
		{ 0, 0.3, 0.2, 0.3 },
		1.4,
		{ 25, OFF, OFF, OFF }, { WAVE_SIN, 6, 0.3 },
		{ OFF, OFF, OFF, OFF },
		{ OFF, }, OFF,
	}
}, drum_tone_inf[] = {
	{	/* bass */
		{ WAVE_SIN, WAVE_NOISE, OFF, 0.4, OFF },
		{ LPF, 400, 1 }, { OFF, },
		{ 0.01, 0.18, 0, 0.18 },
		9.0,
		{ 100, OFF, 30, OFF }, { WAVE_NOISE, 0, 0.5 },
		{ OFF, OFF, OFF, OFF },
		{ OFF, }, OFF,
	},{	/* snare */
		{ WAVE_SQUARE, WAVE_NOISE, OFF, 0.8, ON },
		{ LPF, 1500, 1.7 }, { OFF, }, 
		{ 0, 0.4, 0.3, 0.4 },
		5,
		{ OFF, OFF, OFF, OFF }, {},
		{ OFF, OFF, OFF, OFF },
		{ OFF, }, OFF,
	},{	/* tom */
		{ WAVE_SQUARE, WAVE_NOISE, OFF, 0.5, ON },
		{ LPF, 800, 2.5 }, { OFF, },
		{ 0, 0.03, 0.1, 0.4 },
		5,
		{ OFF, OFF, OFF, OFF }, {},
		{ 200, OFF, 1200, OFF },
		{ OFF, }, OFF,
	},{	/* hi-hat close */
		{ WAVE_SQUARE, WAVE_SQUARE, 700, 0.9, ON },
		{ LPF, 16000, 2 }, { OFF, },
		{ 0, 0.15, 0, 0.15 },
		0.6,
		{ OFF, OFF, OFF, OFF }, {},
		{ OFF, OFF, OFF, OFF },
		{ OFF, }, OFF,
	},{	/* hi-hat open */
		{ WAVE_SQUARE, WAVE_SQUARE, 700, 0.9, ON },
		{ LPF, 16000, 2 }, { OFF, },
		{ 0, 0, 1, 0.35 },
		0.6,
		{ OFF, OFF, OFF, OFF }, {},
		{ OFF, OFF, OFF, OFF },
		{ OFF, }, OFF,
	},{	/* cymbal */
		{ WAVE_NOISE, WAVE_SQUARE, OFF, 0.8, ON },
		{ LPF, 4000, 2 }, { OFF, },
		{ 0, 0.01, 0.2, 0.8 },
		9,
		{ OFF, OFF, OFF, OFF }, {},
		{ OFF, OFF, 600, OFF }, 
		{ OFF, }, OFF,
	},{	/* side stick */
		{ WAVE_NOISE, WAVE_SQUARE, OFF, 0.2, OFF },
		{ LPF, 1700, 3 }, { OFF, },
		{ 0, 0.012, 0.1, 0.7 },
		10,
		{ OFF, OFF, OFF, OFF }, {},
		{ OFF, OFF, OFF, OFF },
		{ OFF, }, OFF,
	}
};

struct tone_rec *
tone_get(int prog, int note, double *ret_freq)
{
	int idx;
	struct tone_rec *ret;

	idx = -1;
	if(prog <= 0){ /* drum part */
		switch(note){
		case 36: /* bass drum1 */
			idx = 0;
			note = 28;
			break;
		case 37: /* side stick */
			idx = 6;
			note = 110;
			break;
		case 40: /* electric snare */
			idx = 1;
			note = 69;
			break;
		case 41: /* low floor tom */
			idx = 2;
			note = 50;
			break;
		case 42: /* closed hi-hat */
			idx = 3;
			note = 115 + 8;
			break;
		case 46: /* open hi-hat */
			idx = 4;
			note = 115 + 8;
			break;
		case 49: /* crash cymbal 1 */
			idx = 5;
			note = 75;
			break;
		case 57: /* crash cymbal 2 */
			idx = 5;
			note = 85;
			break;
		}
		ret = idx < 0 ? NULL : &drum_tone_inf[idx];
	}else{
		switch(prog){
		case 48: /* timpani */
		case 50: /* strings ensamble 2 */
			idx = 0;
			break;
		case 35: /* electric bass (pick) */
			idx = 1;
			break;
		case 79: /* whistle */
		case 81: /* lead 1 (square) */
		case 87: /* lead 7 (fifths) */
			idx = 2;
			break;
		case 24: /* tango accordion */
		case 67: /* tenor sax */
			idx = 3;
			break;
		}
		ret = idx < 0 ? NULL : &tone_inf[idx];
	}
	if(ret_freq) *ret_freq = note_to_freq(note);
	return ret;
}

#define MIDI_CH_N	16
struct ch_rec{
	int vol;
	int pan;
	int bend;
	int rpn;
	int bend_range;
	int prog;
} ch_inf[ MIDI_CH_N ];

#define CH_PROG(ch)	( (ch) == 9 ? 0 : ch_inf[ch].prog )

double
env_out(struct note_rec *nt, double sec)
{
	struct tone_rec *tn;
	struct env_rec *e;
	double v;

	if((tn = tone_get(CH_PROG(nt->ch), nt->note, NULL)) == NULL) return 0;
	e = &tn->env;
	if(nt->onoff){
		sec -= nt->on_sec;
		if(sec < e->attack){
			v = sec / e->attack;
			return log10(1 + v * 9);
		}
		sec -= e->attack;
		if(sec < e->decay){
			v = sec / e->decay;
			v = log10(1 + v * 9);
			return 1 - v * (1 - e->sustain);
		}
		return e->sustain;
	}
	sec -= nt->off_sec;
	if(sec < e->release){
		v = sec / e->release;
		v = log10(1 + v * 9);
		return (1 - v) * nt->off_v;
	}
	return 0;
}

void
modu_out(double v, struct modu_rec *modu, double *ret_arr)
{
	if(modu->pitch1) ret_arr[0] += v * modu->pitch1 * (1.0 / 1200);
	if(modu->pitch2) ret_arr[1] += v * modu->pitch2 * (1.0 / 1200);
	if(modu->filter1) ret_arr[2] += v * modu->filter1 * (1.0 / 1200);
	if(modu->filter2) ret_arr[3] += v * modu->filter2 * (1.0 / 1200);
}

double
lfo_out(struct lfo_rec *lfo, struct modu_rec *modu, double sec, double on_sec)
{
	double dsec;

	if(!(modu->pitch1 || modu->pitch2 || modu->filter1 || modu->filter2)) return 0;
	if((dsec = sec - on_sec - lfo->delay) <= 0) return 0;
	return wave_out(lfo->wave, lfo->freq * dsec);
}

double
vco_out(int wave, struct vco_stat_rec *stat, double freq, double sec, double modu_v)
{
	if(modu_v != 0) freq *= pow(2, modu_v);
	vco_stat_update(stat, freq, sec);
	return wave_out(wave, stat->cycle);
}

double
vcf_out(struct filter_rec *fl, struct filter_stat_rec *stat, struct out_rec *ot, double modu_v, double v)
{
	struct filter_rec tmp;

	if(stat->idx < 0) filter_init(fl, stat, ot);
	if(modu_v != 0){
		tmp = *fl;
		tmp.freq *= pow(2, modu_v);
		filter_update(&tmp, stat, ot);
	}
	return filter_out(stat, v);
}

void
delay_buf_set(struct out_rec *ot, struct note_rec *nt, double v, double env_v)
{
	int i;

	i = (ot->smp_cnt - nt->fst_smp_cnt) % DELAY_BUF_N;
	nt->delay_buf[0][i] = v;
	nt->delay_buf[1][i] = env_v;
}

#define MIX(a, b, rate)		( (a) * (1 - (rate)) + (b) * (rate) )

double
tbl_lookup(double *tbl, int n, double d_idx)
{
	int i;

	i = (int)d_idx;
	d_idx -= i;
	i %= n;
	return MIX(tbl[i], tbl[(i+1)%n], d_idx);
}

double
delay_buf_lookup(struct out_rec *ot, struct note_rec *nt, double sec, double *ret_env_v)
{
	double cycle;

	cycle = ot->smp_freq * sec - nt->fst_smp_cnt;
	if(ret_env_v) *ret_env_v = tbl_lookup(nt->delay_buf[1], DELAY_BUF_N, cycle);
	return tbl_lookup(nt->delay_buf[0], DELAY_BUF_N, cycle);
}

double
delay_out(struct out_rec *ot, struct note_rec *nt, struct delay_rec *delay, double *ret_env_v)
{
	double v;

	if(ot->sec - nt->on_sec < delay->sec) return 0;
	v = delay_buf_lookup(ot, nt, ot->sec - delay->sec, ret_env_v) * delay->gain;
	if(ret_env_v) *ret_env_v *= delay->gain;
	return v;
}

double
chorus_out(struct out_rec *ot, struct note_rec *nt)
{
	double dsec, bak_sec;

	dsec = ot->sec - nt->on_sec;
	bak_sec = 0.01 + 0.001 * sin(2 * M_PI * 0.8 * dsec);
	if(dsec < bak_sec) return 0;
	return delay_buf_lookup(ot, nt, ot->sec - bak_sec, NULL);
}

double
tone_out(struct out_rec *ot, struct note_rec *nt, struct tone_rec *tn, double freq, double env_v)
{
	int i;
	double v, v1, v2, lfo_v, modu_v[4];
	struct vco_rec *vco;

	lfo_v = lfo_out(&tn->lfo, &tn->lfo_modu, ot->sec, nt->on_sec);

	for(i=0; i<4; i++) modu_v[i] = 0;
	modu_out(lfo_v, &tn->lfo_modu, modu_v);
	modu_out(env_v, &tn->env_modu, modu_v);

	vco = &tn->vco;
	v1 = vco_out(vco->wave1, &nt->vco_stat[0], freq, ot->sec, modu_v[0]);

	modu_v[1] += vco->tune * (1.0 / 1200);
	v2 = vco_out(vco->wave2, &nt->vco_stat[1], freq, ot->sec, modu_v[1]);
	if(vco->ring){
		v = v1 * v2;
		v1 = (v1 + v2) * 0.5;
		v2 = v;
	}
	v = MIX(v1, v2, vco->mix);

	if(tn->fl1.type != OFF) v = vcf_out(&tn->fl1, &nt->filter_stat[0], ot, modu_v[2], v);
	if(tn->fl2.type != OFF) v = vcf_out(&tn->fl2, &nt->filter_stat[1], ot, modu_v[3], v);

	v *= env_v * tn->level;
	return v;
}

int
note_out(struct out_rec *ot, struct note_rec *nt, double *vl, double *vr)
{
	double v, freq, pan, env_v, d_env_v;
	int nch;
	struct tone_rec *tn;

	nch = nt->ch;
	tn = tone_get(CH_PROG(nch), nt->note, &freq);
	if(tn == NULL) return 0;

	if(nt->fst_smp_cnt < 0) nt->fst_smp_cnt = ot->smp_cnt;

	if(ch_inf[nch].bend != 0) freq *= pow(2, ch_inf[nch].bend * ch_inf[nch].bend_range * (1.0 / (8192 * 12)));

	env_v = env_out(nt, ot->sec);
	v = (env_v > 0) ? tone_out(ot, nt, tn, freq, env_v) : 0;

	d_env_v = 0;
	if(tn->delay.onoff) v += delay_out(ot, nt, &tn->delay, &d_env_v);
	d_env_v += env_v;
	delay_buf_set(ot, nt, v, d_env_v);
	if(tn->chorus) v += chorus_out(ot, nt);

	v *= (nt->velo * (1.0 / 127)) * (ch_inf[nch].vol * (1.0 / ((1<<14)-1)));
	if(ot->ch_num == 1){
		*vl += v;
	}else{
		pan = ch_inf[nch].pan * (1.0 / (1<<14));
		*vl += (1 - pan) * v;
		*vr += pan * v;
	}
	return nt->onoff == 0 && ot->sec - nt->off_sec >= tn->env.release &&
		(!tn->delay.onoff || d_env_v < 0.01);
}

void
data_out(struct out_rec *ot, double evt_sec)
{
	double vl, vr;
	int i;
	struct note_rec *nt;

	while((ot->sec = ot->smp_t * ot->smp_cnt) < evt_sec){
		vl = vr = 0;
		for(i=0; i<NOTE_BUF_N; i++){
			if(note_buf_is_free(i)) continue;
			nt = &note_buf[i];
			if(note_out(ot, nt, &vl, &vr)) note_buf_free(i);
		}
		out_do(ot, vl * (1.0 / 16));
		if(ot->ch_num > 1) out_do(ot, vr * (1.0 / 16));
		ot->smp_cnt++;
	}
}

void
note_onoff(int onoff, double evt_sec, int ch, int note, int velo)
{
	int i, j;
	struct vco_stat_rec *stat;

	if(onoff){
		if((i = note_buf_search(-1, -1, -1)) < 0){
			MSG("note_buf full");
			return;
		}
		note_buf[i].note = note;
		note_buf[i].ch = ch;
		note_buf[i].onoff = 1;
		note_buf[i].on_sec = evt_sec;
		note_buf[i].velo = velo;
		for(j=0; j<2; j++){
			stat = &note_buf[i].vco_stat[j];
			stat->cycle = 0;
			stat->sec = evt_sec;
		}
		for(j=0; j<2; j++){
			note_buf[i].filter_stat[j].idx = -1;
		}
		note_buf[i].fst_smp_cnt = -1;
	}else{
		if((i = note_buf_search(ch, note, 1)) < 0) return;
		note_buf[i].off_v = env_out(&note_buf[i], evt_sec);
		note_buf[i].onoff = 0;
		note_buf[i].off_sec = evt_sec;
	}
}

void
msb_set(int *vp, int v)
{
	*vp &= ~(127<<7);
	*vp |= v<<7;
}

void
lsb_set(int *vp, int v)
{
	*vp &= ~127;
	*vp |= v;
}

void
bend_note_update(int ch, double sec)
{
	int i, j;
	struct note_rec *nt;
	struct vco_stat_rec *stat;

	for(i=0; i<NOTE_BUF_N; i++){
		if(note_buf_is_free(i)) continue;
		nt = &note_buf[i];
		if(nt->ch != ch) continue;
		for(j=0; j<2; j++){
			stat = &nt->vco_stat[j];
			vco_stat_update(stat, stat->freq, sec);
		}
	}
}

int
main(int ac, char **av)
{
	int div4, delta_sum;
	int i, n, v, hi, low, note, velo;
	int ch, type;
	double sec;
	struct out_rec otr;
	int tempo, tempo_delta_sum;
	double tempo_sec;

	out_init(&otr, ac, av);
	note_buf_init();
	for(i=0; i<MIDI_CH_N; i++){
		ch_inf[i].vol = 0;
		ch_inf[i].pan = 1<<(14-1);
		ch_inf[i].bend = 0;
		ch_inf[i].rpn = 0;
		ch_inf[i].bend_range = 2;
		ch_inf[i].prog =-1;
	}
	tempo = 500000;
	tempo_delta_sum = 0;
	tempo_sec = 0;

	div4 = header();

	if(!rd_str_chk(4, "MTrk")) ERR("track id");
	v = rd_int(4); /* skip */

	hi = low = 0;
	delta_sum = 0;
	while((v = rd_delta()) != EOF){
		delta_sum += v;
		sec = tempo_sec + (double)(delta_sum - tempo_delta_sum) / div4 * tempo * 0.000001;
		
		if((v = rd()) & 0x80){
			hi = (v >> 4) & 0xf;
			low  = v & 0xf;
		}else bk(v);

		data_out(&otr, sec);

		ch = low;
		switch(hi){
		case 8:
		case 9:
			note = rd();
			velo = rd();
			note_onoff(hi == 9, sec, ch, note, velo);
			break;
		case 0xb: /* control change */
			type = rd();
			v = rd();
			switch(type){
			case 7: /* channel volume msb */
				msb_set(&ch_inf[ch].vol, v);
				break;
			case 39: /* channel volume lsb */
				lsb_set(&ch_inf[ch].vol, v);
				break;
			case 10: /* pan msb */
				msb_set(&ch_inf[ch].pan, v);
				break;
			case 42: /* pan lsb */
				lsb_set(&ch_inf[ch].pan, v);
				break;
			case 100: /* rpn lsb */
				lsb_set(&ch_inf[ch].rpn, v);
				break;
			case 101: /* rpn msb */
				msb_set(&ch_inf[ch].rpn, v);
				break;
			case 6: /* data entry msb */
				switch(ch_inf[ch].rpn){
				case 0: /* pitch bend range */
					ch_inf[ch].bend_range = v;
					break;
				}
				break;
			}
			break;
		case 0xa:
			rd();
			rd();
			break;
		case 0xe: /* pitch wheel change */
			bend_note_update(ch, sec);
			v = rd();
			v |= rd() << 7;
			ch_inf[ch].bend = v - 8192;
			break;
		case 0xc: /* program number */
			v = rd();
			ch_inf[ch].prog = v;
			break;
		case 0xd:
			rd();
			break;
		case 0xf:
			type = rd();
			switch(low){
			case 0:
				while(rd() != 0xf7);
				break;
			case 1:
			case 3:
				rd();
				break;
			case 2:
				rd();
				rd();
				break;
			case 0xf: /* meta */
				n = rd();
				switch(type){
				case 0x51: /* set tempo */
					v = rd_int(n);
					tempo = v;
					tempo_delta_sum = delta_sum;
					tempo_sec = sec;
					break;
				default:
					for(i=0; i<n; i++) rd();
					break;
				}
				break;
			default:
				break;
			}
			break;
		}
	}
	if(otr.fp != stdout) pclose(otr.fp);
	return 0;
}

/* EOF */


#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <math.h>

#define MSG(s) fprintf(stderr, "%s() %s L%d : %s\n", __func__, __FILE__, __LINE__, s)
#define ERR(s) do{ fprintf(stderr, "ERR "); MSG(s); exit(1); }while(0)

int bk_buf = -1;

int
rd(void)
{
	int v;

	if((v = bk_buf) < 0) return getchar();
	bk_buf = -1;
	return v;
}

void
bk(int v)
{
	if(bk_buf >= 0) ERR("give up");
	bk_buf = v;
}

void
rd_str(int n, char *s)
{
	int i;

	for(i=0; i<n; i++) s[i] = rd();
	s[i] = '\0';
}

int
rd_str_chk(int n, char *s)
{
	char buf[256];

	rd_str(n, buf);
	return strcmp(buf, s) == 0;
}

int
rd_int(int n) /* big endian */
{
	int i, v;

	v = 0;
	for(i=0; i<n; i++) v = (v << 8) | rd();
	return v;
}

int
rd_delta(void)
{
	int v, c;

	v = 0;
	do{
		if((c = rd()) == EOF) return EOF;
		v = (v << 7) | (c & 0x7f);
	}while(c & 0x80);
	return v;
}


int
opt_idx(char *key, int ac, char **av)
{
	int i;

	for(i=1; i<ac; i++) if(strcmp(av[i], key) == 0) return i;
	return -1;
}

char *
opt_str(char *key, int ac, char **av, char *def)
{
	int i;

	i = opt_idx(key, ac, av);
	if(i < 0 || i+1 >= ac) return def;
	return av[i+1];
}

int
opt_int(char *key, int ac, char **av, int def)
{
	char *s;

	if((s = opt_str(key, ac, av, NULL)) == NULL) return def;
	return strtol(s, NULL, 0);
}

struct out_rec{
	int smp_freq, smp_cnt;
	int bit_len;
	int sign;
	int ch_num;
	FILE *fp;

	int base;
	int amp;
	int iv_min;
	int iv_max;
	double smp_t, sec;
};

int
sox_version(void)
{
	// soxコマンドのバージョンを返す
	// 
	// "sox --version" を実行
	// 結果の出力の 'v'以降の文字列を抽出
	//
	// Sox v14.4.0 ならば、整数 140400 を返す
	// Sox v14.0.1 ならば、整数 140001 をす
	
	FILE *fp;
	int v1, v2, v3;

	if((fp = popen("sox --version | sed -e 's/^.*v//'", "r")) == NULL) return -1;
	fscanf(fp, "%d.%d.%d", &v1, &v2, &v3);
	pclose(fp);
	return v1*10000 + v2*100 + v3;
}

char *
sox_bit_len_fmt(int bit_len)
{
	// soxコマンドのビット長の指定文字列を返す
	//
	// soxコマンドのバージョンが 14.4.0 以降ならば
	//  8 bit  "-b 8"
	//  16 bit "-b 16"
	//
	// soxコマンドのバージョンが 14.4.0 以前ならば
	//  8 bit  "-b"
	//  16 bit "-w"
	
	return sox_version() >= 140400 ? 
		(bit_len == 8 ? "-b 8" : "-b 16") : 
		(bit_len == 8 ? "-b" : "-w");
}

void
out_init(struct out_rec *ot, int ac, char **av)
{
	char cmd[1024], *fn;

	ot->smp_freq = opt_int("-r", ac, av, 44100);
	ot->smp_cnt = 0;
	ot->bit_len = opt_int("-b", ac, av, 16);
	if(ot->bit_len != 8 && ot->bit_len != 16) ERR("bit_len");
	ot->sign = (opt_idx("-u", ac, av) < 0);
	ot->ch_num = opt_int("-c", ac, av, 2);

	ot->fp = stdout;
	cmd[0] = '\0';
	fn = "";
	if(opt_idx("-play", ac, av) >= 0){
		strcat(cmd, "play");
	}else if(opt_idx("-sox", ac, av) >= 0){
		strcat(cmd, "sox");
		fn = opt_str("-sox", ac, av, "-d");
	}
	if(cmd[0]){
		
		sprintf(cmd + strlen(cmd), " -t raw -r %d %s %s -c %d - %s",
			ot->smp_freq, sox_bit_len_fmt(ot->bit_len),
			ot->sign ? "-s" : "-u",
			ot->ch_num, fn);
		// ビット長の指定を sox_bit_len_fmt()関数を使うように変更
		
		if((ot->fp = popen(cmd, "w")) == NULL) ERR("popen");
	}
	ot->amp = ot->bit_len == 8 ? 127 : 32767;
	ot->base = ot->sign ? 0 : ot->amp + 1;
	ot->iv_min = ot->base - (ot->amp + 1);
	ot->iv_max = ot->base + ot->amp;

	ot->smp_t = 1.0 / ot->smp_freq;
}

void
out_do(struct out_rec *ot, double v)
{
	int iv;

	iv = ot->base + (int)(v * ot->amp);
	if(iv > ot->iv_max) iv = ot->iv_max;
	if(iv < ot->iv_min) iv = ot->iv_min;
	switch(ot->bit_len){
	case 8:
		fputc(iv, ot->fp);
		break;
	case 16:
		fputc(iv & 0xff, ot->fp);
		fputc((iv >> 8) & 0xff, ot->fp);
		break;
	}
}

#define OFF		0
#define ON		1
// WAVE_xxx 定義の前にあった OFF,ON のマクロを
// この位置に移動

#define LPF		1
#define HPF		2
#define BPF		3
// フィルタの種類の定義を追加
// (low pass, hi pass, band pass)

struct filter_rec{
	int type; /* OFF, LPF, HPF, BPF */
	double freq, Q;
};
// lpf_rec 構造体を改め、
// フィルタの種類を追加して
// filter_rec 構造体に修正

struct filter_stat_rec{
// lpf_stat_rec 構造体の名前を、filter_stat_rec 構造体に変更

	int idx;
	double in[4], out[4];
	double a0, a1, a2, b0, b1, b2, div_a0;
};

void
filter_update(struct filter_rec *fl, struct filter_stat_rec *stat, struct out_rec *ot)
{
	// lpf_update() 関数を、filter_update() 関数に変更
	//
	// LPF だけでなく、HPF, BPF の場合の処理も追加
	
	double w0, alpha, cos_w0;

	if(fl->type == OFF) return;

	w0 = 2 * M_PI * fl->freq * ot->smp_t;
	cos_w0 = cos(w0);
	alpha = sin(w0) / (2 * fl->Q);

	switch(fl->type){
	case LPF:
		stat->b1 = 1 - cos_w0;
		stat->b0 = stat->b2 = stat->b1 * 0.5;
		break;
	case HPF:
		stat->b1 = -(1 + cos_w0);
		stat->b0 = stat->b2 = -stat->b1 * 0.5;
		break;
	case BPF:
		stat->b0 = fl->Q * alpha;
		stat->b1 = 0;
		stat->b2 = -stat->b0;
		break;
	}
	stat->a0 = 1 + alpha;
	stat->a1 = -2 * cos_w0;
	stat->a2 = 1 - alpha;
	if(stat->a0 != 0) stat->div_a0 = 1 / stat->a0;
}

void
filter_init(struct filter_rec *fl, struct filter_stat_rec *stat, struct out_rec *ot)
{
	// lpf_init() 関数を filter_init() 関数に変更
	
	int i;

	for(i=0; i<4; i++) stat->in[i] = stat->out[i] = 0;
	stat->idx = 0;

	filter_update(fl, stat, ot);
	// lpf_update() 呼び出しを、filter_update() に変更
	
}

double
filter_out(struct filter_stat_rec *stat, double in)
{
	// lpf_out() 関数を filter_out() 関数に変更
	
	double *out_p;
	int i_1, i_2;

	stat->in[stat->idx] = in;
	out_p = &stat->out[stat->idx];

	if(stat->a0 != 0){
		i_1 = (stat->idx + 4 - 1) & 3;
		i_2 = (i_1 + 4 - 1) & 3;
		*out_p = (stat->b0 * in
			+ stat->b1 * stat->in[i_1]
			+ stat->b2 * stat->in[i_2]
			- stat->a1 * stat->out[i_1]
			- stat->a2 * stat->out[i_2] ) * stat->div_a0;
	}else{
		*out_p = 0;
	}
	stat->idx = (stat->idx + 1) & 3;
	return *out_p;
}


#define NOTE_BUF_N	256

struct vco_stat_rec{
	double cycle, freq, sec;
};

void
vco_stat_update(struct vco_stat_rec *stat, double freq, double sec)
{
	stat->cycle += freq * (sec - stat->sec);	
	stat->freq = freq;
	stat->sec = sec;
}

#define DELAY_BUF_N	(44100 * 5 / 10) /* max 0.5 sec */

struct note_rec{
	int ch;
	int note;
	int onoff;
	double on_sec;
	double off_sec;
	int velo;
	struct vco_stat_rec vco_stat[2];
	double off_v;
	struct filter_stat_rec filter_stat[2];
	// lpf_stat_rec 構造体を filter_stat_rec 構造体に変更し
	// 配列として 2 個の構造体を保持するように変更
	
	int fst_smp_cnt;
	double delay_buf[2][ DELAY_BUF_N ];
} note_buf[NOTE_BUF_N];

int
note_buf_is_free(int i)
{
	return note_buf[i].ch < 0;
}

void
note_buf_free(int i)
{
	note_buf[i].ch = -1;
}

void
note_buf_init(void)
{
	int i;

	for(i=0; i<NOTE_BUF_N; i++) note_buf_free(i);
}

int
note_buf_search(int ch, int note, int onoff)
{
	int i;

	for(i=0; i<NOTE_BUF_N; i++) {
		if( (ch < 0 && note_buf[i].ch < 0) ||
		    (note_buf[i].ch == ch &&
		     note_buf[i].note == note &&
		     note_buf[i].onoff == onoff) ) return i;
	}
	return -1;
}

int
header(void)
{
	int v;

	if(!rd_str_chk(4, "MThd")) ERR("header id");
	if(rd_int(4) != 6) ERR("header size");
	if(rd_int(2) != 0) ERR("header format type");
	if(rd_int(2) != 1) ERR("header track num");
	if((v = rd_int(2)) & 0x8000) ERR("header division");
	return v; /* div4 */
}

double
note_to_freq(int note)
{
	return 440 * pow(2, (note - 69) / 12.0);
}

#define WAVE_SIN	0
#define WAVE_SAW	1
#define WAVE_SQUARE	2
#define WAVE_NOISE	3

double
wave_out(int wave, double cycle)
{
	cycle -= (int)cycle;

	switch(wave){
	case WAVE_SIN:
		return sin(2 * M_PI * cycle);
	case WAVE_SAW:
		cycle *= 2;
		if(cycle > 1) cycle -= 2;
		return cycle;
	case WAVE_SQUARE:
		return cycle < 0.5 ? 1 : -1;
	case WAVE_NOISE:
		return ((double)rand() / RAND_MAX) * 2 - 1;
	}
	return 0;
}

struct vco_rec{
	int wave1, wave2;
	int tune; /* for vco2 */
	double mix;
	int ring;
};

struct modu_rec{
	int pitch1, pitch2, filter1, filter2;
	// メンバ filter を filter1 に変更し
	// メンバ filter2 を追加
	
};

struct lfo_rec{
	int wave;
	double freq, delay;
};

struct env_rec{
	double attack;	/* sec */
	double decay;	/* sec */
	double sustain;	/* 0..1 */
	double release;	/* sec */
};

struct delay_rec{
	int onoff;
	double sec, gain;
};

struct tone_rec{
	struct vco_rec vco;
	struct filter_rec fl1, fl2;
		// lpf_rec 構造体を filter_rec 構造体に変更し
		// fl1, fl2 として2つの構造体を保持するように変更
		
	struct env_rec env;
	double level;
	struct modu_rec lfo_modu;
	struct lfo_rec lfo;
	struct modu_rec env_modu;
	struct delay_rec delay;
	int chorus;
} tone_inf[] = {
	{	/* strings */
		{ WAVE_SAW, WAVE_SAW, 12, 0.5, OFF },
		{ LPF, 3000, 1.5 }, { OFF, },
		{ 0.15, 0.5, 0.8, 0.5 },
		1.0,
		{ OFF, 12, OFF, OFF }, { WAVE_SIN, 4, 0.3 },
		{ OFF, OFF, OFF, OFF },
		{ OFF, }, ON,
	},{	/* bass */
		{ WAVE_SAW, WAVE_SQUARE, OFF, 0.5, OFF },
		{ LPF, 1000, 1.5 }, { OFF, },
		{ 0.05, 0.2, 0.4, 0.2 },
		1.0,
		{ OFF, 60, OFF, OFF }, { WAVE_SIN, 1.5, 0.2 },
		{ OFF, OFF, OFF, OFF },
		{ OFF, }, ON,
	},{	/* lead */
		{ WAVE_SQUARE, WAVE_SQUARE, 10, 0.5, OFF },
		{ LPF, 2000, 4 }, { OFF, },
		{ 0.01, 0.2, 0.8, 0.3 },
		1.0,
		{ OFF, 1, 5, OFF }, { WAVE_SIN, 4, 0.3 },
		{ OFF, OFF, OFF, OFF },
		{ ON, 0.2, 0.4}, OFF,
	},{	/* SIN */
		{ WAVE_SIN, WAVE_SIN, OFF, 0, OFF },
		{ LPF, 20000, 0.8 }, { OFF, },
		{ 0, 0.3, 0.2, 0.3 },
		1.4,
		{ 25, OFF, OFF, OFF }, { WAVE_SIN, 6, 0.3 },
		{ OFF, OFF, OFF, OFF },
		{ OFF, }, OFF,
	}
}, drum_tone_inf[] = {
	{	/* bass */
		{ WAVE_SIN, WAVE_NOISE, OFF, 0.4, OFF },
		{ LPF, 400, 1 }, { OFF, },
		{ 0.01, 0.18, 0, 0.18 },
		9.0,
		{ 100, OFF, 30, OFF }, { WAVE_NOISE, 0, 0.5 },
		{ OFF, OFF, OFF, OFF },
		{ OFF, }, OFF,
	},{	/* snare */
		{ WAVE_SQUARE, WAVE_NOISE, OFF, 0.8, ON },
		{ LPF, 1500, 1.7 }, { OFF, }, 
		{ 0, 0.4, 0.3, 0.4 },
		5,
		{ OFF, OFF, OFF, OFF }, {},
		{ OFF, OFF, OFF, OFF },
		{ OFF, }, OFF,
	},{	/* tom */
		{ WAVE_SQUARE, WAVE_NOISE, OFF, 0.5, ON },
		{ LPF, 800, 2.5 }, { OFF, },
		{ 0, 0.03, 0.1, 0.4 },
		5,
		{ OFF, OFF, OFF, OFF }, {},
		{ 200, OFF, 1200, OFF },
		{ OFF, }, OFF,
	},{	/* hi-hat close */
		{ WAVE_SQUARE, WAVE_SQUARE, 700, 0.9, ON },
		{ LPF, 16000, 2 }, { OFF, },
		{ 0, 0.15, 0, 0.15 },
		0.6,
		{ OFF, OFF, OFF, OFF }, {},
		{ OFF, OFF, OFF, OFF },
		{ OFF, }, OFF,
	},{	/* hi-hat open */
		{ WAVE_SQUARE, WAVE_SQUARE, 700, 0.9, ON },
		{ LPF, 16000, 2 }, { OFF, },
		{ 0, 0, 1, 0.35 },
		0.6,
		{ OFF, OFF, OFF, OFF }, {},
		{ OFF, OFF, OFF, OFF },
		{ OFF, }, OFF,
	},{	/* cymbal */
		{ WAVE_NOISE, WAVE_SQUARE, OFF, 0.8, ON },
		{ LPF, 4000, 2 }, { OFF, },
		{ 0, 0.01, 0.2, 0.8 },
		9,
		{ OFF, OFF, OFF, OFF }, {},
		{ OFF, OFF, 600, OFF }, 
		{ OFF, }, OFF,
	},{	/* side stick */
		{ WAVE_NOISE, WAVE_SQUARE, OFF, 0.2, OFF },
		{ LPF, 1700, 3 }, { OFF, },
		{ 0, 0.012, 0.1, 0.7 },
		10,
		{ OFF, OFF, OFF, OFF }, {},
		{ OFF, OFF, OFF, OFF },
		{ OFF, }, OFF,
	}
};

struct tone_rec *
tone_get(int prog, int note, double *ret_freq)
{
	int idx;
	struct tone_rec *ret;

	idx = -1;
	if(prog <= 0){ /* drum part */
		switch(note){
		case 36: /* bass drum1 */
			idx = 0;
			note = 28;
			break;
		case 37: /* side stick */
			idx = 6;
			note = 110;
			break;
		case 40: /* electric snare */
			idx = 1;
			note = 69;
			break;
		case 41: /* low floor tom */
			idx = 2;
			note = 50;
			break;
		case 42: /* closed hi-hat */
			idx = 3;
			note = 115 + 8;
			break;
		case 46: /* open hi-hat */
			idx = 4;
			note = 115 + 8;
			break;
		case 49: /* crash cymbal 1 */
			idx = 5;
			note = 75;
			break;
		case 57: /* crash cymbal 2 */
			idx = 5;
			note = 85;
			break;
		}
		ret = idx < 0 ? NULL : &drum_tone_inf[idx];
	}else{
		switch(prog){
		case 48: /* timpani */
		case 50: /* strings ensamble 2 */
			idx = 0;
			break;
		case 35: /* electric bass (pick) */
			idx = 1;
			break;
		case 79: /* whistle */
		case 81: /* lead 1 (square) */
		case 87: /* lead 7 (fifths) */
			idx = 2;
			break;
		case 24: /* tango accordion */
		case 67: /* tenor sax */
			idx = 3;
			break;
		}
		ret = idx < 0 ? NULL : &tone_inf[idx];
	}
	if(ret_freq) *ret_freq = note_to_freq(note);
	return ret;
}

#define MIDI_CH_N	16
struct ch_rec{
	int vol;
	int pan;
	int bend;
	int rpn;
	int bend_range;
	int prog;
} ch_inf[ MIDI_CH_N ];

#define CH_PROG(ch)	( (ch) == 9 ? 0 : ch_inf[ch].prog )

double
env_out(struct note_rec *nt, double sec)
{
	struct tone_rec *tn;
	struct env_rec *e;
	double v;

	if((tn = tone_get(CH_PROG(nt->ch), nt->note, NULL)) == NULL) return 0;
	e = &tn->env;
	if(nt->onoff){
		sec -= nt->on_sec;
		if(sec < e->attack){
			v = sec / e->attack;
			return log10(1 + v * 9);
		}
		sec -= e->attack;
		if(sec < e->decay){
			v = sec / e->decay;
			v = log10(1 + v * 9);
			return 1 - v * (1 - e->sustain);
		}
		return e->sustain;
	}
	sec -= nt->off_sec;
	if(sec < e->release){
		v = sec / e->release;
		v = log10(1 + v * 9);
		return (1 - v) * nt->off_v;
	}
	return 0;
}

void
modu_out(double v, struct modu_rec *modu, double *ret_arr)
{
	if(modu->pitch1) ret_arr[0] += v * modu->pitch1 * (1.0 / 1200);
	if(modu->pitch2) ret_arr[1] += v * modu->pitch2 * (1.0 / 1200);
	if(modu->filter1) ret_arr[2] += v * modu->filter1 * (1.0 / 1200);
	if(modu->filter2) ret_arr[3] += v * modu->filter2 * (1.0 / 1200);
	// filter を filter1 に変更し
	// filter2 の処理を追加
	
}

double
lfo_out(struct lfo_rec *lfo, struct modu_rec *modu, double sec, double on_sec)
{
	double dsec;

	if(!(modu->pitch1 || modu->pitch2 || modu->filter1 || modu->filter2)) return 0;
	// filter を filter1 に変更し
	// filter2 の判定を追加
	
	if((dsec = sec - on_sec - lfo->delay) <= 0) return 0;
	return wave_out(lfo->wave, lfo->freq * dsec);
}

double
vco_out(int wave, struct vco_stat_rec *stat, double freq, double sec, double modu_v)
{
	if(modu_v != 0) freq *= pow(2, modu_v);
	vco_stat_update(stat, freq, sec);
	return wave_out(wave, stat->cycle);
}

double
vcf_out(struct filter_rec *fl, struct filter_stat_rec *stat, struct out_rec *ot, double modu_v, double v)
{
	// 構造体の変更に追従して変更
	// lpf_xxx --> filter_xxx
	//
	// 関数名の変更に追従して変更
	// lpf_xxx() --> filter_xxx()
	
	struct filter_rec tmp;

	if(stat->idx < 0) filter_init(fl, stat, ot);
	if(modu_v != 0){
		tmp = *fl;
		tmp.freq *= pow(2, modu_v);
		filter_update(&tmp, stat, ot);
	}
	return filter_out(stat, v);
}

void
delay_buf_set(struct out_rec *ot, struct note_rec *nt, double v, double env_v)
{
	int i;

	i = (ot->smp_cnt - nt->fst_smp_cnt) % DELAY_BUF_N;
	nt->delay_buf[0][i] = v;
	nt->delay_buf[1][i] = env_v;
}

#define MIX(a, b, rate)		( (a) * (1 - (rate)) + (b) * (rate) )

double
tbl_lookup(double *tbl, int n, double d_idx)
{
	int i;

	i = (int)d_idx;
	d_idx -= i;
	i %= n;
	return MIX(tbl[i], tbl[(i+1)%n], d_idx);
}

double
delay_buf_lookup(struct out_rec *ot, struct note_rec *nt, double sec, double *ret_env_v)
{
	double cycle;

	cycle = ot->smp_freq * sec - nt->fst_smp_cnt;
	if(ret_env_v) *ret_env_v = tbl_lookup(nt->delay_buf[1], DELAY_BUF_N, cycle);
	return tbl_lookup(nt->delay_buf[0], DELAY_BUF_N, cycle);
}

double
delay_out(struct out_rec *ot, struct note_rec *nt, struct delay_rec *delay, double *ret_env_v)
{
	double v;

	if(ot->sec - nt->on_sec < delay->sec) return 0;
	v = delay_buf_lookup(ot, nt, ot->sec - delay->sec, ret_env_v) * delay->gain;
	if(ret_env_v) *ret_env_v *= delay->gain;
	return v;
}

double
chorus_out(struct out_rec *ot, struct note_rec *nt)
{
	double dsec, bak_sec;

	dsec = ot->sec - nt->on_sec;
	bak_sec = 0.01 + 0.001 * sin(2 * M_PI * 0.8 * dsec);
	if(dsec < bak_sec) return 0;
	return delay_buf_lookup(ot, nt, ot->sec - bak_sec, NULL);
}

double
tone_out(struct out_rec *ot, struct note_rec *nt, struct tone_rec *tn, double freq, double env_v)
{
	int i;
	double v, v1, v2, lfo_v, modu_v[4];
	// modu_v[3] から modu_v[4] に変更 (filter2 追加分)
	
	struct vco_rec *vco;

	lfo_v = lfo_out(&tn->lfo, &tn->lfo_modu, ot->sec, nt->on_sec);

	for(i=0; i<4; i++) modu_v[i] = 0;
	modu_out(lfo_v, &tn->lfo_modu, modu_v);
	modu_out(env_v, &tn->env_modu, modu_v);

	vco = &tn->vco;
	v1 = vco_out(vco->wave1, &nt->vco_stat[0], freq, ot->sec, modu_v[0]);

	modu_v[1] += vco->tune * (1.0 / 1200);
	v2 = vco_out(vco->wave2, &nt->vco_stat[1], freq, ot->sec, modu_v[1]);
	if(vco->ring){
		v = v1 * v2;
		v1 = (v1 + v2) * 0.5;
		v2 = v;
	}
	v = MIX(v1, v2, vco->mix);

	if(tn->fl1.type != OFF) v = vcf_out(&tn->fl1, &nt->filter_stat[0], ot, modu_v[2], v);
	if(tn->fl2.type != OFF) v = vcf_out(&tn->fl2, &nt->filter_stat[1], ot, modu_v[3], v);
	// lpf のための vcf_out() 呼び出してた箇所を、
	// 2つの filter の処理のために vcf_out() を 2回呼び出すように
	// 変更
	
	v *= env_v * tn->level;
	return v;
}

int
note_out(struct out_rec *ot, struct note_rec *nt, double *vl, double *vr)
{
	double v, freq, pan, env_v, d_env_v;
	int nch;
	struct tone_rec *tn;

	nch = nt->ch;
	tn = tone_get(CH_PROG(nch), nt->note, &freq);
	if(tn == NULL) return 0;

	if(nt->fst_smp_cnt < 0) nt->fst_smp_cnt = ot->smp_cnt;

	if(ch_inf[nch].bend != 0) freq *= pow(2, ch_inf[nch].bend * ch_inf[nch].bend_range * (1.0 / (8192 * 12)));

	env_v = env_out(nt, ot->sec);
	v = (env_v > 0) ? tone_out(ot, nt, tn, freq, env_v) : 0;

	d_env_v = 0;
	if(tn->delay.onoff) v += delay_out(ot, nt, &tn->delay, &d_env_v);
	d_env_v += env_v;
	delay_buf_set(ot, nt, v, d_env_v);
	if(tn->chorus) v += chorus_out(ot, nt);

	v *= (nt->velo * (1.0 / 127)) * (ch_inf[nch].vol * (1.0 / ((1<<14)-1)));
	if(ot->ch_num == 1){
		*vl += v;
	}else{
		pan = ch_inf[nch].pan * (1.0 / (1<<14));
		*vl += (1 - pan) * v;
		*vr += pan * v;
	}
	return nt->onoff == 0 && ot->sec - nt->off_sec >= tn->env.release &&
		(!tn->delay.onoff || d_env_v < 0.01);
}

void
data_out(struct out_rec *ot, double evt_sec)
{
	double vl, vr;
	int i;
	struct note_rec *nt;

	while((ot->sec = ot->smp_t * ot->smp_cnt) < evt_sec){
		vl = vr = 0;
		for(i=0; i<NOTE_BUF_N; i++){
			if(note_buf_is_free(i)) continue;
			nt = &note_buf[i];
			if(note_out(ot, nt, &vl, &vr)) note_buf_free(i);
		}
		out_do(ot, vl * (1.0 / 16));
		if(ot->ch_num > 1) out_do(ot, vr * (1.0 / 16));
		ot->smp_cnt++;
	}
}

void
note_onoff(int onoff, double evt_sec, int ch, int note, int velo)
{
	int i, j;
	struct vco_stat_rec *stat;

	if(onoff){
		if((i = note_buf_search(-1, -1, -1)) < 0){
			MSG("note_buf full");
			return;
		}
		note_buf[i].note = note;
		note_buf[i].ch = ch;
		note_buf[i].onoff = 1;
		note_buf[i].on_sec = evt_sec;
		note_buf[i].velo = velo;
		for(j=0; j<2; j++){
			stat = &note_buf[i].vco_stat[j];
			stat->cycle = 0;
			stat->sec = evt_sec;
		}
		for(j=0; j<2; j++){
			note_buf[i].filter_stat[j].idx = -1;
		}
		// lpf_stat_rec 構造体の初期化処理を、
		// filter_stat_rec 構造体の初期化処理に変更
		// (lpf 1つから filter 2つ分に)
		
		note_buf[i].fst_smp_cnt = -1;
	}else{
		if((i = note_buf_search(ch, note, 1)) < 0) return;
		note_buf[i].off_v = env_out(&note_buf[i], evt_sec);
		note_buf[i].onoff = 0;
		note_buf[i].off_sec = evt_sec;
	}
}

void
msb_set(int *vp, int v)
{
	*vp &= ~(127<<7);
	*vp |= v<<7;
}

void
lsb_set(int *vp, int v)
{
	*vp &= ~127;
	*vp |= v;
}

void
bend_note_update(int ch, double sec)
{
	int i, j;
	struct note_rec *nt;
	struct vco_stat_rec *stat;

	for(i=0; i<NOTE_BUF_N; i++){
		if(note_buf_is_free(i)) continue;
		nt = &note_buf[i];
		if(nt->ch != ch) continue;
		for(j=0; j<2; j++){
			stat = &nt->vco_stat[j];
			vco_stat_update(stat, stat->freq, sec);
		}
	}
}

int
main(int ac, char **av)
{
	int div4, delta_sum;
	int i, n, v, hi, low, note, velo;
	int ch, type;
	double sec;
	struct out_rec otr;
	int tempo, tempo_delta_sum;
	double tempo_sec;

	out_init(&otr, ac, av);
	note_buf_init();
	for(i=0; i<MIDI_CH_N; i++){
		ch_inf[i].vol = 0;
		ch_inf[i].pan = 1<<(14-1);
		ch_inf[i].bend = 0;
		ch_inf[i].rpn = 0;
		ch_inf[i].bend_range = 2;
		ch_inf[i].prog =-1;
	}
	tempo = 500000;
	tempo_delta_sum = 0;
	tempo_sec = 0;

	div4 = header();

	if(!rd_str_chk(4, "MTrk")) ERR("track id");
	v = rd_int(4); /* skip */

	hi = low = 0;
	delta_sum = 0;
	while((v = rd_delta()) != EOF){
		delta_sum += v;
		sec = tempo_sec + (double)(delta_sum - tempo_delta_sum) / div4 * tempo * 0.000001;
		
		if((v = rd()) & 0x80){
			hi = (v >> 4) & 0xf;
			low  = v & 0xf;
		}else bk(v);

		data_out(&otr, sec);

		ch = low;
		switch(hi){
		case 8:
		case 9:
			note = rd();
			velo = rd();
			note_onoff(hi == 9, sec, ch, note, velo);
			break;
		case 0xb: /* control change */
			type = rd();
			v = rd();
			switch(type){
			case 7: /* channel volume msb */
				msb_set(&ch_inf[ch].vol, v);
				break;
			case 39: /* channel volume lsb */
				lsb_set(&ch_inf[ch].vol, v);
				break;
			case 10: /* pan msb */
				msb_set(&ch_inf[ch].pan, v);
				break;
			case 42: /* pan lsb */
				lsb_set(&ch_inf[ch].pan, v);
				break;
			case 100: /* rpn lsb */
				lsb_set(&ch_inf[ch].rpn, v);
				break;
			case 101: /* rpn msb */
				msb_set(&ch_inf[ch].rpn, v);
				break;
			case 6: /* data entry msb */
				switch(ch_inf[ch].rpn){
				case 0: /* pitch bend range */
					ch_inf[ch].bend_range = v;
					break;
				}
				break;
			}
			break;
		case 0xa:
			rd();
			rd();
			break;
		case 0xe: /* pitch wheel change */
			bend_note_update(ch, sec);
			v = rd();
			v |= rd() << 7;
			ch_inf[ch].bend = v - 8192;
			break;
		case 0xc: /* program number */
			v = rd();
			ch_inf[ch].prog = v;
			break;
		case 0xd:
			rd();
			break;
		case 0xf:
			type = rd();
			switch(low){
			case 0:
				while(rd() != 0xf7);
				break;
			case 1:
			case 3:
				rd();
				break;
			case 2:
				rd();
				rd();
				break;
			case 0xf: /* meta */
				n = rd();
				switch(type){
				case 0x51: /* set tempo */
					v = rd_int(n);
					tempo = v;
					tempo_delta_sum = delta_sum;
					tempo_sec = sec;
					break;
				default:
					for(i=0; i<n; i++) rd();
					break;
				}
				break;
			default:
				break;
			}
			break;
		}
	}
	if(otr.fp != stdout) pclose(otr.fp);
	return 0;
}

/* EOF */


prog22.c 解説

prog21.c からの変更箇所のみ

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <math.h>

#define MSG(s) fprintf(stderr, "%s() %s L%d : %s\n", __func__, __FILE__, __LINE__, s)
#define ERR(s) do{ fprintf(stderr, "ERR "); MSG(s); exit(1); }while(0)

int bk_buf = -1;

int
rd(void)
{
	int v;

	if((v = bk_buf) < 0) return getchar();
	bk_buf = -1;
	return v;
}

void
bk(int v)
{
	if(bk_buf >= 0) ERR("give up");
	bk_buf = v;
}

void
rd_str(int n, char *s)
{
	int i;

	for(i=0; i<n; i++) s[i] = rd();
	s[i] = '\0';
}

int
rd_str_chk(int n, char *s)
{
	char buf[256];

	rd_str(n, buf);
	return strcmp(buf, s) == 0;
}

int
rd_int(int n) /* big endian */
{
	int i, v;

	v = 0;
	for(i=0; i<n; i++) v = (v << 8) | rd();
	return v;
}

int
rd_delta(void)
{
	int v, c;

	v = 0;
	do{
		if((c = rd()) == EOF) return EOF;
		v = (v << 7) | (c & 0x7f);
	}while(c & 0x80);
	return v;
}


int
opt_idx(char *key, int ac, char **av)
{
	int i;

	for(i=1; i<ac; i++) if(strcmp(av[i], key) == 0) return i;
	return -1;
}

char *
opt_str(char *key, int ac, char **av, char *def)
{
	int i;

	i = opt_idx(key, ac, av);
	if(i < 0 || i+1 >= ac) return def;
	return av[i+1];
}

int
opt_int(char *key, int ac, char **av, int def)
{
	char *s;

	if((s = opt_str(key, ac, av, NULL)) == NULL) return def;
	return strtol(s, NULL, 0);
}

struct out_rec{
	int smp_freq, smp_cnt;
	int bit_len;
	int sign;
	int ch_num;
	FILE *fp;

	int base;
	int amp;
	int iv_min;
	int iv_max;
	double smp_t, sec;
};

int
sox_version(void)
{
	FILE *fp;
	int v1, v2, v3;

	if((fp = popen("sox --version | sed -e 's/^.*v//'", "r")) == NULL) return -1;
	fscanf(fp, "%d.%d.%d", &v1, &v2, &v3);
	pclose(fp);
	return v1*10000 + v2*100 + v3;
}

char *
sox_bit_len_fmt(int bit_len)
{
	return sox_version() >= 140400 ? 
		(bit_len == 8 ? "-b 8" : "-b 16") : 
		(bit_len == 8 ? "-b" : "-w");
}

void
out_init(struct out_rec *ot, int ac, char **av)
{
	char cmd[1024], *fn;

	ot->smp_freq = opt_int("-r", ac, av, 44100);
	ot->smp_cnt = 0;
	ot->bit_len = opt_int("-b", ac, av, 16);
	if(ot->bit_len != 8 && ot->bit_len != 16) ERR("bit_len");
	ot->sign = (opt_idx("-u", ac, av) < 0);
	ot->ch_num = opt_int("-c", ac, av, 2);

	ot->fp = stdout;
	cmd[0] = '\0';
	fn = "";
	if(opt_idx("-play", ac, av) >= 0){
		strcat(cmd, "play");
	}else if(opt_idx("-sox", ac, av) >= 0){
		strcat(cmd, "sox");
		fn = opt_str("-sox", ac, av, "-d");
	}
	if(cmd[0]){
		sprintf(cmd + strlen(cmd), " -t raw -r %d %s %s -c %d - %s",
			ot->smp_freq, sox_bit_len_fmt(ot->bit_len),
			ot->sign ? "-s" : "-u",
			ot->ch_num, fn);
		if((ot->fp = popen(cmd, "w")) == NULL) ERR("popen");
	}
	ot->amp = ot->bit_len == 8 ? 127 : 32767;
	ot->base = ot->sign ? 0 : ot->amp + 1;
	ot->iv_min = ot->base - (ot->amp + 1);
	ot->iv_max = ot->base + ot->amp;

	ot->smp_t = 1.0 / ot->smp_freq;
}

void
out_do(struct out_rec *ot, double v)
{
	int iv;

	iv = ot->base + (int)(v * ot->amp);
	if(iv > ot->iv_max) iv = ot->iv_max;
	if(iv < ot->iv_min) iv = ot->iv_min;
	switch(ot->bit_len){
	case 8:
		fputc(iv, ot->fp);
		break;
	case 16:
		fputc(iv & 0xff, ot->fp);
		fputc((iv >> 8) & 0xff, ot->fp);
		break;
	}
}

#define OFF		0
#define ON		1

#define LPF		1
#define HPF		2
#define BPF		3

struct filter_rec{
	int type; /* OFF, LPF, HPF, BPF */
	double freq, Q;
};

struct filter_stat_rec{
	int idx;
	double in[4], out[4];
	double a0, a1, a2, b0, b1, b2, div_a0;
};

void
filter_update(struct filter_rec *fl, struct filter_stat_rec *stat, struct out_rec *ot)
{
	double w0, alpha, cos_w0;

	if(fl->type == OFF) return;

	w0 = 2 * M_PI * fl->freq * ot->smp_t;
	cos_w0 = cos(w0);
	alpha = sin(w0) / (2 * fl->Q);

	switch(fl->type){
	case LPF:
		stat->b1 = 1 - cos_w0;
		stat->b0 = stat->b2 = stat->b1 * 0.5;
		break;
	case HPF:
		stat->b1 = -(1 + cos_w0);
		stat->b0 = stat->b2 = -stat->b1 * 0.5;
		break;
	case BPF:
		stat->b0 = fl->Q * alpha;
		stat->b1 = 0;
		stat->b2 = -stat->b0;
		break;
	}
	stat->a0 = 1 + alpha;
	stat->a1 = -2 * cos_w0;
	stat->a2 = 1 - alpha;
	if(stat->a0 != 0) stat->div_a0 = 1 / stat->a0;
}

void
filter_init(struct filter_rec *fl, struct filter_stat_rec *stat, struct out_rec *ot)
{
	int i;

	for(i=0; i<4; i++) stat->in[i] = stat->out[i] = 0;
	stat->idx = 0;

	filter_update(fl, stat, ot);
}

double
filter_out(struct filter_stat_rec *stat, double in)
{
	double *out_p;
	int i_1, i_2;

	stat->in[stat->idx] = in;
	out_p = &stat->out[stat->idx];

	if(stat->a0 != 0){
		i_1 = (stat->idx + 4 - 1) & 3;
		i_2 = (i_1 + 4 - 1) & 3;
		*out_p = (stat->b0 * in
			+ stat->b1 * stat->in[i_1]
			+ stat->b2 * stat->in[i_2]
			- stat->a1 * stat->out[i_1]
			- stat->a2 * stat->out[i_2] ) * stat->div_a0;
	}else{
		*out_p = 0;
	}
	stat->idx = (stat->idx + 1) & 3;
	return *out_p;
}


#define NOTE_BUF_N	256

struct vco_stat_rec{
	double cycle, freq, sec;
};

void
vco_stat_update(struct vco_stat_rec *stat, double freq, double sec)
{
	stat->cycle += freq * (sec - stat->sec);	
	stat->freq = freq;
	stat->sec = sec;
}

#define DELAY_BUF_N	(44100 * 5 / 10) /* max 0.5 sec */

struct stat_rec{
	struct vco_stat_rec vco[2];
	struct filter_stat_rec filter[2];
	double off_v;
	int fst_smp_cnt;
	double delay_buf[2][ DELAY_BUF_N ];
};

void
stat_init(struct stat_rec *stat, double sec)
{
	int i;
	struct vco_stat_rec *vco;

	for(i=0; i<2; i++){
		vco = &stat->vco[i];
		vco->cycle = 0;
		vco->sec = sec;
	}
	for(i=0; i<2; i++){
		stat->filter[i].idx = -1;
	}
	stat->fst_smp_cnt = -1;
}

struct note_rec{
	int ch;
	int note;
	int onoff;
	double on_sec;
	double off_sec;
	int velo;

	struct stat_rec stat;
} note_buf[NOTE_BUF_N];

int
note_buf_is_free(int i)
{
	return note_buf[i].ch < 0;
}

void
note_buf_free(int i)
{
	note_buf[i].ch = -1;
}

void
note_buf_init(void)
{
	int i;

	for(i=0; i<NOTE_BUF_N; i++) note_buf_free(i);
}

int
note_buf_search(int ch, int note, int onoff)
{
	int i;

	for(i=0; i<NOTE_BUF_N; i++) {
		if( (ch < 0 && note_buf[i].ch < 0) ||
		    (note_buf[i].ch == ch &&
		     note_buf[i].note == note &&
		     note_buf[i].onoff == onoff) ) return i;
	}
	return -1;
}

int
header(void)
{
	int v;

	if(!rd_str_chk(4, "MThd")) ERR("header id");
	if(rd_int(4) != 6) ERR("header size");
	if(rd_int(2) != 0) ERR("header format type");
	if(rd_int(2) != 1) ERR("header track num");
	if((v = rd_int(2)) & 0x8000) ERR("header division");
	return v; /* div4 */
}

double
note_to_freq(int note)
{
	return 440 * pow(2, (note - 69) / 12.0);
}

#define WAVE_SIN	0
#define WAVE_SAW	1
#define WAVE_SQUARE	2
#define WAVE_NOISE	3

double
wave_out(int wave, double cycle)
{
	cycle -= (int)cycle;

	switch(wave){
	case WAVE_SIN:
		return sin(2 * M_PI * cycle);
	case WAVE_SAW:
		cycle *= 2;
		if(cycle > 1) cycle -= 2;
		return cycle;
	case WAVE_SQUARE:
		return cycle < 0.5 ? 1 : -1;
	case WAVE_NOISE:
		return ((double)rand() / RAND_MAX) * 2 - 1;
	}
	return 0;
}

struct vco_rec{
	int wave1, wave2;
	int tune; /* for vco2 */
	double mix;
	int ring;
};

struct modu_rec{
	int pitch1, pitch2, filter1, filter2;
};

struct lfo_rec{
	int wave;
	double freq, delay;
};

struct env_rec{
	double attack;	/* sec */
	double decay;	/* sec */
	double sustain;	/* 0..1 */
	double release;	/* sec */
};

struct delay_rec{
	int onoff;
	double sec, gain;
};

struct tone_rec{
	struct vco_rec vco;
	struct filter_rec fl1, fl2;
	struct env_rec env;
	double level;
	struct modu_rec lfo_modu;
	struct lfo_rec lfo;
	struct modu_rec env_modu;
	struct delay_rec delay;
	int chorus;
} tone_inf[] = {
	{	/* strings */
		{ WAVE_SAW, WAVE_SAW, 12, 0.5, OFF },
		{ LPF, 3000, 1.5 }, { OFF, },
		{ 0.15, 0.5, 0.8, 0.5 },
		1.0,
		{ OFF, 12, OFF, OFF }, { WAVE_SIN, 4, 0.3 },
		{ OFF, OFF, OFF, OFF },
		{ OFF, }, ON,
	},{	/* bass */
		{ WAVE_SAW, WAVE_SQUARE, OFF, 0.5, OFF },
		{ LPF, 1000, 1.5 }, { OFF, },
		{ 0.05, 0.2, 0.4, 0.2 },
		1.0,
		{ OFF, 60, OFF, OFF }, { WAVE_SIN, 1.5, 0.2 },
		{ OFF, OFF, OFF, OFF },
		{ OFF, }, ON,
	},{	/* lead */
		{ WAVE_SQUARE, WAVE_SQUARE, 10, 0.5, OFF },
		{ LPF, 2000, 4 }, { OFF, },
		{ 0.01, 0.2, 0.8, 0.3 },
		1.0,
		{ OFF, 1, 5, OFF }, { WAVE_SIN, 4, 0.3 },
		{ OFF, OFF, OFF, OFF },
		{ ON, 0.2, 0.4}, OFF,
	},{	/* SIN */
		{ WAVE_SIN, WAVE_SIN, OFF, 0, OFF },
		{ LPF, 20000, 0.8 }, { OFF, },
		{ 0, 0.3, 0.2, 0.3 },
		1.4,
		{ 25, OFF, OFF, OFF }, { WAVE_SIN, 6, 0.3 },
		{ OFF, OFF, OFF, OFF },
		{ OFF, }, OFF,
	}
}, drum_tone_inf[] = {
	{	/* bass */
		{ WAVE_SIN, WAVE_NOISE, OFF, 0.4, OFF },
		{ LPF, 400, 1 }, { OFF, },
		{ 0.01, 0.18, 0, 0.18 },
		9.0,
		{ 100, OFF, 30, OFF }, { WAVE_NOISE, 0, 0.5 },
		{ OFF, OFF, OFF, OFF },
		{ OFF, }, OFF,
	},{	/* snare */
		{ WAVE_SQUARE, WAVE_NOISE, OFF, 0.8, ON },
		{ LPF, 1500, 1.7 }, { OFF, }, 
		{ 0, 0.4, 0.3, 0.4 },
		5,
		{ OFF, OFF, OFF, OFF }, {},
		{ OFF, OFF, OFF, OFF },
		{ OFF, }, OFF,
	},{	/* tom */
		{ WAVE_SQUARE, WAVE_NOISE, OFF, 0.5, ON },
		{ LPF, 800, 2.5 }, { OFF, },
		{ 0, 0.03, 0.1, 0.4 },
		5,
		{ OFF, OFF, OFF, OFF }, {},
		{ 200, OFF, 1200, OFF },
		{ OFF, }, OFF,
	},{	/* hi-hat close */
		{ WAVE_SQUARE, WAVE_SQUARE, 700, 0.9, ON },
		{ LPF, 16000, 2 }, { OFF, },
		{ 0, 0.15, 0, 0.15 },
		0.6,
		{ OFF, OFF, OFF, OFF }, {},
		{ OFF, OFF, OFF, OFF },
		{ OFF, }, OFF,
	},{	/* hi-hat open */
		{ WAVE_SQUARE, WAVE_SQUARE, 700, 0.9, ON },
		{ LPF, 16000, 2 }, { OFF, },
		{ 0, 0, 1, 0.35 },
		0.6,
		{ OFF, OFF, OFF, OFF }, {},
		{ OFF, OFF, OFF, OFF },
		{ OFF, }, OFF,
	},{	/* cymbal */
		{ WAVE_NOISE, WAVE_SQUARE, OFF, 0.8, ON },
		{ LPF, 4000, 2 }, { OFF, },
		{ 0, 0.01, 0.2, 0.8 },
		9,
		{ OFF, OFF, OFF, OFF }, {},
		{ OFF, OFF, 600, OFF }, 
		{ OFF, }, OFF,
	},{	/* side stick */
		{ WAVE_NOISE, WAVE_SQUARE, OFF, 0.2, OFF },
		{ LPF, 1700, 3 }, { OFF, },
		{ 0, 0.012, 0.1, 0.7 },
		10,
		{ OFF, OFF, OFF, OFF }, {},
		{ OFF, OFF, OFF, OFF },
		{ OFF, }, OFF,
	}
};

struct tone_rec *
tone_get(int prog, int note, double *ret_freq)
{
	int idx;
	struct tone_rec *ret;

	idx = -1;
	if(prog <= 0){ /* drum part */
		switch(note){
		case 36: /* bass drum1 */
			idx = 0;
			note = 28;
			break;
		case 37: /* side stick */
			idx = 6;
			note = 110;
			break;
		case 40: /* electric snare */
			idx = 1;
			note = 69;
			break;
		case 41: /* low floor tom */
			idx = 2;
			note = 50;
			break;
		case 42: /* closed hi-hat */
			idx = 3;
			note = 115 + 8;
			break;
		case 46: /* open hi-hat */
			idx = 4;
			note = 115 + 8;
			break;
		case 49: /* crash cymbal 1 */
			idx = 5;
			note = 75;
			break;
		case 57: /* crash cymbal 2 */
			idx = 5;
			note = 85;
			break;
		}
		ret = idx < 0 ? NULL : &drum_tone_inf[idx];
	}else{
		switch(prog){
		case 48: /* timpani */
		case 50: /* strings ensamble 2 */
			idx = 0;
			break;
		case 35: /* electric bass (pick) */
			idx = 1;
			break;
		case 79: /* whistle */
		case 81: /* lead 1 (square) */
		case 87: /* lead 7 (fifths) */
			idx = 2;
			break;
		case 24: /* tango accordion */
		case 67: /* tenor sax */
			idx = 3;
			break;
		}
		ret = idx < 0 ? NULL : &tone_inf[idx];
	}
	if(ret_freq) *ret_freq = note_to_freq(note);
	return ret;
}

#define MIDI_CH_N	16
struct ch_rec{
	int vol;
	int pan;
	int bend;
	int rpn;
	int bend_range;
	int prog;
} ch_inf[ MIDI_CH_N ];

#define CH_PROG(ch)	( (ch) == 9 ? 0 : ch_inf[ch].prog )

double
env_out(struct note_rec *nt, double sec)
{
	struct tone_rec *tn;
	struct env_rec *e;
	double v;

	if((tn = tone_get(CH_PROG(nt->ch), nt->note, NULL)) == NULL) return 0;
	e = &tn->env;
	if(nt->onoff){
		sec -= nt->on_sec;
		if(sec < e->attack){
			v = sec / e->attack;
			return log10(1 + v * 9);
		}
		sec -= e->attack;
		if(sec < e->decay){
			v = sec / e->decay;
			v = log10(1 + v * 9);
			return 1 - v * (1 - e->sustain);
		}
		return e->sustain;
	}
	sec -= nt->off_sec;
	if(sec < e->release){
		v = sec / e->release;
		v = log10(1 + v * 9);
		return (1 - v) * nt->stat.off_v;
	}
	return 0;
}

void
modu_out(double v, struct modu_rec *modu, double *ret_arr)
{
	if(modu->pitch1) ret_arr[0] += v * modu->pitch1 * (1.0 / 1200);
	if(modu->pitch2) ret_arr[1] += v * modu->pitch2 * (1.0 / 1200);
	if(modu->filter1) ret_arr[2] += v * modu->filter1 * (1.0 / 1200);
	if(modu->filter2) ret_arr[3] += v * modu->filter2 * (1.0 / 1200);
}

double
lfo_out(struct lfo_rec *lfo, struct modu_rec *modu, double sec, double on_sec)
{
	double dsec;

	if(!(modu->pitch1 || modu->pitch2 || modu->filter1 || modu->filter2)) return 0;
	if((dsec = sec - on_sec - lfo->delay) <= 0) return 0;
	return wave_out(lfo->wave, lfo->freq * dsec);
}

double
vco_out(int wave, struct vco_stat_rec *stat, double freq, double sec, double modu_v)
{
	if(modu_v != 0) freq *= pow(2, modu_v);
	vco_stat_update(stat, freq, sec);
	return wave_out(wave, stat->cycle);
}

double
vcf_out(struct filter_rec *fl, struct filter_stat_rec *stat, struct out_rec *ot, double modu_v, double v)
{
	struct filter_rec tmp;

	if(stat->idx < 0) filter_init(fl, stat, ot);
	if(modu_v != 0){
		tmp = *fl;
		tmp.freq *= pow(2, modu_v);
		filter_update(&tmp, stat, ot);
	}
	return filter_out(stat, v);
}

void
delay_buf_set(struct out_rec *ot, struct note_rec *nt, double v, double env_v)
{
	int i;

	i = (ot->smp_cnt - nt->stat.fst_smp_cnt) % DELAY_BUF_N;
	nt->stat.delay_buf[0][i] = v;
	nt->stat.delay_buf[1][i] = env_v;
}

#define MIX(a, b, rate)		( (a) * (1 - (rate)) + (b) * (rate) )

double
tbl_lookup(double *tbl, int n, double d_idx)
{
	int i;

	i = (int)d_idx;
	d_idx -= i;
	i %= n;
	return MIX(tbl[i], tbl[(i+1)%n], d_idx);
}

double
delay_buf_lookup(struct out_rec *ot, struct note_rec *nt, double sec, double *ret_env_v)
{
	double cycle;

	cycle = ot->smp_freq * sec - nt->stat.fst_smp_cnt;
	if(ret_env_v) *ret_env_v = tbl_lookup(nt->stat.delay_buf[1], DELAY_BUF_N, cycle);
	return tbl_lookup(nt->stat.delay_buf[0], DELAY_BUF_N, cycle);
}

double
delay_out(struct out_rec *ot, struct note_rec *nt, struct delay_rec *delay, double *ret_env_v)
{
	double v;

	if(ot->sec - nt->on_sec < delay->sec) return 0;
	v = delay_buf_lookup(ot, nt, ot->sec - delay->sec, ret_env_v) * delay->gain;
	if(ret_env_v) *ret_env_v *= delay->gain;
	return v;
}

double
chorus_out(struct out_rec *ot, struct note_rec *nt)
{
	double dsec, bak_sec;

	dsec = ot->sec - nt->on_sec;
	bak_sec = 0.01 + 0.001 * sin(2 * M_PI * 0.8 * dsec);
	if(dsec < bak_sec) return 0;
	return delay_buf_lookup(ot, nt, ot->sec - bak_sec, NULL);
}

double
tone_out(struct out_rec *ot, struct note_rec *nt, struct tone_rec *tn, double freq, double env_v)
{
	int i;
	double v, v1, v2, lfo_v, modu_v[4];
	struct vco_rec *vco;

	lfo_v = lfo_out(&tn->lfo, &tn->lfo_modu, ot->sec, nt->on_sec);

	for(i=0; i<4; i++) modu_v[i] = 0;
	modu_out(lfo_v, &tn->lfo_modu, modu_v);
	modu_out(env_v, &tn->env_modu, modu_v);

	vco = &tn->vco;
	v1 = vco_out(vco->wave1, &nt->stat.vco[0], freq, ot->sec, modu_v[0]);

	modu_v[1] += vco->tune * (1.0 / 1200);
	v2 = vco_out(vco->wave2, &nt->stat.vco[1], freq, ot->sec, modu_v[1]);
	if(vco->ring){
		v = v1 * v2;
		v1 = (v1 + v2) * 0.5;
		v2 = v;
	}
	v = MIX(v1, v2, vco->mix);

	if(tn->fl1.type != OFF) v = vcf_out(&tn->fl1, &nt->stat.filter[0], ot, modu_v[2], v);
	if(tn->fl2.type != OFF) v = vcf_out(&tn->fl2, &nt->stat.filter[1], ot, modu_v[3], v);

	v *= env_v * tn->level;
	return v;
}

int
note_out(struct out_rec *ot, struct note_rec *nt, double *vl, double *vr)
{
	double v, freq, pan, env_v, d_env_v;
	int nch;
	struct tone_rec *tn;

	nch = nt->ch;
	tn = tone_get(CH_PROG(nch), nt->note, &freq);
	if(tn == NULL) return 0;

	if(nt->stat.fst_smp_cnt < 0) nt->stat.fst_smp_cnt = ot->smp_cnt;

	if(ch_inf[nch].bend != 0) freq *= pow(2, ch_inf[nch].bend * ch_inf[nch].bend_range * (1.0 / (8192 * 12)));

	env_v = env_out(nt, ot->sec);
	v = (env_v > 0) ? tone_out(ot, nt, tn, freq, env_v) : 0;

	d_env_v = 0;
	if(tn->delay.onoff) v += delay_out(ot, nt, &tn->delay, &d_env_v);
	d_env_v += env_v;
	delay_buf_set(ot, nt, v, d_env_v);
	if(tn->chorus) v += chorus_out(ot, nt);

	v *= (nt->velo * (1.0 / 127)) * (ch_inf[nch].vol * (1.0 / ((1<<14)-1)));
	if(ot->ch_num == 1){
		*vl += v;
	}else{
		pan = ch_inf[nch].pan * (1.0 / (1<<14));
		*vl += (1 - pan) * v;
		*vr += pan * v;
	}
	return nt->onoff == 0 && ot->sec - nt->off_sec >= tn->env.release &&
		(!tn->delay.onoff || d_env_v < 0.01);
}

void
data_out(struct out_rec *ot, double evt_sec)
{
	double vl, vr;
	int i;
	struct note_rec *nt;

	while((ot->sec = ot->smp_t * ot->smp_cnt) < evt_sec){
		vl = vr = 0;
		for(i=0; i<NOTE_BUF_N; i++){
			if(note_buf_is_free(i)) continue;
			nt = &note_buf[i];
			if(note_out(ot, nt, &vl, &vr)) note_buf_free(i);
		}
		out_do(ot, vl * (1.0 / 16));
		if(ot->ch_num > 1) out_do(ot, vr * (1.0 / 16));
		ot->smp_cnt++;
	}
}

void
note_onoff(int onoff, double evt_sec, int ch, int note, int velo)
{
	int i;

	if(onoff){
		if((i = note_buf_search(-1, -1, -1)) < 0){
			MSG("note_buf full");
			return;
		}
		note_buf[i].note = note;
		note_buf[i].ch = ch;
		note_buf[i].onoff = 1;
		note_buf[i].on_sec = evt_sec;
		note_buf[i].velo = velo;

		stat_init(&note_buf[i].stat, evt_sec);
	}else{
		if((i = note_buf_search(ch, note, 1)) < 0) return;
		note_buf[i].stat.off_v = env_out(&note_buf[i], evt_sec);
		note_buf[i].onoff = 0;
		note_buf[i].off_sec = evt_sec;
	}
}

void
msb_set(int *vp, int v)
{
	*vp &= ~(127<<7);
	*vp |= v<<7;
}

void
lsb_set(int *vp, int v)
{
	*vp &= ~127;
	*vp |= v;
}

void
bend_note_update(int ch, double sec)
{
	int i, j;
	struct note_rec *nt;
	struct vco_stat_rec *stat;

	for(i=0; i<NOTE_BUF_N; i++){
		if(note_buf_is_free(i)) continue;
		nt = &note_buf[i];
		if(nt->ch != ch) continue;
		for(j=0; j<2; j++){
			stat = &nt->stat.vco[j];
			vco_stat_update(stat, stat->freq, sec);
		}
	}
}

int
main(int ac, char **av)
{
	int div4, delta_sum;
	int i, n, v, hi, low, note, velo;
	int ch, type;
	double sec;
	struct out_rec otr;
	int tempo, tempo_delta_sum;
	double tempo_sec;

	out_init(&otr, ac, av);
	note_buf_init();
	for(i=0; i<MIDI_CH_N; i++){
		ch_inf[i].vol = 0;
		ch_inf[i].pan = 1<<(14-1);
		ch_inf[i].bend = 0;
		ch_inf[i].rpn = 0;
		ch_inf[i].bend_range = 2;
		ch_inf[i].prog =-1;
	}
	tempo = 500000;
	tempo_delta_sum = 0;
	tempo_sec = 0;

	div4 = header();

	if(!rd_str_chk(4, "MTrk")) ERR("track id");
	v = rd_int(4); /* skip */

	hi = low = 0;
	delta_sum = 0;
	while((v = rd_delta()) != EOF){
		delta_sum += v;
		sec = tempo_sec + (double)(delta_sum - tempo_delta_sum) / div4 * tempo * 0.000001;
		
		if((v = rd()) & 0x80){
			hi = (v >> 4) & 0xf;
			low  = v & 0xf;
		}else bk(v);

		data_out(&otr, sec);

		ch = low;
		switch(hi){
		case 8:
		case 9:
			note = rd();
			velo = rd();
			note_onoff(hi == 9, sec, ch, note, velo);
			break;
		case 0xb: /* control change */
			type = rd();
			v = rd();
			switch(type){
			case 7: /* channel volume msb */
				msb_set(&ch_inf[ch].vol, v);
				break;
			case 39: /* channel volume lsb */
				lsb_set(&ch_inf[ch].vol, v);
				break;
			case 10: /* pan msb */
				msb_set(&ch_inf[ch].pan, v);
				break;
			case 42: /* pan lsb */
				lsb_set(&ch_inf[ch].pan, v);
				break;
			case 100: /* rpn lsb */
				lsb_set(&ch_inf[ch].rpn, v);
				break;
			case 101: /* rpn msb */
				msb_set(&ch_inf[ch].rpn, v);
				break;
			case 6: /* data entry msb */
				switch(ch_inf[ch].rpn){
				case 0: /* pitch bend range */
					ch_inf[ch].bend_range = v;
					break;
				}
				break;
			}
			break;
		case 0xa:
			rd();
			rd();
			break;
		case 0xe: /* pitch wheel change */
			bend_note_update(ch, sec);
			v = rd();
			v |= rd() << 7;
			ch_inf[ch].bend = v - 8192;
			break;
		case 0xc: /* program number */
			v = rd();
			ch_inf[ch].prog = v;
			break;
		case 0xd:
			rd();
			break;
		case 0xf:
			type = rd();
			switch(low){
			case 0:
				while(rd() != 0xf7);
				break;
			case 1:
			case 3:
				rd();
				break;
			case 2:
				rd();
				rd();
				break;
			case 0xf: /* meta */
				n = rd();
				switch(type){
				case 0x51: /* set tempo */
					v = rd_int(n);
					tempo = v;
					tempo_delta_sum = delta_sum;
					tempo_sec = sec;
					break;
				default:
					for(i=0; i<n; i++) rd();
					break;
				}
				break;
			default:
				break;
			}
			break;
		}
	}
	if(otr.fp != stdout) pclose(otr.fp);
	return 0;
}

/* EOF */


#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <math.h>

#define MSG(s) fprintf(stderr, "%s() %s L%d : %s\n", __func__, __FILE__, __LINE__, s)
#define ERR(s) do{ fprintf(stderr, "ERR "); MSG(s); exit(1); }while(0)

int bk_buf = -1;

int
rd(void)
{
	int v;

	if((v = bk_buf) < 0) return getchar();
	bk_buf = -1;
	return v;
}

void
bk(int v)
{
	if(bk_buf >= 0) ERR("give up");
	bk_buf = v;
}

void
rd_str(int n, char *s)
{
	int i;

	for(i=0; i<n; i++) s[i] = rd();
	s[i] = '\0';
}

int
rd_str_chk(int n, char *s)
{
	char buf[256];

	rd_str(n, buf);
	return strcmp(buf, s) == 0;
}

int
rd_int(int n) /* big endian */
{
	int i, v;

	v = 0;
	for(i=0; i<n; i++) v = (v << 8) | rd();
	return v;
}

int
rd_delta(void)
{
	int v, c;

	v = 0;
	do{
		if((c = rd()) == EOF) return EOF;
		v = (v << 7) | (c & 0x7f);
	}while(c & 0x80);
	return v;
}


int
opt_idx(char *key, int ac, char **av)
{
	int i;

	for(i=1; i<ac; i++) if(strcmp(av[i], key) == 0) return i;
	return -1;
}

char *
opt_str(char *key, int ac, char **av, char *def)
{
	int i;

	i = opt_idx(key, ac, av);
	if(i < 0 || i+1 >= ac) return def;
	return av[i+1];
}

int
opt_int(char *key, int ac, char **av, int def)
{
	char *s;

	if((s = opt_str(key, ac, av, NULL)) == NULL) return def;
	return strtol(s, NULL, 0);
}

struct out_rec{
	int smp_freq, smp_cnt;
	int bit_len;
	int sign;
	int ch_num;
	FILE *fp;

	int base;
	int amp;
	int iv_min;
	int iv_max;
	double smp_t, sec;
};

int
sox_version(void)
{
	FILE *fp;
	int v1, v2, v3;

	if((fp = popen("sox --version | sed -e 's/^.*v//'", "r")) == NULL) return -1;
	fscanf(fp, "%d.%d.%d", &v1, &v2, &v3);
	pclose(fp);
	return v1*10000 + v2*100 + v3;
}

char *
sox_bit_len_fmt(int bit_len)
{
	return sox_version() >= 140400 ? 
		(bit_len == 8 ? "-b 8" : "-b 16") : 
		(bit_len == 8 ? "-b" : "-w");
}

void
out_init(struct out_rec *ot, int ac, char **av)
{
	char cmd[1024], *fn;

	ot->smp_freq = opt_int("-r", ac, av, 44100);
	ot->smp_cnt = 0;
	ot->bit_len = opt_int("-b", ac, av, 16);
	if(ot->bit_len != 8 && ot->bit_len != 16) ERR("bit_len");
	ot->sign = (opt_idx("-u", ac, av) < 0);
	ot->ch_num = opt_int("-c", ac, av, 2);

	ot->fp = stdout;
	cmd[0] = '\0';
	fn = "";
	if(opt_idx("-play", ac, av) >= 0){
		strcat(cmd, "play");
	}else if(opt_idx("-sox", ac, av) >= 0){
		strcat(cmd, "sox");
		fn = opt_str("-sox", ac, av, "-d");
	}
	if(cmd[0]){
		sprintf(cmd + strlen(cmd), " -t raw -r %d %s %s -c %d - %s",
			ot->smp_freq, sox_bit_len_fmt(ot->bit_len),
			ot->sign ? "-s" : "-u",
			ot->ch_num, fn);
		if((ot->fp = popen(cmd, "w")) == NULL) ERR("popen");
	}
	ot->amp = ot->bit_len == 8 ? 127 : 32767;
	ot->base = ot->sign ? 0 : ot->amp + 1;
	ot->iv_min = ot->base - (ot->amp + 1);
	ot->iv_max = ot->base + ot->amp;

	ot->smp_t = 1.0 / ot->smp_freq;
}

void
out_do(struct out_rec *ot, double v)
{
	int iv;

	iv = ot->base + (int)(v * ot->amp);
	if(iv > ot->iv_max) iv = ot->iv_max;
	if(iv < ot->iv_min) iv = ot->iv_min;
	switch(ot->bit_len){
	case 8:
		fputc(iv, ot->fp);
		break;
	case 16:
		fputc(iv & 0xff, ot->fp);
		fputc((iv >> 8) & 0xff, ot->fp);
		break;
	}
}

#define OFF		0
#define ON		1

#define LPF		1
#define HPF		2
#define BPF		3

struct filter_rec{
	int type; /* OFF, LPF, HPF, BPF */
	double freq, Q;
};

struct filter_stat_rec{
	int idx;
	double in[4], out[4];
	double a0, a1, a2, b0, b1, b2, div_a0;
};

void
filter_update(struct filter_rec *fl, struct filter_stat_rec *stat, struct out_rec *ot)
{
	double w0, alpha, cos_w0;

	if(fl->type == OFF) return;

	w0 = 2 * M_PI * fl->freq * ot->smp_t;
	cos_w0 = cos(w0);
	alpha = sin(w0) / (2 * fl->Q);

	switch(fl->type){
	case LPF:
		stat->b1 = 1 - cos_w0;
		stat->b0 = stat->b2 = stat->b1 * 0.5;
		break;
	case HPF:
		stat->b1 = -(1 + cos_w0);
		stat->b0 = stat->b2 = -stat->b1 * 0.5;
		break;
	case BPF:
		stat->b0 = fl->Q * alpha;
		stat->b1 = 0;
		stat->b2 = -stat->b0;
		break;
	}
	stat->a0 = 1 + alpha;
	stat->a1 = -2 * cos_w0;
	stat->a2 = 1 - alpha;
	if(stat->a0 != 0) stat->div_a0 = 1 / stat->a0;
}

void
filter_init(struct filter_rec *fl, struct filter_stat_rec *stat, struct out_rec *ot)
{
	int i;

	for(i=0; i<4; i++) stat->in[i] = stat->out[i] = 0;
	stat->idx = 0;

	filter_update(fl, stat, ot);
}

double
filter_out(struct filter_stat_rec *stat, double in)
{
	double *out_p;
	int i_1, i_2;

	stat->in[stat->idx] = in;
	out_p = &stat->out[stat->idx];

	if(stat->a0 != 0){
		i_1 = (stat->idx + 4 - 1) & 3;
		i_2 = (i_1 + 4 - 1) & 3;
		*out_p = (stat->b0 * in
			+ stat->b1 * stat->in[i_1]
			+ stat->b2 * stat->in[i_2]
			- stat->a1 * stat->out[i_1]
			- stat->a2 * stat->out[i_2] ) * stat->div_a0;
	}else{
		*out_p = 0;
	}
	stat->idx = (stat->idx + 1) & 3;
	return *out_p;
}


#define NOTE_BUF_N	256

struct vco_stat_rec{
	double cycle, freq, sec;
};

void
vco_stat_update(struct vco_stat_rec *stat, double freq, double sec)
{
	stat->cycle += freq * (sec - stat->sec);	
	stat->freq = freq;
	stat->sec = sec;
}

#define DELAY_BUF_N	(44100 * 5 / 10) /* max 0.5 sec */

struct stat_rec{
	struct vco_stat_rec vco[2];
	struct filter_stat_rec filter[2];
	double off_v;
	int fst_smp_cnt;
	double delay_buf[2][ DELAY_BUF_N ];
};
// stat_rec 構造体定義追加
// 旧 note_rec 構造体から、「状態」の部分を切り出してまとめた

void
stat_init(struct stat_rec *stat, double sec)
{
	// stat_rec 構造体の初期化
	//
	// note_onoff() 関数で直接行なっていた処理を、
	// この関数にまとめた
	// note_onoff() 関数から、本関数を呼び出すように変更
	
	int i;
	struct vco_stat_rec *vco;

	for(i=0; i<2; i++){
		vco = &stat->vco[i];
		vco->cycle = 0;
		vco->sec = sec;
	}
	for(i=0; i<2; i++){
		stat->filter[i].idx = -1;
	}
	stat->fst_smp_cnt = -1;
}

struct note_rec{
	int ch;
	int note;
	int onoff;
	double on_sec;
	double off_sec;
	int velo;

	struct stat_rec stat;
	// 「状態」の部分を切り出して
	// stat_rec 構造体にまとめた
	
} note_buf[NOTE_BUF_N];

int
note_buf_is_free(int i)
{
	return note_buf[i].ch < 0;
}

void
note_buf_free(int i)
{
	note_buf[i].ch = -1;
}

void
note_buf_init(void)
{
	int i;

	for(i=0; i<NOTE_BUF_N; i++) note_buf_free(i);
}

int
note_buf_search(int ch, int note, int onoff)
{
	int i;

	for(i=0; i<NOTE_BUF_N; i++) {
		if( (ch < 0 && note_buf[i].ch < 0) ||
		    (note_buf[i].ch == ch &&
		     note_buf[i].note == note &&
		     note_buf[i].onoff == onoff) ) return i;
	}
	return -1;
}

int
header(void)
{
	int v;

	if(!rd_str_chk(4, "MThd")) ERR("header id");
	if(rd_int(4) != 6) ERR("header size");
	if(rd_int(2) != 0) ERR("header format type");
	if(rd_int(2) != 1) ERR("header track num");
	if((v = rd_int(2)) & 0x8000) ERR("header division");
	return v; /* div4 */
}

double
note_to_freq(int note)
{
	return 440 * pow(2, (note - 69) / 12.0);
}

#define WAVE_SIN	0
#define WAVE_SAW	1
#define WAVE_SQUARE	2
#define WAVE_NOISE	3

double
wave_out(int wave, double cycle)
{
	cycle -= (int)cycle;

	switch(wave){
	case WAVE_SIN:
		return sin(2 * M_PI * cycle);
	case WAVE_SAW:
		cycle *= 2;
		if(cycle > 1) cycle -= 2;
		return cycle;
	case WAVE_SQUARE:
		return cycle < 0.5 ? 1 : -1;
	case WAVE_NOISE:
		return ((double)rand() / RAND_MAX) * 2 - 1;
	}
	return 0;
}

struct vco_rec{
	int wave1, wave2;
	int tune; /* for vco2 */
	double mix;
	int ring;
};

struct modu_rec{
	int pitch1, pitch2, filter1, filter2;
};

struct lfo_rec{
	int wave;
	double freq, delay;
};

struct env_rec{
	double attack;	/* sec */
	double decay;	/* sec */
	double sustain;	/* 0..1 */
	double release;	/* sec */
};

struct delay_rec{
	int onoff;
	double sec, gain;
};

struct tone_rec{
	struct vco_rec vco;
	struct filter_rec fl1, fl2;
	struct env_rec env;
	double level;
	struct modu_rec lfo_modu;
	struct lfo_rec lfo;
	struct modu_rec env_modu;
	struct delay_rec delay;
	int chorus;
} tone_inf[] = {
	{	/* strings */
		{ WAVE_SAW, WAVE_SAW, 12, 0.5, OFF },
		{ LPF, 3000, 1.5 }, { OFF, },
		{ 0.15, 0.5, 0.8, 0.5 },
		1.0,
		{ OFF, 12, OFF, OFF }, { WAVE_SIN, 4, 0.3 },
		{ OFF, OFF, OFF, OFF },
		{ OFF, }, ON,
	},{	/* bass */
		{ WAVE_SAW, WAVE_SQUARE, OFF, 0.5, OFF },
		{ LPF, 1000, 1.5 }, { OFF, },
		{ 0.05, 0.2, 0.4, 0.2 },
		1.0,
		{ OFF, 60, OFF, OFF }, { WAVE_SIN, 1.5, 0.2 },
		{ OFF, OFF, OFF, OFF },
		{ OFF, }, ON,
	},{	/* lead */
		{ WAVE_SQUARE, WAVE_SQUARE, 10, 0.5, OFF },
		{ LPF, 2000, 4 }, { OFF, },
		{ 0.01, 0.2, 0.8, 0.3 },
		1.0,
		{ OFF, 1, 5, OFF }, { WAVE_SIN, 4, 0.3 },
		{ OFF, OFF, OFF, OFF },
		{ ON, 0.2, 0.4}, OFF,
	},{	/* SIN */
		{ WAVE_SIN, WAVE_SIN, OFF, 0, OFF },
		{ LPF, 20000, 0.8 }, { OFF, },
		{ 0, 0.3, 0.2, 0.3 },
		1.4,
		{ 25, OFF, OFF, OFF }, { WAVE_SIN, 6, 0.3 },
		{ OFF, OFF, OFF, OFF },
		{ OFF, }, OFF,
	}
}, drum_tone_inf[] = {
	{	/* bass */
		{ WAVE_SIN, WAVE_NOISE, OFF, 0.4, OFF },
		{ LPF, 400, 1 }, { OFF, },
		{ 0.01, 0.18, 0, 0.18 },
		9.0,
		{ 100, OFF, 30, OFF }, { WAVE_NOISE, 0, 0.5 },
		{ OFF, OFF, OFF, OFF },
		{ OFF, }, OFF,
	},{	/* snare */
		{ WAVE_SQUARE, WAVE_NOISE, OFF, 0.8, ON },
		{ LPF, 1500, 1.7 }, { OFF, }, 
		{ 0, 0.4, 0.3, 0.4 },
		5,
		{ OFF, OFF, OFF, OFF }, {},
		{ OFF, OFF, OFF, OFF },
		{ OFF, }, OFF,
	},{	/* tom */
		{ WAVE_SQUARE, WAVE_NOISE, OFF, 0.5, ON },
		{ LPF, 800, 2.5 }, { OFF, },
		{ 0, 0.03, 0.1, 0.4 },
		5,
		{ OFF, OFF, OFF, OFF }, {},
		{ 200, OFF, 1200, OFF },
		{ OFF, }, OFF,
	},{	/* hi-hat close */
		{ WAVE_SQUARE, WAVE_SQUARE, 700, 0.9, ON },
		{ LPF, 16000, 2 }, { OFF, },
		{ 0, 0.15, 0, 0.15 },
		0.6,
		{ OFF, OFF, OFF, OFF }, {},
		{ OFF, OFF, OFF, OFF },
		{ OFF, }, OFF,
	},{	/* hi-hat open */
		{ WAVE_SQUARE, WAVE_SQUARE, 700, 0.9, ON },
		{ LPF, 16000, 2 }, { OFF, },
		{ 0, 0, 1, 0.35 },
		0.6,
		{ OFF, OFF, OFF, OFF }, {},
		{ OFF, OFF, OFF, OFF },
		{ OFF, }, OFF,
	},{	/* cymbal */
		{ WAVE_NOISE, WAVE_SQUARE, OFF, 0.8, ON },
		{ LPF, 4000, 2 }, { OFF, },
		{ 0, 0.01, 0.2, 0.8 },
		9,
		{ OFF, OFF, OFF, OFF }, {},
		{ OFF, OFF, 600, OFF }, 
		{ OFF, }, OFF,
	},{	/* side stick */
		{ WAVE_NOISE, WAVE_SQUARE, OFF, 0.2, OFF },
		{ LPF, 1700, 3 }, { OFF, },
		{ 0, 0.012, 0.1, 0.7 },
		10,
		{ OFF, OFF, OFF, OFF }, {},
		{ OFF, OFF, OFF, OFF },
		{ OFF, }, OFF,
	}
};

struct tone_rec *
tone_get(int prog, int note, double *ret_freq)
{
	int idx;
	struct tone_rec *ret;

	idx = -1;
	if(prog <= 0){ /* drum part */
		switch(note){
		case 36: /* bass drum1 */
			idx = 0;
			note = 28;
			break;
		case 37: /* side stick */
			idx = 6;
			note = 110;
			break;
		case 40: /* electric snare */
			idx = 1;
			note = 69;
			break;
		case 41: /* low floor tom */
			idx = 2;
			note = 50;
			break;
		case 42: /* closed hi-hat */
			idx = 3;
			note = 115 + 8;
			break;
		case 46: /* open hi-hat */
			idx = 4;
			note = 115 + 8;
			break;
		case 49: /* crash cymbal 1 */
			idx = 5;
			note = 75;
			break;
		case 57: /* crash cymbal 2 */
			idx = 5;
			note = 85;
			break;
		}
		ret = idx < 0 ? NULL : &drum_tone_inf[idx];
	}else{
		switch(prog){
		case 48: /* timpani */
		case 50: /* strings ensamble 2 */
			idx = 0;
			break;
		case 35: /* electric bass (pick) */
			idx = 1;
			break;
		case 79: /* whistle */
		case 81: /* lead 1 (square) */
		case 87: /* lead 7 (fifths) */
			idx = 2;
			break;
		case 24: /* tango accordion */
		case 67: /* tenor sax */
			idx = 3;
			break;
		}
		ret = idx < 0 ? NULL : &tone_inf[idx];
	}
	if(ret_freq) *ret_freq = note_to_freq(note);
	return ret;
}

#define MIDI_CH_N	16
struct ch_rec{
	int vol;
	int pan;
	int bend;
	int rpn;
	int bend_range;
	int prog;
} ch_inf[ MIDI_CH_N ];

#define CH_PROG(ch)	( (ch) == 9 ? 0 : ch_inf[ch].prog )

double
env_out(struct note_rec *nt, double sec)
{
	struct tone_rec *tn;
	struct env_rec *e;
	double v;

	if((tn = tone_get(CH_PROG(nt->ch), nt->note, NULL)) == NULL) return 0;
	e = &tn->env;
	if(nt->onoff){
		sec -= nt->on_sec;
		if(sec < e->attack){
			v = sec / e->attack;
			return log10(1 + v * 9);
		}
		sec -= e->attack;
		if(sec < e->decay){
			v = sec / e->decay;
			v = log10(1 + v * 9);
			return 1 - v * (1 - e->sustain);
		}
		return e->sustain;
	}
	sec -= nt->off_sec;
	if(sec < e->release){
		v = sec / e->release;
		v = log10(1 + v * 9);
		return (1 - v) * nt->stat.off_v;
		// stat_rec 構造体経由に変更
		
	}
	return 0;
}

void
modu_out(double v, struct modu_rec *modu, double *ret_arr)
{
	if(modu->pitch1) ret_arr[0] += v * modu->pitch1 * (1.0 / 1200);
	if(modu->pitch2) ret_arr[1] += v * modu->pitch2 * (1.0 / 1200);
	if(modu->filter1) ret_arr[2] += v * modu->filter1 * (1.0 / 1200);
	if(modu->filter2) ret_arr[3] += v * modu->filter2 * (1.0 / 1200);
}

double
lfo_out(struct lfo_rec *lfo, struct modu_rec *modu, double sec, double on_sec)
{
	double dsec;

	if(!(modu->pitch1 || modu->pitch2 || modu->filter1 || modu->filter2)) return 0;
	if((dsec = sec - on_sec - lfo->delay) <= 0) return 0;
	return wave_out(lfo->wave, lfo->freq * dsec);
}

double
vco_out(int wave, struct vco_stat_rec *stat, double freq, double sec, double modu_v)
{
	if(modu_v != 0) freq *= pow(2, modu_v);
	vco_stat_update(stat, freq, sec);
	return wave_out(wave, stat->cycle);
}

double
vcf_out(struct filter_rec *fl, struct filter_stat_rec *stat, struct out_rec *ot, double modu_v, double v)
{
	struct filter_rec tmp;

	if(stat->idx < 0) filter_init(fl, stat, ot);
	if(modu_v != 0){
		tmp = *fl;
		tmp.freq *= pow(2, modu_v);
		filter_update(&tmp, stat, ot);
	}
	return filter_out(stat, v);
}

void
delay_buf_set(struct out_rec *ot, struct note_rec *nt, double v, double env_v)
{
	int i;

	i = (ot->smp_cnt - nt->stat.fst_smp_cnt) % DELAY_BUF_N;
	nt->stat.delay_buf[0][i] = v;
	nt->stat.delay_buf[1][i] = env_v;
	// stat_rec 構造体経由に変更
	
}

#define MIX(a, b, rate)		( (a) * (1 - (rate)) + (b) * (rate) )

double
tbl_lookup(double *tbl, int n, double d_idx)
{
	int i;

	i = (int)d_idx;
	d_idx -= i;
	i %= n;
	return MIX(tbl[i], tbl[(i+1)%n], d_idx);
}

double
delay_buf_lookup(struct out_rec *ot, struct note_rec *nt, double sec, double *ret_env_v)
{
	double cycle;

	cycle = ot->smp_freq * sec - nt->stat.fst_smp_cnt;
	if(ret_env_v) *ret_env_v = tbl_lookup(nt->stat.delay_buf[1], DELAY_BUF_N, cycle);
	return tbl_lookup(nt->stat.delay_buf[0], DELAY_BUF_N, cycle);
	// stat_rec 構造体経由に変更
	
}

double
delay_out(struct out_rec *ot, struct note_rec *nt, struct delay_rec *delay, double *ret_env_v)
{
	double v;

	if(ot->sec - nt->on_sec < delay->sec) return 0;
	v = delay_buf_lookup(ot, nt, ot->sec - delay->sec, ret_env_v) * delay->gain;
	if(ret_env_v) *ret_env_v *= delay->gain;
	return v;
}

double
chorus_out(struct out_rec *ot, struct note_rec *nt)
{
	double dsec, bak_sec;

	dsec = ot->sec - nt->on_sec;
	bak_sec = 0.01 + 0.001 * sin(2 * M_PI * 0.8 * dsec);
	if(dsec < bak_sec) return 0;
	return delay_buf_lookup(ot, nt, ot->sec - bak_sec, NULL);
}

double
tone_out(struct out_rec *ot, struct note_rec *nt, struct tone_rec *tn, double freq, double env_v)
{
	int i;
	double v, v1, v2, lfo_v, modu_v[4];
	struct vco_rec *vco;

	lfo_v = lfo_out(&tn->lfo, &tn->lfo_modu, ot->sec, nt->on_sec);

	for(i=0; i<4; i++) modu_v[i] = 0;
	modu_out(lfo_v, &tn->lfo_modu, modu_v);
	modu_out(env_v, &tn->env_modu, modu_v);

	vco = &tn->vco;
	v1 = vco_out(vco->wave1, &nt->stat.vco[0], freq, ot->sec, modu_v[0]);
	// stat_rec 構造体経由に変更
	
	modu_v[1] += vco->tune * (1.0 / 1200);
	v2 = vco_out(vco->wave2, &nt->stat.vco[1], freq, ot->sec, modu_v[1]);
	// stat_rec 構造体経由に変更
	
	if(vco->ring){
		v = v1 * v2;
		v1 = (v1 + v2) * 0.5;
		v2 = v;
	}
	v = MIX(v1, v2, vco->mix);

	if(tn->fl1.type != OFF) v = vcf_out(&tn->fl1, &nt->stat.filter[0], ot, modu_v[2], v);
	if(tn->fl2.type != OFF) v = vcf_out(&tn->fl2, &nt->stat.filter[1], ot, modu_v[3], v);
	// stat_rec 構造体経由に変更
	
	v *= env_v * tn->level;
	return v;
}

int
note_out(struct out_rec *ot, struct note_rec *nt, double *vl, double *vr)
{
	double v, freq, pan, env_v, d_env_v;
	int nch;
	struct tone_rec *tn;

	nch = nt->ch;
	tn = tone_get(CH_PROG(nch), nt->note, &freq);
	if(tn == NULL) return 0;

	if(nt->stat.fst_smp_cnt < 0) nt->stat.fst_smp_cnt = ot->smp_cnt;
	// stat_rec 構造体経由に変更
	
	if(ch_inf[nch].bend != 0) freq *= pow(2, ch_inf[nch].bend * ch_inf[nch].bend_range * (1.0 / (8192 * 12)));

	env_v = env_out(nt, ot->sec);
	v = (env_v > 0) ? tone_out(ot, nt, tn, freq, env_v) : 0;

	d_env_v = 0;
	if(tn->delay.onoff) v += delay_out(ot, nt, &tn->delay, &d_env_v);
	d_env_v += env_v;
	delay_buf_set(ot, nt, v, d_env_v);
	if(tn->chorus) v += chorus_out(ot, nt);

	v *= (nt->velo * (1.0 / 127)) * (ch_inf[nch].vol * (1.0 / ((1<<14)-1)));
	if(ot->ch_num == 1){
		*vl += v;
	}else{
		pan = ch_inf[nch].pan * (1.0 / (1<<14));
		*vl += (1 - pan) * v;
		*vr += pan * v;
	}
	return nt->onoff == 0 && ot->sec - nt->off_sec >= tn->env.release &&
		(!tn->delay.onoff || d_env_v < 0.01);
}

void
data_out(struct out_rec *ot, double evt_sec)
{
	double vl, vr;
	int i;
	struct note_rec *nt;

	while((ot->sec = ot->smp_t * ot->smp_cnt) < evt_sec){
		vl = vr = 0;
		for(i=0; i<NOTE_BUF_N; i++){
			if(note_buf_is_free(i)) continue;
			nt = &note_buf[i];
			if(note_out(ot, nt, &vl, &vr)) note_buf_free(i);
		}
		out_do(ot, vl * (1.0 / 16));
		if(ot->ch_num > 1) out_do(ot, vr * (1.0 / 16));
		ot->smp_cnt++;
	}
}

void
note_onoff(int onoff, double evt_sec, int ch, int note, int velo)
{
	int i;

	if(onoff){
		if((i = note_buf_search(-1, -1, -1)) < 0){
			MSG("note_buf full");
			return;
		}
		note_buf[i].note = note;
		note_buf[i].ch = ch;
		note_buf[i].onoff = 1;
		note_buf[i].on_sec = evt_sec;
		note_buf[i].velo = velo;

		stat_init(&note_buf[i].stat, evt_sec);
		// 直接処理していた内容を、
		// stat_init() 関数にまとめた
		
	}else{
		if((i = note_buf_search(ch, note, 1)) < 0) return;
		note_buf[i].stat.off_v = env_out(&note_buf[i], evt_sec);
		// stat_rec 構造体経由に変更
		
		note_buf[i].onoff = 0;
		note_buf[i].off_sec = evt_sec;
	}
}

void
msb_set(int *vp, int v)
{
	*vp &= ~(127<<7);
	*vp |= v<<7;
}

void
lsb_set(int *vp, int v)
{
	*vp &= ~127;
	*vp |= v;
}

void
bend_note_update(int ch, double sec)
{
	int i, j;
	struct note_rec *nt;
	struct vco_stat_rec *stat;

	for(i=0; i<NOTE_BUF_N; i++){
		if(note_buf_is_free(i)) continue;
		nt = &note_buf[i];
		if(nt->ch != ch) continue;
		for(j=0; j<2; j++){
			stat = &nt->stat.vco[j];
			// stat_rec 構造体経由に変更
			
			vco_stat_update(stat, stat->freq, sec);
		}
	}
}

int
main(int ac, char **av)
{
	int div4, delta_sum;
	int i, n, v, hi, low, note, velo;
	int ch, type;
	double sec;
	struct out_rec otr;
	int tempo, tempo_delta_sum;
	double tempo_sec;

	out_init(&otr, ac, av);
	note_buf_init();
	for(i=0; i<MIDI_CH_N; i++){
		ch_inf[i].vol = 0;
		ch_inf[i].pan = 1<<(14-1);
		ch_inf[i].bend = 0;
		ch_inf[i].rpn = 0;
		ch_inf[i].bend_range = 2;
		ch_inf[i].prog =-1;
	}
	tempo = 500000;
	tempo_delta_sum = 0;
	tempo_sec = 0;

	div4 = header();

	if(!rd_str_chk(4, "MTrk")) ERR("track id");
	v = rd_int(4); /* skip */

	hi = low = 0;
	delta_sum = 0;
	while((v = rd_delta()) != EOF){
		delta_sum += v;
		sec = tempo_sec + (double)(delta_sum - tempo_delta_sum) / div4 * tempo * 0.000001;
		
		if((v = rd()) & 0x80){
			hi = (v >> 4) & 0xf;
			low  = v & 0xf;
		}else bk(v);

		data_out(&otr, sec);

		ch = low;
		switch(hi){
		case 8:
		case 9:
			note = rd();
			velo = rd();
			note_onoff(hi == 9, sec, ch, note, velo);
			break;
		case 0xb: /* control change */
			type = rd();
			v = rd();
			switch(type){
			case 7: /* channel volume msb */
				msb_set(&ch_inf[ch].vol, v);
				break;
			case 39: /* channel volume lsb */
				lsb_set(&ch_inf[ch].vol, v);
				break;
			case 10: /* pan msb */
				msb_set(&ch_inf[ch].pan, v);
				break;
			case 42: /* pan lsb */
				lsb_set(&ch_inf[ch].pan, v);
				break;
			case 100: /* rpn lsb */
				lsb_set(&ch_inf[ch].rpn, v);
				break;
			case 101: /* rpn msb */
				msb_set(&ch_inf[ch].rpn, v);
				break;
			case 6: /* data entry msb */
				switch(ch_inf[ch].rpn){
				case 0: /* pitch bend range */
					ch_inf[ch].bend_range = v;
					break;
				}
				break;
			}
			break;
		case 0xa:
			rd();
			rd();
			break;
		case 0xe: /* pitch wheel change */
			bend_note_update(ch, sec);
			v = rd();
			v |= rd() << 7;
			ch_inf[ch].bend = v - 8192;
			break;
		case 0xc: /* program number */
			v = rd();
			ch_inf[ch].prog = v;
			break;
		case 0xd:
			rd();
			break;
		case 0xf:
			type = rd();
			switch(low){
			case 0:
				while(rd() != 0xf7);
				break;
			case 1:
			case 3:
				rd();
				break;
			case 2:
				rd();
				rd();
				break;
			case 0xf: /* meta */
				n = rd();
				switch(type){
				case 0x51: /* set tempo */
					v = rd_int(n);
					tempo = v;
					tempo_delta_sum = delta_sum;
					tempo_sec = sec;
					break;
				default:
					for(i=0; i<n; i++) rd();
					break;
				}
				break;
			default:
				break;
			}
			break;
		}
	}
	if(otr.fp != stdout) pclose(otr.fp);
	return 0;
}

/* EOF */


prog23.c 解説

prog22.c からの変更箇所のみ

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <math.h>

#define MSG(s) fprintf(stderr, "%s() %s L%d : %s\n", __func__, __FILE__, __LINE__, s)
#define ERR(s) do{ fprintf(stderr, "ERR "); MSG(s); exit(1); }while(0)

int bk_buf = -1;

int
rd(void)
{
	int v;

	if((v = bk_buf) < 0) return getchar();
	bk_buf = -1;
	return v;
}

void
bk(int v)
{
	if(bk_buf >= 0) ERR("give up");
	bk_buf = v;
}

void
rd_str(int n, char *s)
{
	int i;

	for(i=0; i<n; i++) s[i] = rd();
	s[i] = '\0';
}

int
rd_str_chk(int n, char *s)
{
	char buf[256];

	rd_str(n, buf);
	return strcmp(buf, s) == 0;
}

int
rd_int(int n) /* big endian */
{
	int i, v;

	v = 0;
	for(i=0; i<n; i++) v = (v << 8) | rd();
	return v;
}

int
rd_delta(void)
{
	int v, c;

	v = 0;
	do{
		if((c = rd()) == EOF) return EOF;
		v = (v << 7) | (c & 0x7f);
	}while(c & 0x80);
	return v;
}


int
opt_idx(char *key, int ac, char **av)
{
	int i;

	for(i=1; i<ac; i++) if(strcmp(av[i], key) == 0) return i;
	return -1;
}

char *
opt_str(char *key, int ac, char **av, char *def)
{
	int i;

	i = opt_idx(key, ac, av);
	if(i < 0 || i+1 >= ac) return def;
	return av[i+1];
}

int
opt_int(char *key, int ac, char **av, int def)
{
	char *s;

	if((s = opt_str(key, ac, av, NULL)) == NULL) return def;
	return strtol(s, NULL, 0);
}

struct out_rec{
	int smp_freq, smp_cnt;
	int bit_len;
	int sign;
	int ch_num;
	FILE *fp;

	int base;
	int amp;
	int iv_min;
	int iv_max;
	double smp_t, sec;
};

int
sox_version(void)
{
	FILE *fp;
	int v1, v2, v3;

	if((fp = popen("sox --version | sed -e 's/^.*v//'", "r")) == NULL) return -1;
	fscanf(fp, "%d.%d.%d", &v1, &v2, &v3);
	pclose(fp);
	return v1*10000 + v2*100 + v3;
}

char *
sox_bit_len_fmt(int bit_len)
{
	return sox_version() >= 140400 ? 
		(bit_len == 8 ? "-b 8" : "-b 16") : 
		(bit_len == 8 ? "-b" : "-w");
}

void
out_init(struct out_rec *ot, int ac, char **av)
{
	char cmd[1024], *fn;

	ot->smp_freq = opt_int("-r", ac, av, 44100);
	ot->smp_cnt = 0;
	ot->bit_len = opt_int("-b", ac, av, 16);
	if(ot->bit_len != 8 && ot->bit_len != 16) ERR("bit_len");
	ot->sign = (opt_idx("-u", ac, av) < 0);
	ot->ch_num = opt_int("-c", ac, av, 2);

	ot->fp = stdout;
	cmd[0] = '\0';
	fn = "";
	if(opt_idx("-play", ac, av) >= 0){
		strcat(cmd, "play");
	}else if(opt_idx("-sox", ac, av) >= 0){
		strcat(cmd, "sox");
		fn = opt_str("-sox", ac, av, "-d");
	}
	if(cmd[0]){
		sprintf(cmd + strlen(cmd), " -t raw -r %d %s %s -c %d - %s",
			ot->smp_freq, sox_bit_len_fmt(ot->bit_len),
			ot->sign ? "-s" : "-u",
			ot->ch_num, fn);
		if((ot->fp = popen(cmd, "w")) == NULL) ERR("popen");
	}
	ot->amp = ot->bit_len == 8 ? 127 : 32767;
	ot->base = ot->sign ? 0 : ot->amp + 1;
	ot->iv_min = ot->base - (ot->amp + 1);
	ot->iv_max = ot->base + ot->amp;

	ot->smp_t = 1.0 / ot->smp_freq;
}

void
out_do(struct out_rec *ot, double v)
{
	int iv;

	iv = ot->base + (int)(v * ot->amp);
	if(iv > ot->iv_max) iv = ot->iv_max;
	if(iv < ot->iv_min) iv = ot->iv_min;
	switch(ot->bit_len){
	case 8:
		fputc(iv, ot->fp);
		break;
	case 16:
		fputc(iv & 0xff, ot->fp);
		fputc((iv >> 8) & 0xff, ot->fp);
		break;
	}
}

#define OFF		0
#define ON		1

#define LPF		1
#define HPF		2
#define BPF		3

struct filter_rec{
	int type; /* OFF, LPF, HPF, BPF */
	double freq, Q;
};

struct filter_stat_rec{
	int idx;
	double in[4], out[4];
	double a0, a1, a2, b0, b1, b2, div_a0;
};

void
filter_update(struct filter_rec *fl, struct filter_stat_rec *stat, struct out_rec *ot)
{
	double w0, alpha, cos_w0;

	if(fl->type == OFF) return;

	w0 = 2 * M_PI * fl->freq * ot->smp_t;
	cos_w0 = cos(w0);
	alpha = sin(w0) / (2 * fl->Q);

	switch(fl->type){
	case LPF:
		stat->b1 = 1 - cos_w0;
		stat->b0 = stat->b2 = stat->b1 * 0.5;
		break;
	case HPF:
		stat->b1 = -(1 + cos_w0);
		stat->b0 = stat->b2 = -stat->b1 * 0.5;
		break;
	case BPF:
		stat->b0 = fl->Q * alpha;
		stat->b1 = 0;
		stat->b2 = -stat->b0;
		break;
	}
	stat->a0 = 1 + alpha;
	stat->a1 = -2 * cos_w0;
	stat->a2 = 1 - alpha;
	if(stat->a0 != 0) stat->div_a0 = 1 / stat->a0;
}

void
filter_init(struct filter_rec *fl, struct filter_stat_rec *stat, struct out_rec *ot)
{
	int i;

	for(i=0; i<4; i++) stat->in[i] = stat->out[i] = 0;
	stat->idx = 0;

	filter_update(fl, stat, ot);
}

double
filter_out(struct filter_stat_rec *stat, double in)
{
	double *out_p;
	int i_1, i_2;

	stat->in[stat->idx] = in;
	out_p = &stat->out[stat->idx];

	if(stat->a0 != 0){
		i_1 = (stat->idx + 4 - 1) & 3;
		i_2 = (i_1 + 4 - 1) & 3;
		*out_p = (stat->b0 * in
			+ stat->b1 * stat->in[i_1]
			+ stat->b2 * stat->in[i_2]
			- stat->a1 * stat->out[i_1]
			- stat->a2 * stat->out[i_2] ) * stat->div_a0;
	}else{
		*out_p = 0;
	}
	stat->idx = (stat->idx + 1) & 3;
	return *out_p;
}


#define NOTE_BUF_N	256

struct vco_stat_rec{
	double cycle, freq, sec;
};

void
vco_stat_update(struct vco_stat_rec *stat, double freq, double sec)
{
	stat->cycle += freq * (sec - stat->sec);	
	stat->freq = freq;
	stat->sec = sec;
}

#define DELAY_BUF_N	(44100 * 5 / 10) /* max 0.5 sec */

struct stat_rec{
	struct vco_stat_rec vco[2];
	struct filter_stat_rec filter[2];
	double off_v;
	int fst_smp_cnt;
	double delay_buf[2][ DELAY_BUF_N ];
};

void
stat_init(struct stat_rec *stat, double sec)
{
	int i;
	struct vco_stat_rec *vco;

	for(i=0; i<2; i++){
		vco = &stat->vco[i];
		vco->cycle = 0;
		vco->sec = sec;
	}
	for(i=0; i<2; i++){
		stat->filter[i].idx = -1;
	}
	stat->fst_smp_cnt = -1;
}

struct tone_compo_rec;

struct note_rec{
	int ch;
	int note;
	int onoff;
	double on_sec;
	double off_sec;
	int velo;

	struct stat_rec stat;
	struct tone_compo_rec *tone_compo;
} note_buf[NOTE_BUF_N];

int
note_buf_is_free(int i)
{
	return note_buf[i].ch < 0;
}

void
note_buf_free(int i)
{
	note_buf[i].ch = -1;
}

void
note_buf_init(void)
{
	int i;

	for(i=0; i<NOTE_BUF_N; i++) note_buf_free(i);
}

int
note_buf_search(int ch, int note, int onoff)
{
	int i;

	for(i=0; i<NOTE_BUF_N; i++) {
		if( (ch < 0 && note_buf[i].ch < 0) ||
		    (note_buf[i].ch == ch &&
		     note_buf[i].note == note &&
		     note_buf[i].onoff == onoff) ) return i;
	}
	return -1;
}

int
header(void)
{
	int v;

	if(!rd_str_chk(4, "MThd")) ERR("header id");
	if(rd_int(4) != 6) ERR("header size");
	if(rd_int(2) != 0) ERR("header format type");
	if(rd_int(2) != 1) ERR("header track num");
	if((v = rd_int(2)) & 0x8000) ERR("header division");
	return v; /* div4 */
}

double
note_to_freq(int note)
{
	return 440 * pow(2, (note - 69) / 12.0);
}

#define WAVE_SIN	0
#define WAVE_SAW	1
#define WAVE_SQUARE	2
#define WAVE_NOISE	3

double
wave_out(int wave, double cycle)
{
	cycle -= (int)cycle;

	switch(wave){
	case WAVE_SIN:
		return sin(2 * M_PI * cycle);
	case WAVE_SAW:
		cycle *= 2;
		if(cycle > 1) cycle -= 2;
		return cycle;
	case WAVE_SQUARE:
		return cycle < 0.5 ? 1 : -1;
	case WAVE_NOISE:
		return ((double)rand() / RAND_MAX) * 2 - 1;
	}
	return 0;
}

struct vco_rec{
	int wave1, wave2;
	int tune; /* for vco2 */
	double mix;
	int ring;
};

struct modu_rec{
	int pitch1, pitch2, filter1, filter2;
};

struct lfo_rec{
	int wave;
	double freq, delay;
};

struct env_rec{
	double attack;	/* sec */
	double decay;	/* sec */
	double sustain;	/* 0..1 */
	double release;	/* sec */
};

struct delay_rec{
	int onoff;
	double sec, gain;
};

struct tone_rec{
	struct vco_rec vco;
	struct filter_rec fl1, fl2;
	struct env_rec env;
	double level;
	struct modu_rec lfo_modu;
	struct lfo_rec lfo;
	struct modu_rec env_modu;
	struct delay_rec delay;
	int chorus;
} tone_inf[] = {
	{	/* strings */
		{ WAVE_SAW, WAVE_SAW, 12, 0.5, OFF },
		{ LPF, 3000, 1.5 }, { OFF, },
		{ 0.15, 0.5, 0.8, 0.5 },
		1.0,
		{ OFF, 12, OFF, OFF }, { WAVE_SIN, 4, 0.3 },
		{ OFF, OFF, OFF, OFF },
		{ OFF, }, ON,
	},{	/* bass */
		{ WAVE_SAW, WAVE_SQUARE, OFF, 0.5, OFF },
		{ LPF, 1000, 1.5 }, { OFF, },
		{ 0.05, 0.2, 0.4, 0.2 },
		1.0,
		{ OFF, 60, OFF, OFF }, { WAVE_SIN, 1.5, 0.2 },
		{ OFF, OFF, OFF, OFF },
		{ OFF, }, ON,
	},{	/* lead */
		{ WAVE_SQUARE, WAVE_SQUARE, 10, 0.5, OFF },
		{ LPF, 2000, 4 }, { OFF, },
		{ 0.01, 0.2, 0.8, 0.3 },
		1.0,
		{ OFF, 1, 5, OFF }, { WAVE_SIN, 4, 0.3 },
		{ OFF, OFF, OFF, OFF },
		{ ON, 0.2, 0.4}, OFF,
	},{	/* SIN */
		{ WAVE_SIN, WAVE_SIN, OFF, 0, OFF },
		{ LPF, 20000, 0.8 }, { OFF, },
		{ 0, 0.3, 0.2, 0.3 },
		1.4,
		{ 25, OFF, OFF, OFF }, { WAVE_SIN, 6, 0.3 },
		{ OFF, OFF, OFF, OFF },
		{ OFF, }, OFF,
	}
}, drum_tone_inf[] = {
	{	/* bass */
		{ WAVE_SIN, WAVE_NOISE, OFF, 0.4, OFF },
		{ LPF, 400, 1 }, { OFF, },
		{ 0.01, 0.18, 0, 0.18 },
		9.0,
		{ 100, OFF, 30, OFF }, { WAVE_NOISE, 0, 0.5 },
		{ OFF, OFF, OFF, OFF },
		{ OFF, }, OFF,
	},{	/* snare */
		{ WAVE_SQUARE, WAVE_NOISE, OFF, 0.8, ON },
		{ LPF, 1500, 1.7 }, { OFF, }, 
		{ 0, 0.4, 0.3, 0.4 },
		5,
		{ OFF, OFF, OFF, OFF }, {},
		{ OFF, OFF, OFF, OFF },
		{ OFF, }, OFF,
	},{	/* tom */
		{ WAVE_SQUARE, WAVE_NOISE, OFF, 0.5, ON },
		{ LPF, 800, 2.5 }, { OFF, },
		{ 0, 0.03, 0.1, 0.4 },
		5,
		{ OFF, OFF, OFF, OFF }, {},
		{ 200, OFF, 1200, OFF },
		{ OFF, }, OFF,
	},{	/* hi-hat close */
		{ WAVE_SQUARE, WAVE_SQUARE, 700, 0.9, ON },
		{ LPF, 16000, 2 }, { OFF, },
		{ 0, 0.15, 0, 0.15 },
		0.6,
		{ OFF, OFF, OFF, OFF }, {},
		{ OFF, OFF, OFF, OFF },
		{ OFF, }, OFF,
	},{	/* hi-hat open */
		{ WAVE_SQUARE, WAVE_SQUARE, 700, 0.9, ON },
		{ LPF, 16000, 2 }, { OFF, },
		{ 0, 0, 1, 0.35 },
		0.6,
		{ OFF, OFF, OFF, OFF }, {},
		{ OFF, OFF, OFF, OFF },
		{ OFF, }, OFF,
	},{	/* cymbal */
		{ WAVE_NOISE, WAVE_SQUARE, OFF, 0.8, ON },
		{ LPF, 4000, 2 }, { OFF, },
		{ 0, 0.01, 0.2, 0.8 },
		9,
		{ OFF, OFF, OFF, OFF }, {},
		{ OFF, OFF, 600, OFF }, 
		{ OFF, }, OFF,
	},{	/* side stick */
		{ WAVE_NOISE, WAVE_SQUARE, OFF, 0.2, OFF },
		{ LPF, 1700, 3 }, { OFF, },
		{ 0, 0.012, 0.1, 0.7 },
		10,
		{ OFF, OFF, OFF, OFF }, {},
		{ OFF, OFF, OFF, OFF },
		{ OFF, }, OFF,
	}
};

struct tone_compo_rec{
	struct tone_rec *tone;
	int note; /* -1 : event note */
	double rate;
};

#define PROG_DRUM	0

struct{
	int prog, note; /* note for ch 9 */
	struct tone_compo_rec *tone_compo;
} tones_lst[] = {
	{
		PROG_DRUM, 36, /* bass drum1 */
		(struct tone_compo_rec []){
			{ &drum_tone_inf[0], 28, 1.0 }, { NULL, }
		}
	},{
		PROG_DRUM, 37, /* side stick */
		(struct tone_compo_rec []){
			{ &drum_tone_inf[6], 110, 1.0 }, { NULL, }
		}
	},{
		PROG_DRUM, 40, /* electric snare */
		(struct tone_compo_rec []){
			{ &drum_tone_inf[1], 69, 1.0 }, { NULL, }
		}
	},{
		PROG_DRUM, 41, /* low floor tom */
		(struct tone_compo_rec []){
			{ &drum_tone_inf[2], 50, 1.0 }, { NULL, }
		}
	},{
		PROG_DRUM, 42, /* closed hi-hat */
		(struct tone_compo_rec []){
			{ &drum_tone_inf[3], 115 + 8, 1.0 }, { NULL, }
		}
	},{
		PROG_DRUM, 46, /* open hi-hat */
		(struct tone_compo_rec []){
			{ &drum_tone_inf[4], 115 + 8, 1.0 }, { NULL, }
		}
	},{
		PROG_DRUM, 49, /* crash cymbal 1 */
		(struct tone_compo_rec []){
			{ &drum_tone_inf[5], 75, 1.0 }, { NULL, }
		}
	},{
		PROG_DRUM, 57, /* crash cymbal 2 */
		(struct tone_compo_rec []){
			{ &drum_tone_inf[5], 85, 1.0 }, { NULL, }
		}
	},{
		48, -1, /* timpani */
		(struct tone_compo_rec []){
			{ &tone_inf[0], -1, 1.0 }, { NULL, }
		}
	},{
		50, -1, /* strings ensamble 2 */
		(struct tone_compo_rec []){
			{ &tone_inf[0], -1, 1.0 }, { NULL, }
		}
	},{
		35, -1, /* electric bass (pick) */
		(struct tone_compo_rec []){
			{ &tone_inf[1], -1, 1.0 }, { NULL, }
		}
	},{
		79, -1, /* whistle */
		(struct tone_compo_rec []){
			{ &tone_inf[2], -1, 1.0 }, { NULL, }
		}
	},{
		81, -1, /* lead 1 (square) */
		(struct tone_compo_rec []){
			{ &tone_inf[2], -1, 1.0 }, { NULL, }
		}
	},{
		87, -1, /* lead 7 (fifths) */
		(struct tone_compo_rec []){
			{ &tone_inf[2], -1, 1.0 }, { NULL, }
		}
	},{
		24, -1, /* tango accordion */
		(struct tone_compo_rec []){
			{ &tone_inf[3], -1, 1.0 }, { NULL, }
		}
	},{
		67, -1, /* tenor sax */
		(struct tone_compo_rec []){
			{ &tone_inf[3], -1, 1.0 }, { NULL, }
		}
	},{
		-1, /* tail */
	}
};

#define MIDI_CH_N	16
struct ch_rec{
	int vol;
	int pan;
	int bend;
	int rpn;
	int bend_range;
	int prog;
} ch_inf[ MIDI_CH_N ];

#define CH_PROG(ch)	( (ch) == 9 ? 0 : ch_inf[ch].prog )

struct tone_compo_rec *
tone_compo_get(int ch, int note, int *ret_n)
{
	struct tone_compo_rec *tone_compo;
	int prog, i;

	prog = CH_PROG(ch);
	for(i=0; tones_lst[i].prog >= 0; i++){
		if(tones_lst[i].prog == prog &&
		   (tones_lst[i].note == note || tones_lst[i].note < 0)) break;
	}
	if(tones_lst[i].prog < 0) return NULL; /* not found */
	tone_compo = tones_lst[i].tone_compo;
	if(ret_n){
		for(i=0; tone_compo[i].tone; i++);
		*ret_n = i;
	}
	return tone_compo;
}

double
env_out(struct note_rec *nt, double sec)
{
	struct tone_rec *tn;
	struct env_rec *e;
	double v;

	tn = nt->tone_compo->tone;
	e = &tn->env;
	if(nt->onoff){
		sec -= nt->on_sec;
		if(sec < e->attack){
			v = sec / e->attack;
			return log10(1 + v * 9);
		}
		sec -= e->attack;
		if(sec < e->decay){
			v = sec / e->decay;
			v = log10(1 + v * 9);
			return 1 - v * (1 - e->sustain);
		}
		return e->sustain;
	}
	sec -= nt->off_sec;
	if(sec < e->release){
		v = sec / e->release;
		v = log10(1 + v * 9);
		return (1 - v) * nt->stat.off_v;
	}
	return 0;
}

void
modu_out(double v, struct modu_rec *modu, double *ret_arr)
{
	if(modu->pitch1) ret_arr[0] += v * modu->pitch1 * (1.0 / 1200);
	if(modu->pitch2) ret_arr[1] += v * modu->pitch2 * (1.0 / 1200);
	if(modu->filter1) ret_arr[2] += v * modu->filter1 * (1.0 / 1200);
	if(modu->filter2) ret_arr[3] += v * modu->filter2 * (1.0 / 1200);
}

double
lfo_out(struct lfo_rec *lfo, struct modu_rec *modu, double sec, double on_sec)
{
	double dsec;

	if(!(modu->pitch1 || modu->pitch2 || modu->filter1 || modu->filter2)) return 0;
	if((dsec = sec - on_sec - lfo->delay) <= 0) return 0;
	return wave_out(lfo->wave, lfo->freq * dsec);
}

double
vco_out(int wave, struct vco_stat_rec *stat, double freq, double sec, double modu_v)
{
	if(modu_v != 0) freq *= pow(2, modu_v);
	vco_stat_update(stat, freq, sec);
	return wave_out(wave, stat->cycle);
}

double
vcf_out(struct filter_rec *fl, struct filter_stat_rec *stat, struct out_rec *ot, double modu_v, double v)
{
	struct filter_rec tmp;

	if(stat->idx < 0) filter_init(fl, stat, ot);
	if(modu_v != 0){
		tmp = *fl;
		tmp.freq *= pow(2, modu_v);
		filter_update(&tmp, stat, ot);
	}
	return filter_out(stat, v);
}

void
delay_buf_set(struct out_rec *ot, struct note_rec *nt, double v, double env_v)
{
	int i;

	i = (ot->smp_cnt - nt->stat.fst_smp_cnt) % DELAY_BUF_N;
	nt->stat.delay_buf[0][i] = v;
	nt->stat.delay_buf[1][i] = env_v;
}

#define MIX(a, b, rate)		( (a) * (1 - (rate)) + (b) * (rate) )

double
tbl_lookup(double *tbl, int n, double d_idx)
{
	int i;

	i = (int)d_idx;
	d_idx -= i;
	i %= n;
	return MIX(tbl[i], tbl[(i+1)%n], d_idx);
}

double
delay_buf_lookup(struct out_rec *ot, struct note_rec *nt, double sec, double *ret_env_v)
{
	double cycle;

	cycle = ot->smp_freq * sec - nt->stat.fst_smp_cnt;
	if(ret_env_v) *ret_env_v = tbl_lookup(nt->stat.delay_buf[1], DELAY_BUF_N, cycle);
	return tbl_lookup(nt->stat.delay_buf[0], DELAY_BUF_N, cycle);
}

double
delay_out(struct out_rec *ot, struct note_rec *nt, struct delay_rec *delay, double *ret_env_v)
{
	double v;

	if(ot->sec - nt->on_sec < delay->sec) return 0;
	v = delay_buf_lookup(ot, nt, ot->sec - delay->sec, ret_env_v) * delay->gain;
	if(ret_env_v) *ret_env_v *= delay->gain;
	return v;
}

double
chorus_out(struct out_rec *ot, struct note_rec *nt)
{
	double dsec, bak_sec;

	dsec = ot->sec - nt->on_sec;
	bak_sec = 0.01 + 0.001 * sin(2 * M_PI * 0.8 * dsec);
	if(dsec < bak_sec) return 0;
	return delay_buf_lookup(ot, nt, ot->sec - bak_sec, NULL);
}

double
tone_out(struct out_rec *ot, struct note_rec *nt, struct tone_rec *tn, double freq, double env_v)
{
	int i;
	double v, v1, v2, lfo_v, modu_v[4];
	struct vco_rec *vco;

	lfo_v = lfo_out(&tn->lfo, &tn->lfo_modu, ot->sec, nt->on_sec);

	for(i=0; i<4; i++) modu_v[i] = 0;
	modu_out(lfo_v, &tn->lfo_modu, modu_v);
	modu_out(env_v, &tn->env_modu, modu_v);

	vco = &tn->vco;
	v1 = vco_out(vco->wave1, &nt->stat.vco[0], freq, ot->sec, modu_v[0]);

	modu_v[1] += vco->tune * (1.0 / 1200);
	v2 = vco_out(vco->wave2, &nt->stat.vco[1], freq, ot->sec, modu_v[1]);
	if(vco->ring){
		v = v1 * v2;
		v1 = (v1 + v2) * 0.5;
		v2 = v;
	}
	v = MIX(v1, v2, vco->mix);

	if(tn->fl1.type != OFF) v = vcf_out(&tn->fl1, &nt->stat.filter[0], ot, modu_v[2], v);
	if(tn->fl2.type != OFF) v = vcf_out(&tn->fl2, &nt->stat.filter[1], ot, modu_v[3], v);

	v *= env_v * tn->level;
	return v;
}

int
note_out(struct out_rec *ot, struct note_rec *nt, double *vl, double *vr)
{
	double v, freq, pan, env_v, d_env_v;
	int nch;
	struct tone_rec *tn;

	nch = nt->ch;
	tn = nt->tone_compo->tone;
	freq = note_to_freq(nt->tone_compo->note >= 0 ? nt->tone_compo->note : nt->note);

	if(nt->stat.fst_smp_cnt < 0) nt->stat.fst_smp_cnt = ot->smp_cnt;

	if(ch_inf[nch].bend != 0) freq *= pow(2, ch_inf[nch].bend * ch_inf[nch].bend_range * (1.0 / (8192 * 12)));

	env_v = env_out(nt, ot->sec);
	v = (env_v > 0) ? tone_out(ot, nt, tn, freq, env_v) : 0;

	d_env_v = 0;
	if(tn->delay.onoff) v += delay_out(ot, nt, &tn->delay, &d_env_v);
	d_env_v += env_v;
	delay_buf_set(ot, nt, v, d_env_v);
	if(tn->chorus) v += chorus_out(ot, nt);

	v *= (nt->velo * (1.0 / 127)) * (ch_inf[nch].vol * (1.0 / ((1<<14)-1)));
	if(ot->ch_num == 1){
		*vl += v;
	}else{
		pan = ch_inf[nch].pan * (1.0 / (1<<14));
		*vl += (1 - pan) * v;
		*vr += pan * v;
	}
	return nt->onoff == 0 && ot->sec - nt->off_sec >= tn->env.release &&
		(!tn->delay.onoff || d_env_v < 0.01);
}

void
data_out(struct out_rec *ot, double evt_sec)
{
	double vl, vr;
	int i;
	struct note_rec *nt;

	while((ot->sec = ot->smp_t * ot->smp_cnt) < evt_sec){
		vl = vr = 0;
		for(i=0; i<NOTE_BUF_N; i++){
			if(note_buf_is_free(i)) continue;
			nt = &note_buf[i];
			if(note_out(ot, nt, &vl, &vr)) note_buf_free(i);
		}
		out_do(ot, vl * (1.0 / 16));
		if(ot->ch_num > 1) out_do(ot, vr * (1.0 / 16));
		ot->smp_cnt++;
	}
}

void
note_onoff(int onoff, double evt_sec, int ch, int note, int velo)
{
	int i, tone_n;
	struct tone_compo_rec *tone_compo;

	if(onoff){
		if((i = note_buf_search(-1, -1, -1)) < 0){
			MSG("note_buf full");
			return;
		}
		note_buf[i].note = note;
		note_buf[i].ch = ch;
		note_buf[i].onoff = 1;
		note_buf[i].on_sec = evt_sec;
		note_buf[i].velo = velo;

		stat_init(&note_buf[i].stat, evt_sec);
		if((tone_compo = tone_compo_get(ch, note, &tone_n)) == NULL){
			note_buf_free(i);
			return;
		}
		note_buf[i].tone_compo = tone_compo;
	}else{
		if((i = note_buf_search(ch, note, 1)) < 0) return;
		note_buf[i].stat.off_v = env_out(&note_buf[i], evt_sec);
		note_buf[i].onoff = 0;
		note_buf[i].off_sec = evt_sec;
	}
}

void
msb_set(int *vp, int v)
{
	*vp &= ~(127<<7);
	*vp |= v<<7;
}

void
lsb_set(int *vp, int v)
{
	*vp &= ~127;
	*vp |= v;
}

void
bend_note_update(int ch, double sec)
{
	int i, j;
	struct note_rec *nt;
	struct vco_stat_rec *stat;

	for(i=0; i<NOTE_BUF_N; i++){
		if(note_buf_is_free(i)) continue;
		nt = &note_buf[i];
		if(nt->ch != ch) continue;
		for(j=0; j<2; j++){
			stat = &nt->stat.vco[j];
			vco_stat_update(stat, stat->freq, sec);
		}
	}
}

int
main(int ac, char **av)
{
	int div4, delta_sum;
	int i, n, v, hi, low, note, velo;
	int ch, type;
	double sec;
	struct out_rec otr;
	int tempo, tempo_delta_sum;
	double tempo_sec;

	out_init(&otr, ac, av);
	note_buf_init();
	for(i=0; i<MIDI_CH_N; i++){
		ch_inf[i].vol = 0;
		ch_inf[i].pan = 1<<(14-1);
		ch_inf[i].bend = 0;
		ch_inf[i].rpn = 0;
		ch_inf[i].bend_range = 2;
		ch_inf[i].prog =-1;
	}
	tempo = 500000;
	tempo_delta_sum = 0;
	tempo_sec = 0;

	div4 = header();

	if(!rd_str_chk(4, "MTrk")) ERR("track id");
	v = rd_int(4); /* skip */

	hi = low = 0;
	delta_sum = 0;
	while((v = rd_delta()) != EOF){
		delta_sum += v;
		sec = tempo_sec + (double)(delta_sum - tempo_delta_sum) / div4 * tempo * 0.000001;
		
		if((v = rd()) & 0x80){
			hi = (v >> 4) & 0xf;
			low  = v & 0xf;
		}else bk(v);

		data_out(&otr, sec);

		ch = low;
		switch(hi){
		case 8:
		case 9:
			note = rd();
			velo = rd();
			note_onoff(hi == 9, sec, ch, note, velo);
			break;
		case 0xb: /* control change */
			type = rd();
			v = rd();
			switch(type){
			case 7: /* channel volume msb */
				msb_set(&ch_inf[ch].vol, v);
				break;
			case 39: /* channel volume lsb */
				lsb_set(&ch_inf[ch].vol, v);
				break;
			case 10: /* pan msb */
				msb_set(&ch_inf[ch].pan, v);
				break;
			case 42: /* pan lsb */
				lsb_set(&ch_inf[ch].pan, v);
				break;
			case 100: /* rpn lsb */
				lsb_set(&ch_inf[ch].rpn, v);
				break;
			case 101: /* rpn msb */
				msb_set(&ch_inf[ch].rpn, v);
				break;
			case 6: /* data entry msb */
				switch(ch_inf[ch].rpn){
				case 0: /* pitch bend range */
					ch_inf[ch].bend_range = v;
					break;
				}
				break;
			}
			break;
		case 0xa:
			rd();
			rd();
			break;
		case 0xe: /* pitch wheel change */
			bend_note_update(ch, sec);
			v = rd();
			v |= rd() << 7;
			ch_inf[ch].bend = v - 8192;
			break;
		case 0xc: /* program number */
			v = rd();
			ch_inf[ch].prog = v;
			break;
		case 0xd:
			rd();
			break;
		case 0xf:
			type = rd();
			switch(low){
			case 0:
				while(rd() != 0xf7);
				break;
			case 1:
			case 3:
				rd();
				break;
			case 2:
				rd();
				rd();
				break;
			case 0xf: /* meta */
				n = rd();
				switch(type){
				case 0x51: /* set tempo */
					v = rd_int(n);
					tempo = v;
					tempo_delta_sum = delta_sum;
					tempo_sec = sec;
					break;
				default:
					for(i=0; i<n; i++) rd();
					break;
				}
				break;
			default:
				break;
			}
			break;
		}
	}
	if(otr.fp != stdout) pclose(otr.fp);
	return 0;
}

/* EOF */


#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <math.h>

#define MSG(s) fprintf(stderr, "%s() %s L%d : %s\n", __func__, __FILE__, __LINE__, s)
#define ERR(s) do{ fprintf(stderr, "ERR "); MSG(s); exit(1); }while(0)

int bk_buf = -1;

int
rd(void)
{
	int v;

	if((v = bk_buf) < 0) return getchar();
	bk_buf = -1;
	return v;
}

void
bk(int v)
{
	if(bk_buf >= 0) ERR("give up");
	bk_buf = v;
}

void
rd_str(int n, char *s)
{
	int i;

	for(i=0; i<n; i++) s[i] = rd();
	s[i] = '\0';
}

int
rd_str_chk(int n, char *s)
{
	char buf[256];

	rd_str(n, buf);
	return strcmp(buf, s) == 0;
}

int
rd_int(int n) /* big endian */
{
	int i, v;

	v = 0;
	for(i=0; i<n; i++) v = (v << 8) | rd();
	return v;
}

int
rd_delta(void)
{
	int v, c;

	v = 0;
	do{
		if((c = rd()) == EOF) return EOF;
		v = (v << 7) | (c & 0x7f);
	}while(c & 0x80);
	return v;
}


int
opt_idx(char *key, int ac, char **av)
{
	int i;

	for(i=1; i<ac; i++) if(strcmp(av[i], key) == 0) return i;
	return -1;
}

char *
opt_str(char *key, int ac, char **av, char *def)
{
	int i;

	i = opt_idx(key, ac, av);
	if(i < 0 || i+1 >= ac) return def;
	return av[i+1];
}

int
opt_int(char *key, int ac, char **av, int def)
{
	char *s;

	if((s = opt_str(key, ac, av, NULL)) == NULL) return def;
	return strtol(s, NULL, 0);
}

struct out_rec{
	int smp_freq, smp_cnt;
	int bit_len;
	int sign;
	int ch_num;
	FILE *fp;

	int base;
	int amp;
	int iv_min;
	int iv_max;
	double smp_t, sec;
};

int
sox_version(void)
{
	FILE *fp;
	int v1, v2, v3;

	if((fp = popen("sox --version | sed -e 's/^.*v//'", "r")) == NULL) return -1;
	fscanf(fp, "%d.%d.%d", &v1, &v2, &v3);
	pclose(fp);
	return v1*10000 + v2*100 + v3;
}

char *
sox_bit_len_fmt(int bit_len)
{
	return sox_version() >= 140400 ? 
		(bit_len == 8 ? "-b 8" : "-b 16") : 
		(bit_len == 8 ? "-b" : "-w");
}

void
out_init(struct out_rec *ot, int ac, char **av)
{
	char cmd[1024], *fn;

	ot->smp_freq = opt_int("-r", ac, av, 44100);
	ot->smp_cnt = 0;
	ot->bit_len = opt_int("-b", ac, av, 16);
	if(ot->bit_len != 8 && ot->bit_len != 16) ERR("bit_len");
	ot->sign = (opt_idx("-u", ac, av) < 0);
	ot->ch_num = opt_int("-c", ac, av, 2);

	ot->fp = stdout;
	cmd[0] = '\0';
	fn = "";
	if(opt_idx("-play", ac, av) >= 0){
		strcat(cmd, "play");
	}else if(opt_idx("-sox", ac, av) >= 0){
		strcat(cmd, "sox");
		fn = opt_str("-sox", ac, av, "-d");
	}
	if(cmd[0]){
		sprintf(cmd + strlen(cmd), " -t raw -r %d %s %s -c %d - %s",
			ot->smp_freq, sox_bit_len_fmt(ot->bit_len),
			ot->sign ? "-s" : "-u",
			ot->ch_num, fn);
		if((ot->fp = popen(cmd, "w")) == NULL) ERR("popen");
	}
	ot->amp = ot->bit_len == 8 ? 127 : 32767;
	ot->base = ot->sign ? 0 : ot->amp + 1;
	ot->iv_min = ot->base - (ot->amp + 1);
	ot->iv_max = ot->base + ot->amp;

	ot->smp_t = 1.0 / ot->smp_freq;
}

void
out_do(struct out_rec *ot, double v)
{
	int iv;

	iv = ot->base + (int)(v * ot->amp);
	if(iv > ot->iv_max) iv = ot->iv_max;
	if(iv < ot->iv_min) iv = ot->iv_min;
	switch(ot->bit_len){
	case 8:
		fputc(iv, ot->fp);
		break;
	case 16:
		fputc(iv & 0xff, ot->fp);
		fputc((iv >> 8) & 0xff, ot->fp);
		break;
	}
}

#define OFF		0
#define ON		1

#define LPF		1
#define HPF		2
#define BPF		3

struct filter_rec{
	int type; /* OFF, LPF, HPF, BPF */
	double freq, Q;
};

struct filter_stat_rec{
	int idx;
	double in[4], out[4];
	double a0, a1, a2, b0, b1, b2, div_a0;
};

void
filter_update(struct filter_rec *fl, struct filter_stat_rec *stat, struct out_rec *ot)
{
	double w0, alpha, cos_w0;

	if(fl->type == OFF) return;

	w0 = 2 * M_PI * fl->freq * ot->smp_t;
	cos_w0 = cos(w0);
	alpha = sin(w0) / (2 * fl->Q);

	switch(fl->type){
	case LPF:
		stat->b1 = 1 - cos_w0;
		stat->b0 = stat->b2 = stat->b1 * 0.5;
		break;
	case HPF:
		stat->b1 = -(1 + cos_w0);
		stat->b0 = stat->b2 = -stat->b1 * 0.5;
		break;
	case BPF:
		stat->b0 = fl->Q * alpha;
		stat->b1 = 0;
		stat->b2 = -stat->b0;
		break;
	}
	stat->a0 = 1 + alpha;
	stat->a1 = -2 * cos_w0;
	stat->a2 = 1 - alpha;
	if(stat->a0 != 0) stat->div_a0 = 1 / stat->a0;
}

void
filter_init(struct filter_rec *fl, struct filter_stat_rec *stat, struct out_rec *ot)
{
	int i;

	for(i=0; i<4; i++) stat->in[i] = stat->out[i] = 0;
	stat->idx = 0;

	filter_update(fl, stat, ot);
}

double
filter_out(struct filter_stat_rec *stat, double in)
{
	double *out_p;
	int i_1, i_2;

	stat->in[stat->idx] = in;
	out_p = &stat->out[stat->idx];

	if(stat->a0 != 0){
		i_1 = (stat->idx + 4 - 1) & 3;
		i_2 = (i_1 + 4 - 1) & 3;
		*out_p = (stat->b0 * in
			+ stat->b1 * stat->in[i_1]
			+ stat->b2 * stat->in[i_2]
			- stat->a1 * stat->out[i_1]
			- stat->a2 * stat->out[i_2] ) * stat->div_a0;
	}else{
		*out_p = 0;
	}
	stat->idx = (stat->idx + 1) & 3;
	return *out_p;
}


#define NOTE_BUF_N	256

struct vco_stat_rec{
	double cycle, freq, sec;
};

void
vco_stat_update(struct vco_stat_rec *stat, double freq, double sec)
{
	stat->cycle += freq * (sec - stat->sec);	
	stat->freq = freq;
	stat->sec = sec;
}

#define DELAY_BUF_N	(44100 * 5 / 10) /* max 0.5 sec */

struct stat_rec{
	struct vco_stat_rec vco[2];
	struct filter_stat_rec filter[2];
	double off_v;
	int fst_smp_cnt;
	double delay_buf[2][ DELAY_BUF_N ];
};

void
stat_init(struct stat_rec *stat, double sec)
{
	int i;
	struct vco_stat_rec *vco;

	for(i=0; i<2; i++){
		vco = &stat->vco[i];
		vco->cycle = 0;
		vco->sec = sec;
	}
	for(i=0; i<2; i++){
		stat->filter[i].idx = -1;
	}
	stat->fst_smp_cnt = -1;
}

struct tone_compo_rec;
// note_rec 構造体のメンバに 
// tone_compo_rec 構造体のポインタを追加したいが、
// tone_compo_rec 構造体定義が、後方なので、
// 宣言だけ追加

struct note_rec{
	int ch;
	int note;
	int onoff;
	double on_sec;
	double off_sec;
	int velo;

	struct stat_rec stat;
	struct tone_compo_rec *tone_compo;
	// 音色成分の構造体のポインタを追加
	// 配列として使用する
	
} note_buf[NOTE_BUF_N];

int
note_buf_is_free(int i)
{
	return note_buf[i].ch < 0;
}

void
note_buf_free(int i)
{
	note_buf[i].ch = -1;
}

void
note_buf_init(void)
{
	int i;

	for(i=0; i<NOTE_BUF_N; i++) note_buf_free(i);
}

int
note_buf_search(int ch, int note, int onoff)
{
	int i;

	for(i=0; i<NOTE_BUF_N; i++) {
		if( (ch < 0 && note_buf[i].ch < 0) ||
		    (note_buf[i].ch == ch &&
		     note_buf[i].note == note &&
		     note_buf[i].onoff == onoff) ) return i;
	}
	return -1;
}

int
header(void)
{
	int v;

	if(!rd_str_chk(4, "MThd")) ERR("header id");
	if(rd_int(4) != 6) ERR("header size");
	if(rd_int(2) != 0) ERR("header format type");
	if(rd_int(2) != 1) ERR("header track num");
	if((v = rd_int(2)) & 0x8000) ERR("header division");
	return v; /* div4 */
}

double
note_to_freq(int note)
{
	return 440 * pow(2, (note - 69) / 12.0);
}

#define WAVE_SIN	0
#define WAVE_SAW	1
#define WAVE_SQUARE	2
#define WAVE_NOISE	3

double
wave_out(int wave, double cycle)
{
	cycle -= (int)cycle;

	switch(wave){
	case WAVE_SIN:
		return sin(2 * M_PI * cycle);
	case WAVE_SAW:
		cycle *= 2;
		if(cycle > 1) cycle -= 2;
		return cycle;
	case WAVE_SQUARE:
		return cycle < 0.5 ? 1 : -1;
	case WAVE_NOISE:
		return ((double)rand() / RAND_MAX) * 2 - 1;
	}
	return 0;
}

struct vco_rec{
	int wave1, wave2;
	int tune; /* for vco2 */
	double mix;
	int ring;
};

struct modu_rec{
	int pitch1, pitch2, filter1, filter2;
};

struct lfo_rec{
	int wave;
	double freq, delay;
};

struct env_rec{
	double attack;	/* sec */
	double decay;	/* sec */
	double sustain;	/* 0..1 */
	double release;	/* sec */
};

struct delay_rec{
	int onoff;
	double sec, gain;
};

struct tone_rec{
	struct vco_rec vco;
	struct filter_rec fl1, fl2;
	struct env_rec env;
	double level;
	struct modu_rec lfo_modu;
	struct lfo_rec lfo;
	struct modu_rec env_modu;
	struct delay_rec delay;
	int chorus;
} tone_inf[] = {
	{	/* strings */
		{ WAVE_SAW, WAVE_SAW, 12, 0.5, OFF },
		{ LPF, 3000, 1.5 }, { OFF, },
		{ 0.15, 0.5, 0.8, 0.5 },
		1.0,
		{ OFF, 12, OFF, OFF }, { WAVE_SIN, 4, 0.3 },
		{ OFF, OFF, OFF, OFF },
		{ OFF, }, ON,
	},{	/* bass */
		{ WAVE_SAW, WAVE_SQUARE, OFF, 0.5, OFF },
		{ LPF, 1000, 1.5 }, { OFF, },
		{ 0.05, 0.2, 0.4, 0.2 },
		1.0,
		{ OFF, 60, OFF, OFF }, { WAVE_SIN, 1.5, 0.2 },
		{ OFF, OFF, OFF, OFF },
		{ OFF, }, ON,
	},{	/* lead */
		{ WAVE_SQUARE, WAVE_SQUARE, 10, 0.5, OFF },
		{ LPF, 2000, 4 }, { OFF, },
		{ 0.01, 0.2, 0.8, 0.3 },
		1.0,
		{ OFF, 1, 5, OFF }, { WAVE_SIN, 4, 0.3 },
		{ OFF, OFF, OFF, OFF },
		{ ON, 0.2, 0.4}, OFF,
	},{	/* SIN */
		{ WAVE_SIN, WAVE_SIN, OFF, 0, OFF },
		{ LPF, 20000, 0.8 }, { OFF, },
		{ 0, 0.3, 0.2, 0.3 },
		1.4,
		{ 25, OFF, OFF, OFF }, { WAVE_SIN, 6, 0.3 },
		{ OFF, OFF, OFF, OFF },
		{ OFF, }, OFF,
	}
}, drum_tone_inf[] = {
	{	/* bass */
		{ WAVE_SIN, WAVE_NOISE, OFF, 0.4, OFF },
		{ LPF, 400, 1 }, { OFF, },
		{ 0.01, 0.18, 0, 0.18 },
		9.0,
		{ 100, OFF, 30, OFF }, { WAVE_NOISE, 0, 0.5 },
		{ OFF, OFF, OFF, OFF },
		{ OFF, }, OFF,
	},{	/* snare */
		{ WAVE_SQUARE, WAVE_NOISE, OFF, 0.8, ON },
		{ LPF, 1500, 1.7 }, { OFF, }, 
		{ 0, 0.4, 0.3, 0.4 },
		5,
		{ OFF, OFF, OFF, OFF }, {},
		{ OFF, OFF, OFF, OFF },
		{ OFF, }, OFF,
	},{	/* tom */
		{ WAVE_SQUARE, WAVE_NOISE, OFF, 0.5, ON },
		{ LPF, 800, 2.5 }, { OFF, },
		{ 0, 0.03, 0.1, 0.4 },
		5,
		{ OFF, OFF, OFF, OFF }, {},
		{ 200, OFF, 1200, OFF },
		{ OFF, }, OFF,
	},{	/* hi-hat close */
		{ WAVE_SQUARE, WAVE_SQUARE, 700, 0.9, ON },
		{ LPF, 16000, 2 }, { OFF, },
		{ 0, 0.15, 0, 0.15 },
		0.6,
		{ OFF, OFF, OFF, OFF }, {},
		{ OFF, OFF, OFF, OFF },
		{ OFF, }, OFF,
	},{	/* hi-hat open */
		{ WAVE_SQUARE, WAVE_SQUARE, 700, 0.9, ON },
		{ LPF, 16000, 2 }, { OFF, },
		{ 0, 0, 1, 0.35 },
		0.6,
		{ OFF, OFF, OFF, OFF }, {},
		{ OFF, OFF, OFF, OFF },
		{ OFF, }, OFF,
	},{	/* cymbal */
		{ WAVE_NOISE, WAVE_SQUARE, OFF, 0.8, ON },
		{ LPF, 4000, 2 }, { OFF, },
		{ 0, 0.01, 0.2, 0.8 },
		9,
		{ OFF, OFF, OFF, OFF }, {},
		{ OFF, OFF, 600, OFF }, 
		{ OFF, }, OFF,
	},{	/* side stick */
		{ WAVE_NOISE, WAVE_SQUARE, OFF, 0.2, OFF },
		{ LPF, 1700, 3 }, { OFF, },
		{ 0, 0.012, 0.1, 0.7 },
		10,
		{ OFF, OFF, OFF, OFF }, {},
		{ OFF, OFF, OFF, OFF },
		{ OFF, }, OFF,
	}
};

struct tone_compo_rec{
	struct tone_rec *tone;
	int note; /* -1 : event note */
	double rate;
};
// 音色成分の構造体定義を追加

#define PROG_DRUM	0
// ドラム・パートのプログラム番号指定用

struct{
	int prog, note; /* note for ch 9 */
	struct tone_compo_rec *tone_compo;
} tones_lst[] = {
	{
		PROG_DRUM, 36, /* bass drum1 */
		(struct tone_compo_rec []){
			{ &drum_tone_inf[0], 28, 1.0 }, { NULL, }
		}
	},{
		PROG_DRUM, 37, /* side stick */
		(struct tone_compo_rec []){
			{ &drum_tone_inf[6], 110, 1.0 }, { NULL, }
		}
	},{
		PROG_DRUM, 40, /* electric snare */
		(struct tone_compo_rec []){
			{ &drum_tone_inf[1], 69, 1.0 }, { NULL, }
		}
	},{
		PROG_DRUM, 41, /* low floor tom */
		(struct tone_compo_rec []){
			{ &drum_tone_inf[2], 50, 1.0 }, { NULL, }
		}
	},{
		PROG_DRUM, 42, /* closed hi-hat */
		(struct tone_compo_rec []){
			{ &drum_tone_inf[3], 115 + 8, 1.0 }, { NULL, }
		}
	},{
		PROG_DRUM, 46, /* open hi-hat */
		(struct tone_compo_rec []){
			{ &drum_tone_inf[4], 115 + 8, 1.0 }, { NULL, }
		}
	},{
		PROG_DRUM, 49, /* crash cymbal 1 */
		(struct tone_compo_rec []){
			{ &drum_tone_inf[5], 75, 1.0 }, { NULL, }
		}
	},{
		PROG_DRUM, 57, /* crash cymbal 2 */
		(struct tone_compo_rec []){
			{ &drum_tone_inf[5], 85, 1.0 }, { NULL, }
		}
	},{
		48, -1, /* timpani */
		(struct tone_compo_rec []){
			{ &tone_inf[0], -1, 1.0 }, { NULL, }
		}
	},{
		50, -1, /* strings ensamble 2 */
		(struct tone_compo_rec []){
			{ &tone_inf[0], -1, 1.0 }, { NULL, }
		}
	},{
		35, -1, /* electric bass (pick) */
		(struct tone_compo_rec []){
			{ &tone_inf[1], -1, 1.0 }, { NULL, }
		}
	},{
		79, -1, /* whistle */
		(struct tone_compo_rec []){
			{ &tone_inf[2], -1, 1.0 }, { NULL, }
		}
	},{
		81, -1, /* lead 1 (square) */
		(struct tone_compo_rec []){
			{ &tone_inf[2], -1, 1.0 }, { NULL, }
		}
	},{
		87, -1, /* lead 7 (fifths) */
		(struct tone_compo_rec []){
			{ &tone_inf[2], -1, 1.0 }, { NULL, }
		}
	},{
		24, -1, /* tango accordion */
		(struct tone_compo_rec []){
			{ &tone_inf[3], -1, 1.0 }, { NULL, }
		}
	},{
		67, -1, /* tenor sax */
		(struct tone_compo_rec []){
			{ &tone_inf[3], -1, 1.0 }, { NULL, }
		}
	},{
		-1, /* tail */
	}
};

#define MIDI_CH_N	16
struct ch_rec{
	int vol;
	int pan;
	int bend;
	int rpn;
	int bend_range;
	int prog;
} ch_inf[ MIDI_CH_N ];

#define CH_PROG(ch)	( (ch) == 9 ? 0 : ch_inf[ch].prog )

struct tone_compo_rec *
tone_compo_get(int ch, int note, int *ret_n)
{
	// 音色成分の配列を取得する
	// 末尾の引数には、配列の要素数が返る
	// 対応する音色が見つからなければ NULL を返す
	
	struct tone_compo_rec *tone_compo;
	int prog, i;

	prog = CH_PROG(ch);
	for(i=0; tones_lst[i].prog >= 0; i++){
		if(tones_lst[i].prog == prog &&
		   (tones_lst[i].note == note || tones_lst[i].note < 0)) break;
	}
	if(tones_lst[i].prog < 0) return NULL; /* not found */
	tone_compo = tones_lst[i].tone_compo;
	if(ret_n){
		for(i=0; tone_compo[i].tone; i++);
		*ret_n = i;
	}
	return tone_compo;
}

double
env_out(struct note_rec *nt, double sec)
{
	struct tone_rec *tn;
	struct env_rec *e;
	double v;

	tn = nt->tone_compo->tone;
	// tone_get() 関数は廃止
	//
	// note_onoff() 関数で tone_compo_get() 関数を使用し、
	// note_rec 構造体に tone_compo_rec 構造体の配列が保持される
	//
	// tone_compo_rec 構造体の配列のうち、
	// 先頭の要素だけ使って試している
	
	e = &tn->env;
	if(nt->onoff){
		sec -= nt->on_sec;
		if(sec < e->attack){
			v = sec / e->attack;
			return log10(1 + v * 9);
		}
		sec -= e->attack;
		if(sec < e->decay){
			v = sec / e->decay;
			v = log10(1 + v * 9);
			return 1 - v * (1 - e->sustain);
		}
		return e->sustain;
	}
	sec -= nt->off_sec;
	if(sec < e->release){
		v = sec / e->release;
		v = log10(1 + v * 9);
		return (1 - v) * nt->stat.off_v;
	}
	return 0;
}

void
modu_out(double v, struct modu_rec *modu, double *ret_arr)
{
	if(modu->pitch1) ret_arr[0] += v * modu->pitch1 * (1.0 / 1200);
	if(modu->pitch2) ret_arr[1] += v * modu->pitch2 * (1.0 / 1200);
	if(modu->filter1) ret_arr[2] += v * modu->filter1 * (1.0 / 1200);
	if(modu->filter2) ret_arr[3] += v * modu->filter2 * (1.0 / 1200);
}

double
lfo_out(struct lfo_rec *lfo, struct modu_rec *modu, double sec, double on_sec)
{
	double dsec;

	if(!(modu->pitch1 || modu->pitch2 || modu->filter1 || modu->filter2)) return 0;
	if((dsec = sec - on_sec - lfo->delay) <= 0) return 0;
	return wave_out(lfo->wave, lfo->freq * dsec);
}

double
vco_out(int wave, struct vco_stat_rec *stat, double freq, double sec, double modu_v)
{
	if(modu_v != 0) freq *= pow(2, modu_v);
	vco_stat_update(stat, freq, sec);
	return wave_out(wave, stat->cycle);
}

double
vcf_out(struct filter_rec *fl, struct filter_stat_rec *stat, struct out_rec *ot, double modu_v, double v)
{
	struct filter_rec tmp;

	if(stat->idx < 0) filter_init(fl, stat, ot);
	if(modu_v != 0){
		tmp = *fl;
		tmp.freq *= pow(2, modu_v);
		filter_update(&tmp, stat, ot);
	}
	return filter_out(stat, v);
}

void
delay_buf_set(struct out_rec *ot, struct note_rec *nt, double v, double env_v)
{
	int i;

	i = (ot->smp_cnt - nt->stat.fst_smp_cnt) % DELAY_BUF_N;
	nt->stat.delay_buf[0][i] = v;
	nt->stat.delay_buf[1][i] = env_v;
}

#define MIX(a, b, rate)		( (a) * (1 - (rate)) + (b) * (rate) )

double
tbl_lookup(double *tbl, int n, double d_idx)
{
	int i;

	i = (int)d_idx;
	d_idx -= i;
	i %= n;
	return MIX(tbl[i], tbl[(i+1)%n], d_idx);
}

double
delay_buf_lookup(struct out_rec *ot, struct note_rec *nt, double sec, double *ret_env_v)
{
	double cycle;

	cycle = ot->smp_freq * sec - nt->stat.fst_smp_cnt;
	if(ret_env_v) *ret_env_v = tbl_lookup(nt->stat.delay_buf[1], DELAY_BUF_N, cycle);
	return tbl_lookup(nt->stat.delay_buf[0], DELAY_BUF_N, cycle);
}

double
delay_out(struct out_rec *ot, struct note_rec *nt, struct delay_rec *delay, double *ret_env_v)
{
	double v;

	if(ot->sec - nt->on_sec < delay->sec) return 0;
	v = delay_buf_lookup(ot, nt, ot->sec - delay->sec, ret_env_v) * delay->gain;
	if(ret_env_v) *ret_env_v *= delay->gain;
	return v;
}

double
chorus_out(struct out_rec *ot, struct note_rec *nt)
{
	double dsec, bak_sec;

	dsec = ot->sec - nt->on_sec;
	bak_sec = 0.01 + 0.001 * sin(2 * M_PI * 0.8 * dsec);
	if(dsec < bak_sec) return 0;
	return delay_buf_lookup(ot, nt, ot->sec - bak_sec, NULL);
}

double
tone_out(struct out_rec *ot, struct note_rec *nt, struct tone_rec *tn, double freq, double env_v)
{
	int i;
	double v, v1, v2, lfo_v, modu_v[4];
	struct vco_rec *vco;

	lfo_v = lfo_out(&tn->lfo, &tn->lfo_modu, ot->sec, nt->on_sec);

	for(i=0; i<4; i++) modu_v[i] = 0;
	modu_out(lfo_v, &tn->lfo_modu, modu_v);
	modu_out(env_v, &tn->env_modu, modu_v);

	vco = &tn->vco;
	v1 = vco_out(vco->wave1, &nt->stat.vco[0], freq, ot->sec, modu_v[0]);

	modu_v[1] += vco->tune * (1.0 / 1200);
	v2 = vco_out(vco->wave2, &nt->stat.vco[1], freq, ot->sec, modu_v[1]);
	if(vco->ring){
		v = v1 * v2;
		v1 = (v1 + v2) * 0.5;
		v2 = v;
	}
	v = MIX(v1, v2, vco->mix);

	if(tn->fl1.type != OFF) v = vcf_out(&tn->fl1, &nt->stat.filter[0], ot, modu_v[2], v);
	if(tn->fl2.type != OFF) v = vcf_out(&tn->fl2, &nt->stat.filter[1], ot, modu_v[3], v);

	v *= env_v * tn->level;
	return v;
}

int
note_out(struct out_rec *ot, struct note_rec *nt, double *vl, double *vr)
{
	double v, freq, pan, env_v, d_env_v;
	int nch;
	struct tone_rec *tn;

	nch = nt->ch;
	tn = nt->tone_compo->tone;
	// tone_get() 関数は廃止
	//
	// note_onoff() 関数で tone_compo_get() 関数を使用し、
	// note_rec 構造体に tone_compo_rec 構造体の配列が保持される
	//
	// tone_compo_rec 構造体の配列のうち、
	// 先頭の要素だけ使って試している
	//
	// (env_out() 関数の場合と同様)
	
	freq = note_to_freq(nt->tone_compo->note >= 0 ? nt->tone_compo->note : nt->note);
	// tone_get() 関数で、周波数への換算もしていたので、
	// その処理は、ここに追加している
	
	if(nt->stat.fst_smp_cnt < 0) nt->stat.fst_smp_cnt = ot->smp_cnt;

	if(ch_inf[nch].bend != 0) freq *= pow(2, ch_inf[nch].bend * ch_inf[nch].bend_range * (1.0 / (8192 * 12)));

	env_v = env_out(nt, ot->sec);
	v = (env_v > 0) ? tone_out(ot, nt, tn, freq, env_v) : 0;

	d_env_v = 0;
	if(tn->delay.onoff) v += delay_out(ot, nt, &tn->delay, &d_env_v);
	d_env_v += env_v;
	delay_buf_set(ot, nt, v, d_env_v);
	if(tn->chorus) v += chorus_out(ot, nt);

	v *= (nt->velo * (1.0 / 127)) * (ch_inf[nch].vol * (1.0 / ((1<<14)-1)));
	if(ot->ch_num == 1){
		*vl += v;
	}else{
		pan = ch_inf[nch].pan * (1.0 / (1<<14));
		*vl += (1 - pan) * v;
		*vr += pan * v;
	}
	return nt->onoff == 0 && ot->sec - nt->off_sec >= tn->env.release &&
		(!tn->delay.onoff || d_env_v < 0.01);
}

void
data_out(struct out_rec *ot, double evt_sec)
{
	double vl, vr;
	int i;
	struct note_rec *nt;

	while((ot->sec = ot->smp_t * ot->smp_cnt) < evt_sec){
		vl = vr = 0;
		for(i=0; i<NOTE_BUF_N; i++){
			if(note_buf_is_free(i)) continue;
			nt = &note_buf[i];
			if(note_out(ot, nt, &vl, &vr)) note_buf_free(i);
		}
		out_do(ot, vl * (1.0 / 16));
		if(ot->ch_num > 1) out_do(ot, vr * (1.0 / 16));
		ot->smp_cnt++;
	}
}

void
note_onoff(int onoff, double evt_sec, int ch, int note, int velo)
{
	int i, tone_n;
	struct tone_compo_rec *tone_compo;

	if(onoff){
		if((i = note_buf_search(-1, -1, -1)) < 0){
			MSG("note_buf full");
			return;
		}
		note_buf[i].note = note;
		note_buf[i].ch = ch;
		note_buf[i].onoff = 1;
		note_buf[i].on_sec = evt_sec;
		note_buf[i].velo = velo;

		stat_init(&note_buf[i].stat, evt_sec);
		if((tone_compo = tone_compo_get(ch, note, &tone_n)) == NULL){
			note_buf_free(i);
			return;
		}
		// 追加した tone_compo_get() 関数をここで呼び出す
		// 音色が見つからなければ、鍵盤情報の割り当て自体をキャンセル
		
		note_buf[i].tone_compo = tone_compo;
		// 取得した tone_compo_rec 構造体の配列を、
		// note_rec 構造体に記録
		
	}else{
		if((i = note_buf_search(ch, note, 1)) < 0) return;
		note_buf[i].stat.off_v = env_out(&note_buf[i], evt_sec);
		note_buf[i].onoff = 0;
		note_buf[i].off_sec = evt_sec;
	}
}

void
msb_set(int *vp, int v)
{
	*vp &= ~(127<<7);
	*vp |= v<<7;
}

void
lsb_set(int *vp, int v)
{
	*vp &= ~127;
	*vp |= v;
}

void
bend_note_update(int ch, double sec)
{
	int i, j;
	struct note_rec *nt;
	struct vco_stat_rec *stat;

	for(i=0; i<NOTE_BUF_N; i++){
		if(note_buf_is_free(i)) continue;
		nt = &note_buf[i];
		if(nt->ch != ch) continue;
		for(j=0; j<2; j++){
			stat = &nt->stat.vco[j];
			vco_stat_update(stat, stat->freq, sec);
		}
	}
}

int
main(int ac, char **av)
{
	int div4, delta_sum;
	int i, n, v, hi, low, note, velo;
	int ch, type;
	double sec;
	struct out_rec otr;
	int tempo, tempo_delta_sum;
	double tempo_sec;

	out_init(&otr, ac, av);
	note_buf_init();
	for(i=0; i<MIDI_CH_N; i++){
		ch_inf[i].vol = 0;
		ch_inf[i].pan = 1<<(14-1);
		ch_inf[i].bend = 0;
		ch_inf[i].rpn = 0;
		ch_inf[i].bend_range = 2;
		ch_inf[i].prog =-1;
	}
	tempo = 500000;
	tempo_delta_sum = 0;
	tempo_sec = 0;

	div4 = header();

	if(!rd_str_chk(4, "MTrk")) ERR("track id");
	v = rd_int(4); /* skip */

	hi = low = 0;
	delta_sum = 0;
	while((v = rd_delta()) != EOF){
		delta_sum += v;
		sec = tempo_sec + (double)(delta_sum - tempo_delta_sum) / div4 * tempo * 0.000001;
		
		if((v = rd()) & 0x80){
			hi = (v >> 4) & 0xf;
			low  = v & 0xf;
		}else bk(v);

		data_out(&otr, sec);

		ch = low;
		switch(hi){
		case 8:
		case 9:
			note = rd();
			velo = rd();
			note_onoff(hi == 9, sec, ch, note, velo);
			break;
		case 0xb: /* control change */
			type = rd();
			v = rd();
			switch(type){
			case 7: /* channel volume msb */
				msb_set(&ch_inf[ch].vol, v);
				break;
			case 39: /* channel volume lsb */
				lsb_set(&ch_inf[ch].vol, v);
				break;
			case 10: /* pan msb */
				msb_set(&ch_inf[ch].pan, v);
				break;
			case 42: /* pan lsb */
				lsb_set(&ch_inf[ch].pan, v);
				break;
			case 100: /* rpn lsb */
				lsb_set(&ch_inf[ch].rpn, v);
				break;
			case 101: /* rpn msb */
				msb_set(&ch_inf[ch].rpn, v);
				break;
			case 6: /* data entry msb */
				switch(ch_inf[ch].rpn){
				case 0: /* pitch bend range */
					ch_inf[ch].bend_range = v;
					break;
				}
				break;
			}
			break;
		case 0xa:
			rd();
			rd();
			break;
		case 0xe: /* pitch wheel change */
			bend_note_update(ch, sec);
			v = rd();
			v |= rd() << 7;
			ch_inf[ch].bend = v - 8192;
			break;
		case 0xc: /* program number */
			v = rd();
			ch_inf[ch].prog = v;
			break;
		case 0xd:
			rd();
			break;
		case 0xf:
			type = rd();
			switch(low){
			case 0:
				while(rd() != 0xf7);
				break;
			case 1:
			case 3:
				rd();
				break;
			case 2:
				rd();
				rd();
				break;
			case 0xf: /* meta */
				n = rd();
				switch(type){
				case 0x51: /* set tempo */
					v = rd_int(n);
					tempo = v;
					tempo_delta_sum = delta_sum;
					tempo_sec = sec;
					break;
				default:
					for(i=0; i<n; i++) rd();
					break;
				}
				break;
			default:
				break;
			}
			break;
		}
	}
	if(otr.fp != stdout) pclose(otr.fp);
	return 0;
}

/* EOF */


prog24.c 解説

prog23.c からの変更箇所のみ

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <math.h>

#define MSG(s) fprintf(stderr, "%s() %s L%d : %s\n", __func__, __FILE__, __LINE__, s)
#define ERR(s) do{ fprintf(stderr, "ERR "); MSG(s); exit(1); }while(0)

int bk_buf = -1;

int
rd(void)
{
	int v;

	if((v = bk_buf) < 0) return getchar();
	bk_buf = -1;
	return v;
}

void
bk(int v)
{
	if(bk_buf >= 0) ERR("give up");
	bk_buf = v;
}

void
rd_str(int n, char *s)
{
	int i;

	for(i=0; i<n; i++) s[i] = rd();
	s[i] = '\0';
}

int
rd_str_chk(int n, char *s)
{
	char buf[256];

	rd_str(n, buf);
	return strcmp(buf, s) == 0;
}

int
rd_int(int n) /* big endian */
{
	int i, v;

	v = 0;
	for(i=0; i<n; i++) v = (v << 8) | rd();
	return v;
}

int
rd_delta(void)
{
	int v, c;

	v = 0;
	do{
		if((c = rd()) == EOF) return EOF;
		v = (v << 7) | (c & 0x7f);
	}while(c & 0x80);
	return v;
}


int
opt_idx(char *key, int ac, char **av)
{
	int i;

	for(i=1; i<ac; i++) if(strcmp(av[i], key) == 0) return i;
	return -1;
}

char *
opt_str(char *key, int ac, char **av, char *def)
{
	int i;

	i = opt_idx(key, ac, av);
	if(i < 0 || i+1 >= ac) return def;
	return av[i+1];
}

int
opt_int(char *key, int ac, char **av, int def)
{
	char *s;

	if((s = opt_str(key, ac, av, NULL)) == NULL) return def;
	return strtol(s, NULL, 0);
}

struct out_rec{
	int smp_freq, smp_cnt;
	int bit_len;
	int sign;
	int ch_num;
	FILE *fp;

	int base;
	int amp;
	int iv_min;
	int iv_max;
	double smp_t, sec;
};

int
sox_version(void)
{
	FILE *fp;
	int v1, v2, v3;

	if((fp = popen("sox --version | sed -e 's/^.*v//'", "r")) == NULL) return -1;
	fscanf(fp, "%d.%d.%d", &v1, &v2, &v3);
	pclose(fp);
	return v1*10000 + v2*100 + v3;
}

char *
sox_bit_len_fmt(int bit_len)
{
	return sox_version() >= 140400 ? 
		(bit_len == 8 ? "-b 8" : "-b 16") : 
		(bit_len == 8 ? "-b" : "-w");
}

void
out_init(struct out_rec *ot, int ac, char **av)
{
	char cmd[1024], *fn;

	ot->smp_freq = opt_int("-r", ac, av, 44100);
	ot->smp_cnt = 0;
	ot->bit_len = opt_int("-b", ac, av, 16);
	if(ot->bit_len != 8 && ot->bit_len != 16) ERR("bit_len");
	ot->sign = (opt_idx("-u", ac, av) < 0);
	ot->ch_num = opt_int("-c", ac, av, 2);

	ot->fp = stdout;
	cmd[0] = '\0';
	fn = "";
	if(opt_idx("-play", ac, av) >= 0){
		strcat(cmd, "play");
	}else if(opt_idx("-sox", ac, av) >= 0){
		strcat(cmd, "sox");
		fn = opt_str("-sox", ac, av, "-d");
	}
	if(cmd[0]){
		sprintf(cmd + strlen(cmd), " -t raw -r %d %s %s -c %d - %s",
			ot->smp_freq, sox_bit_len_fmt(ot->bit_len),
			ot->sign ? "-s" : "-u",
			ot->ch_num, fn);
		if((ot->fp = popen(cmd, "w")) == NULL) ERR("popen");
	}
	ot->amp = ot->bit_len == 8 ? 127 : 32767;
	ot->base = ot->sign ? 0 : ot->amp + 1;
	ot->iv_min = ot->base - (ot->amp + 1);
	ot->iv_max = ot->base + ot->amp;

	ot->smp_t = 1.0 / ot->smp_freq;
}

void
out_do(struct out_rec *ot, double v)
{
	int iv;

	iv = ot->base + (int)(v * ot->amp);
	if(iv > ot->iv_max) iv = ot->iv_max;
	if(iv < ot->iv_min) iv = ot->iv_min;
	switch(ot->bit_len){
	case 8:
		fputc(iv, ot->fp);
		break;
	case 16:
		fputc(iv & 0xff, ot->fp);
		fputc((iv >> 8) & 0xff, ot->fp);
		break;
	}
}

#define OFF		0
#define ON		1

#define LPF		1
#define HPF		2
#define BPF		3

struct filter_rec{
	int type; /* OFF, LPF, HPF, BPF */
	double freq, Q;
};

struct filter_stat_rec{
	int idx;
	double in[4], out[4];
	double a0, a1, a2, b0, b1, b2, div_a0;
};

void
filter_update(struct filter_rec *fl, struct filter_stat_rec *stat, struct out_rec *ot)
{
	double w0, alpha, cos_w0;

	if(fl->type == OFF) return;

	w0 = 2 * M_PI * fl->freq * ot->smp_t;
	cos_w0 = cos(w0);
	alpha = sin(w0) / (2 * fl->Q);

	switch(fl->type){
	case LPF:
		stat->b1 = 1 - cos_w0;
		stat->b0 = stat->b2 = stat->b1 * 0.5;
		break;
	case HPF:
		stat->b1 = -(1 + cos_w0);
		stat->b0 = stat->b2 = -stat->b1 * 0.5;
		break;
	case BPF:
		stat->b0 = fl->Q * alpha;
		stat->b1 = 0;
		stat->b2 = -stat->b0;
		break;
	}
	stat->a0 = 1 + alpha;
	stat->a1 = -2 * cos_w0;
	stat->a2 = 1 - alpha;
	if(stat->a0 != 0) stat->div_a0 = 1 / stat->a0;
}

void
filter_init(struct filter_rec *fl, struct filter_stat_rec *stat, struct out_rec *ot)
{
	int i;

	for(i=0; i<4; i++) stat->in[i] = stat->out[i] = 0;
	stat->idx = 0;

	filter_update(fl, stat, ot);
}

double
filter_out(struct filter_stat_rec *stat, double in)
{
	double *out_p;
	int i_1, i_2;

	stat->in[stat->idx] = in;
	out_p = &stat->out[stat->idx];

	if(stat->a0 != 0){
		i_1 = (stat->idx + 4 - 1) & 3;
		i_2 = (i_1 + 4 - 1) & 3;
		*out_p = (stat->b0 * in
			+ stat->b1 * stat->in[i_1]
			+ stat->b2 * stat->in[i_2]
			- stat->a1 * stat->out[i_1]
			- stat->a2 * stat->out[i_2] ) * stat->div_a0;
	}else{
		*out_p = 0;
	}
	stat->idx = (stat->idx + 1) & 3;
	return *out_p;
}


#define NOTE_BUF_N	256
#define STAT_BUF_N	256

struct vco_stat_rec{
	double cycle, freq, sec;
};

void
vco_stat_update(struct vco_stat_rec *stat, double freq, double sec)
{
	stat->cycle += freq * (sec - stat->sec);	
	stat->freq = freq;
	stat->sec = sec;
}

#define DELAY_BUF_N	(44100 * 5 / 10) /* max 0.5 sec */

struct note_rec;
struct tone_compo_rec;

struct stat_rec{
	struct vco_stat_rec vco[2];
	struct filter_stat_rec filter[2];
	double off_v;
	int fst_smp_cnt;
	double delay_buf[2][ DELAY_BUF_N ];

	struct note_rec *nt;
	struct tone_compo_rec *tone_compo;
	struct stat_rec *next;
} stat_buf[ STAT_BUF_N ];

void
stat_init(struct stat_rec *stat, double sec)
{
	int i;
	struct vco_stat_rec *vco;

	for(i=0; i<2; i++){
		vco = &stat->vco[i];
		vco->cycle = 0;
		vco->sec = sec;
	}
	for(i=0; i<2; i++){
		stat->filter[i].idx = -1;
	}
	stat->fst_smp_cnt = -1;
}

void
stat_buf_init(void)
{
	int i;

	for(i=0; i<STAT_BUF_N; i++) stat_buf[i].nt = NULL;
}

struct note_rec{
	int ch;
	int note;
	int onoff;
	double on_sec;
	double off_sec;
	int velo;

	struct stat_rec *stat; /* current */
	struct stat_rec *stat_lst;
} note_buf[NOTE_BUF_N];

int
note_buf_is_free(int i)
{
	return note_buf[i].ch < 0;
}

void
note_buf_free(int i)
{
	note_buf[i].ch = -1;
}

void
note_buf_init(void)
{
	int i;

	for(i=0; i<NOTE_BUF_N; i++) note_buf_free(i);
}

int
note_buf_search(int ch, int note, int onoff)
{
	int i;

	for(i=0; i<NOTE_BUF_N; i++) {
		if( (ch < 0 && note_buf[i].ch < 0) ||
		    (note_buf[i].ch == ch &&
		     note_buf[i].note == note &&
		     note_buf[i].onoff == onoff) ) return i;
	}
	return -1;
}

int
header(void)
{
	int v;

	if(!rd_str_chk(4, "MThd")) ERR("header id");
	if(rd_int(4) != 6) ERR("header size");
	if(rd_int(2) != 0) ERR("header format type");
	if(rd_int(2) != 1) ERR("header track num");
	if((v = rd_int(2)) & 0x8000) ERR("header division");
	return v; /* div4 */
}

double
note_to_freq(int note)
{
	return 440 * pow(2, (note - 69) / 12.0);
}

#define WAVE_SIN	0
#define WAVE_SAW	1
#define WAVE_SQUARE	2
#define WAVE_NOISE	3

double
wave_out(int wave, double cycle)
{
	cycle -= (int)cycle;

	switch(wave){
	case WAVE_SIN:
		return sin(2 * M_PI * cycle);
	case WAVE_SAW:
		cycle *= 2;
		if(cycle > 1) cycle -= 2;
		return cycle;
	case WAVE_SQUARE:
		return cycle < 0.5 ? 1 : -1;
	case WAVE_NOISE:
		return ((double)rand() / RAND_MAX) * 2 - 1;
	}
	return 0;
}

struct vco_rec{
	int wave1, wave2;
	int tune; /* for vco2 */
	double mix;
	int ring;
};

struct modu_rec{
	int pitch1, pitch2, filter1, filter2;
};

struct lfo_rec{
	int wave;
	double freq, delay;
};

struct env_rec{
	double attack;	/* sec */
	double decay;	/* sec */
	double sustain;	/* 0..1 */
	double release;	/* sec */
};

struct delay_rec{
	int onoff;
	double sec, gain;
};

struct tone_rec{
	struct vco_rec vco;
	struct filter_rec fl1, fl2;
	struct env_rec env;
	double level;
	struct modu_rec lfo_modu;
	struct lfo_rec lfo;
	struct modu_rec env_modu;
	struct delay_rec delay;
	int chorus;
} tone_inf[] = {
	{	/* strings */
		{ WAVE_SAW, WAVE_SAW, 12, 0.5, OFF },
		{ LPF, 3000, 1.5 }, { OFF, },
		{ 0.15, 0.5, 0.8, 0.5 },
		1.0,
		{ OFF, 12, OFF, OFF }, { WAVE_SIN, 4, 0.3 },
		{ OFF, OFF, OFF, OFF },
		{ OFF, }, ON,
	},{	/* bass */
		{ WAVE_SAW, WAVE_SQUARE, OFF, 0.5, OFF },
		{ LPF, 1000, 1.5 }, { OFF, },
		{ 0.05, 0.2, 0.4, 0.2 },
		1.0,
		{ OFF, 60, OFF, OFF }, { WAVE_SIN, 1.5, 0.2 },
		{ OFF, OFF, OFF, OFF },
		{ OFF, }, ON,
	},{	/* lead */
		{ WAVE_SQUARE, WAVE_SQUARE, 10, 0.5, OFF },
		{ LPF, 2000, 4 }, { OFF, },
		{ 0.01, 0.2, 0.8, 0.3 },
		1.0,
		{ OFF, 1, 5, OFF }, { WAVE_SIN, 4, 0.3 },
		{ OFF, OFF, OFF, OFF },
		{ ON, 0.2, 0.4}, OFF,
	},{	/* SIN */
		{ WAVE_SIN, WAVE_SIN, OFF, 0, OFF },
		{ LPF, 20000, 0.8 }, { OFF, },
		{ 0, 0.3, 0.2, 0.3 },
		1.4,
		{ 25, OFF, OFF, OFF }, { WAVE_SIN, 6, 0.3 },
		{ OFF, OFF, OFF, OFF },
		{ OFF, }, OFF,
	}
}, drum_tone_inf[] = {
	{	/* bass */
		{ WAVE_SIN, WAVE_NOISE, OFF, 0.4, OFF },
		{ LPF, 400, 1 }, { OFF, },
		{ 0.01, 0.18, 0, 0.18 },
		9.0,
		{ 100, OFF, 30, OFF }, { WAVE_NOISE, 0, 0.5 },
		{ OFF, OFF, OFF, OFF },
		{ OFF, }, OFF,
	},{	/* snare */
		{ WAVE_SQUARE, WAVE_NOISE, OFF, 0.8, ON },
		{ LPF, 1500, 1.7 }, { OFF, }, 
		{ 0, 0.4, 0.3, 0.4 },
		5,
		{ OFF, OFF, OFF, OFF }, {},
		{ OFF, OFF, OFF, OFF },
		{ OFF, }, OFF,
	},{	/* tom */
		{ WAVE_SQUARE, WAVE_NOISE, OFF, 0.5, ON },
		{ LPF, 800, 2.5 }, { OFF, },
		{ 0, 0.03, 0.1, 0.4 },
		5,
		{ OFF, OFF, OFF, OFF }, {},
		{ 200, OFF, 1200, OFF },
		{ OFF, }, OFF,
	},{	/* hi-hat close */
		{ WAVE_SQUARE, WAVE_SQUARE, 700, 0.9, ON },
		{ LPF, 16000, 2 }, { OFF, },
		{ 0, 0.15, 0, 0.15 },
		0.6,
		{ OFF, OFF, OFF, OFF }, {},
		{ OFF, OFF, OFF, OFF },
		{ OFF, }, OFF,
	},{	/* hi-hat open */
		{ WAVE_SQUARE, WAVE_SQUARE, 700, 0.9, ON },
		{ LPF, 16000, 2 }, { OFF, },
		{ 0, 0, 1, 0.35 },
		0.6,
		{ OFF, OFF, OFF, OFF }, {},
		{ OFF, OFF, OFF, OFF },
		{ OFF, }, OFF,
	},{	/* cymbal */
		{ WAVE_NOISE, WAVE_SQUARE, OFF, 0.8, ON },
		{ LPF, 4000, 2 }, { OFF, },
		{ 0, 0.01, 0.2, 0.8 },
		9,
		{ OFF, OFF, OFF, OFF }, {},
		{ OFF, OFF, 600, OFF }, 
		{ OFF, }, OFF,
	},{	/* side stick */
		{ WAVE_NOISE, WAVE_SQUARE, OFF, 0.2, OFF },
		{ LPF, 1700, 3 }, { OFF, },
		{ 0, 0.012, 0.1, 0.7 },
		10,
		{ OFF, OFF, OFF, OFF }, {},
		{ OFF, OFF, OFF, OFF },
		{ OFF, }, OFF,
	}
};

struct tone_compo_rec{
	struct tone_rec *tone;
	int note; /* -1 : event note */
	double rate;
};

#define PROG_DRUM	0

struct{
	int prog, note; /* note for ch 9 */
	struct tone_compo_rec *tone_compo;
} tones_lst[] = {
	{
		PROG_DRUM, 36, /* bass drum1 */
		(struct tone_compo_rec []){
			{ &drum_tone_inf[0], 28, 1.0 }, { NULL, }
		}
	},{
		PROG_DRUM, 37, /* side stick */
		(struct tone_compo_rec []){
			{ &drum_tone_inf[6], 110, 1.0 }, { NULL, }
		}
	},{
		PROG_DRUM, 40, /* electric snare */
		(struct tone_compo_rec []){
			{ &drum_tone_inf[1], 69, 1.0 }, { NULL, }
		}
	},{
		PROG_DRUM, 41, /* low floor tom */
		(struct tone_compo_rec []){
			{ &drum_tone_inf[2], 50, 1.0 }, { NULL, }
		}
	},{
		PROG_DRUM, 42, /* closed hi-hat */
		(struct tone_compo_rec []){
			{ &drum_tone_inf[3], 115 + 8, 1.0 }, { NULL, }
		}
	},{
		PROG_DRUM, 46, /* open hi-hat */
		(struct tone_compo_rec []){
			{ &drum_tone_inf[4], 115 + 8, 1.0 }, { NULL, }
		}
	},{
		PROG_DRUM, 49, /* crash cymbal 1 */
		(struct tone_compo_rec []){
			{ &drum_tone_inf[5], 75, 1.0 }, { NULL, }
		}
	},{
		PROG_DRUM, 57, /* crash cymbal 2 */
		(struct tone_compo_rec []){
			{ &drum_tone_inf[5], 85, 1.0 }, { NULL, }
		}
	},{
		48, -1, /* timpani */
		(struct tone_compo_rec []){
			{ &tone_inf[0], -1, 1.0 }, { NULL, }
		}
	},{
		50, -1, /* strings ensamble 2 */
		(struct tone_compo_rec []){
			{ &tone_inf[0], -1, 1.0 }, { NULL, }
		}
	},{
		35, -1, /* electric bass (pick) */
		(struct tone_compo_rec []){
			{ &tone_inf[1], -1, 1.0 }, { NULL, }
		}
	},{
		79, -1, /* whistle */
		(struct tone_compo_rec []){
			{ &tone_inf[2], -1, 1.0 }, { NULL, }
		}
	},{
		81, -1, /* lead 1 (square) */
		(struct tone_compo_rec []){
			{ &tone_inf[2], -1, 1.0 }, { NULL, }
		}
	},{
		87, -1, /* lead 7 (fifths) */
		(struct tone_compo_rec []){
			{ &tone_inf[2], -1, 1.0 }, { NULL, }
		}
	},{
		24, -1, /* tango accordion */
		(struct tone_compo_rec []){
			{ &tone_inf[3], -1, 1.0 }, { NULL, }
		}
	},{
		67, -1, /* tenor sax */
		(struct tone_compo_rec []){
			{ &tone_inf[3], -1, 1.0 }, { NULL, }
		}
	},{
		-1, /* tail */
	}
};

void
stat_lst_free(struct stat_rec *stat)
{
	if(!stat) return;
	stat->nt = NULL;
	stat_lst_free(stat->next);
}

struct stat_rec *
stat_lst_alloc_init(int n, double sec, struct note_rec *nt, struct tone_compo_rec *tone_compo_arr, struct stat_rec *next)
{
	struct stat_rec *stat;
	int i;

	if(n > 1){
		next = stat_lst_alloc_init(n - 1, sec, nt, tone_compo_arr + 1, next);
		if(next == NULL) return NULL;
	}
	for(i=0; i<STAT_BUF_N; i++) if(stat_buf[i].nt == NULL) break;
	if(i >= STAT_BUF_N){
		stat_lst_free(next);
		return NULL;
	}
	stat = &stat_buf[i];
	stat->nt = nt;
	stat->tone_compo = tone_compo_arr;
	stat->next = next;
	stat_init(stat, sec);
	return stat;
}

#define MIDI_CH_N	16
struct ch_rec{
	int vol;
	int pan;
	int bend;
	int rpn;
	int bend_range;
	int prog;
} ch_inf[ MIDI_CH_N ];

#define CH_PROG(ch)	( (ch) == 9 ? 0 : ch_inf[ch].prog )

struct tone_compo_rec *
tone_compo_get(int ch, int note, int *ret_n)
{
	struct tone_compo_rec *tone_compo;
	int prog, i;

	prog = CH_PROG(ch);
	for(i=0; tones_lst[i].prog >= 0; i++){
		if(tones_lst[i].prog == prog &&
		   (tones_lst[i].note == note || tones_lst[i].note < 0)) break;
	}
	if(tones_lst[i].prog < 0) return NULL; /* not found */
	tone_compo = tones_lst[i].tone_compo;
	if(ret_n){
		for(i=0; tone_compo[i].tone; i++);
		*ret_n = i;
	}
	return tone_compo;
}

double
env_out(struct note_rec *nt, double sec)
{
	struct tone_rec *tn;
	struct env_rec *e;
	double v;

	tn = nt->stat->tone_compo->tone;
	e = &tn->env;
	if(nt->onoff){
		sec -= nt->on_sec;
		if(sec < e->attack){
			v = sec / e->attack;
			return log10(1 + v * 9);
		}
		sec -= e->attack;
		if(sec < e->decay){
			v = sec / e->decay;
			v = log10(1 + v * 9);
			return 1 - v * (1 - e->sustain);
		}
		return e->sustain;
	}
	sec -= nt->off_sec;
	if(sec < e->release){
		v = sec / e->release;
		v = log10(1 + v * 9);
		return (1 - v) * nt->stat->off_v;
	}
	return 0;
}

void
modu_out(double v, struct modu_rec *modu, double *ret_arr)
{
	if(modu->pitch1) ret_arr[0] += v * modu->pitch1 * (1.0 / 1200);
	if(modu->pitch2) ret_arr[1] += v * modu->pitch2 * (1.0 / 1200);
	if(modu->filter1) ret_arr[2] += v * modu->filter1 * (1.0 / 1200);
	if(modu->filter2) ret_arr[3] += v * modu->filter2 * (1.0 / 1200);
}

double
lfo_out(struct lfo_rec *lfo, struct modu_rec *modu, double sec, double on_sec)
{
	double dsec;

	if(!(modu->pitch1 || modu->pitch2 || modu->filter1 || modu->filter2)) return 0;
	if((dsec = sec - on_sec - lfo->delay) <= 0) return 0;
	return wave_out(lfo->wave, lfo->freq * dsec);
}

double
vco_out(int wave, struct vco_stat_rec *stat, double freq, double sec, double modu_v)
{
	if(modu_v != 0) freq *= pow(2, modu_v);
	vco_stat_update(stat, freq, sec);
	return wave_out(wave, stat->cycle);
}

double
vcf_out(struct filter_rec *fl, struct filter_stat_rec *stat, struct out_rec *ot, double modu_v, double v)
{
	struct filter_rec tmp;

	if(stat->idx < 0) filter_init(fl, stat, ot);
	if(modu_v != 0){
		tmp = *fl;
		tmp.freq *= pow(2, modu_v);
		filter_update(&tmp, stat, ot);
	}
	return filter_out(stat, v);
}

void
delay_buf_set(struct out_rec *ot, struct note_rec *nt, double v, double env_v)
{
	int i;

	i = (ot->smp_cnt - nt->stat->fst_smp_cnt) % DELAY_BUF_N;
	nt->stat->delay_buf[0][i] = v;
	nt->stat->delay_buf[1][i] = env_v;
}

#define MIX(a, b, rate)		( (a) * (1 - (rate)) + (b) * (rate) )

double
tbl_lookup(double *tbl, int n, double d_idx)
{
	int i;

	i = (int)d_idx;
	d_idx -= i;
	i %= n;
	return MIX(tbl[i], tbl[(i+1)%n], d_idx);
}

double
delay_buf_lookup(struct out_rec *ot, struct note_rec *nt, double sec, double *ret_env_v)
{
	double cycle;

	cycle = ot->smp_freq * sec - nt->stat->fst_smp_cnt;
	if(ret_env_v) *ret_env_v = tbl_lookup(nt->stat->delay_buf[1], DELAY_BUF_N, cycle);
	return tbl_lookup(nt->stat->delay_buf[0], DELAY_BUF_N, cycle);
}

double
delay_out(struct out_rec *ot, struct note_rec *nt, struct delay_rec *delay, double *ret_env_v)
{
	double v;

	if(ot->sec - nt->on_sec < delay->sec) return 0;
	v = delay_buf_lookup(ot, nt, ot->sec - delay->sec, ret_env_v) * delay->gain;
	if(ret_env_v) *ret_env_v *= delay->gain;
	return v;
}

double
chorus_out(struct out_rec *ot, struct note_rec *nt)
{
	double dsec, bak_sec;

	dsec = ot->sec - nt->on_sec;
	bak_sec = 0.01 + 0.001 * sin(2 * M_PI * 0.8 * dsec);
	if(dsec < bak_sec) return 0;
	return delay_buf_lookup(ot, nt, ot->sec - bak_sec, NULL);
}

double
tone_out(struct out_rec *ot, struct note_rec *nt, struct tone_rec *tn, double freq, double env_v)
{
	int i;
	double v, v1, v2, lfo_v, modu_v[4];
	struct vco_rec *vco;

	lfo_v = lfo_out(&tn->lfo, &tn->lfo_modu, ot->sec, nt->on_sec);

	for(i=0; i<4; i++) modu_v[i] = 0;
	modu_out(lfo_v, &tn->lfo_modu, modu_v);
	modu_out(env_v, &tn->env_modu, modu_v);

	vco = &tn->vco;
	v1 = vco_out(vco->wave1, &nt->stat->vco[0], freq, ot->sec, modu_v[0]);

	modu_v[1] += vco->tune * (1.0 / 1200);
	v2 = vco_out(vco->wave2, &nt->stat->vco[1], freq, ot->sec, modu_v[1]);
	if(vco->ring){
		v = v1 * v2;
		v1 = (v1 + v2) * 0.5;
		v2 = v;
	}
	v = MIX(v1, v2, vco->mix);

	if(tn->fl1.type != OFF) v = vcf_out(&tn->fl1, &nt->stat->filter[0], ot, modu_v[2], v);
	if(tn->fl2.type != OFF) v = vcf_out(&tn->fl2, &nt->stat->filter[1], ot, modu_v[3], v);

	v *= env_v * tn->level;
	return v;
}

int
note_out(struct out_rec *ot, struct note_rec *nt, double *vl, double *vr)
{
	double v, sum_v, freq, pan, env_v, d_env_v;
	int nch, cnt;
	struct tone_rec *tn;
	struct tone_compo_rec *tone_compo;
	struct stat_rec *stat;

	nch = nt->ch;
	cnt = 0;
	sum_v = 0;
	for(stat=nt->stat_lst; stat; stat=stat->next){
		tone_compo = stat->tone_compo;
		if(tone_compo == NULL) continue;
		cnt++;
		nt->stat = stat; /* back compati */
		tn = tone_compo->tone;
		freq = note_to_freq(tone_compo->note >= 0 ? tone_compo->note : nt->note);

		if(nt->stat->fst_smp_cnt < 0) nt->stat->fst_smp_cnt = ot->smp_cnt;
		if(ch_inf[nch].bend != 0) freq *= pow(2, ch_inf[nch].bend * ch_inf[nch].bend_range * (1.0 / (8192 * 12)));

		env_v = env_out(nt, ot->sec);
		v = (env_v > 0) ? tone_out(ot, nt, tn, freq, env_v) : 0;

		d_env_v = 0;
		if(tn->delay.onoff) v += delay_out(ot, nt, &tn->delay, &d_env_v);
		d_env_v += env_v;
		delay_buf_set(ot, nt, v, d_env_v);
		if(tn->chorus) v += chorus_out(ot, nt);

		sum_v += v * tone_compo->rate;

		if(nt->onoff == 0 && ot->sec - nt->off_sec >= tn->env.release && (!tn->delay.onoff || d_env_v < 0.01)){
			nt->stat->tone_compo = NULL;
		}
	}
	v = sum_v;

	v *= (nt->velo * (1.0 / 127)) * (ch_inf[nch].vol * (1.0 / ((1<<14)-1)));
	if(ot->ch_num == 1){
		*vl += v;
	}else{
		pan = ch_inf[nch].pan * (1.0 / (1<<14));
		*vl += (1 - pan) * v;
		*vr += pan * v;
	}
	return cnt == 0;
}

void
data_out(struct out_rec *ot, double evt_sec)
{
	double vl, vr;
	int i;
	struct note_rec *nt;

	while((ot->sec = ot->smp_t * ot->smp_cnt) < evt_sec){
		vl = vr = 0;
		for(i=0; i<NOTE_BUF_N; i++){
			if(note_buf_is_free(i)) continue;
			nt = &note_buf[i];
			if(note_out(ot, nt, &vl, &vr)){
				stat_lst_free(nt->stat_lst);
				note_buf_free(i);
			}
		}
		out_do(ot, vl * (1.0 / 16));
		if(ot->ch_num > 1) out_do(ot, vr * (1.0 / 16));
		ot->smp_cnt++;
	}
}

void
note_onoff(int onoff, double evt_sec, int ch, int note, int velo)
{
	int i, tone_n;
	struct note_rec *nt;
	struct stat_rec *stat;
	struct tone_compo_rec *tone_compo;

	if(onoff){
		if((i = note_buf_search(-1, -1, -1)) < 0){
			MSG("note_buf full");
			return;
		}
		nt = &note_buf[i];
		nt->note = note;
		nt->ch = ch;
		nt->onoff = 1;
		nt->on_sec = evt_sec;
		nt->velo = velo;

		if((tone_compo = tone_compo_get(ch, note, &tone_n)) == NULL){
			note_buf_free(i);
			return;
		}
		if((nt->stat_lst = stat_lst_alloc_init(tone_n, evt_sec, nt, tone_compo, NULL)) == NULL){
			note_buf_free(i);
		}
	}else{
		if((i = note_buf_search(ch, note, 1)) < 0) return;
		nt = &note_buf[i];
		for(stat=nt->stat_lst; stat; stat=stat->next){
			nt->stat = stat; /* back compati */
			nt->stat->off_v = env_out(nt, evt_sec);
		}
		nt->onoff = 0;
		nt->off_sec = evt_sec;
	}
}

void
msb_set(int *vp, int v)
{
	*vp &= ~(127<<7);
	*vp |= v<<7;
}

void
lsb_set(int *vp, int v)
{
	*vp &= ~127;
	*vp |= v;
}

void
bend_note_update(int ch, double sec)
{
	int i, j;
	struct note_rec *nt;
	struct vco_stat_rec *vco_stat;
	struct stat_rec *stat;

	for(i=0; i<NOTE_BUF_N; i++){
		if(note_buf_is_free(i)) continue;
		nt = &note_buf[i];
		if(nt->ch != ch) continue;
		for(stat=nt->stat_lst; stat; stat=stat->next){
			for(j=0; j<2; j++){
				vco_stat = &stat->vco[j];
				vco_stat_update(vco_stat, vco_stat->freq, sec);
			}
		}
	}
}

int
main(int ac, char **av)
{
	int div4, delta_sum;
	int i, n, v, hi, low, note, velo;
	int ch, type;
	double sec;
	struct out_rec otr;
	int tempo, tempo_delta_sum;
	double tempo_sec;

	out_init(&otr, ac, av);
	note_buf_init();
	stat_buf_init();
	for(i=0; i<MIDI_CH_N; i++){
		ch_inf[i].vol = 0;
		ch_inf[i].pan = 1<<(14-1);
		ch_inf[i].bend = 0;
		ch_inf[i].rpn = 0;
		ch_inf[i].bend_range = 2;
		ch_inf[i].prog =-1;
	}
	tempo = 500000;
	tempo_delta_sum = 0;
	tempo_sec = 0;

	div4 = header();

	if(!rd_str_chk(4, "MTrk")) ERR("track id");
	v = rd_int(4); /* skip */

	hi = low = 0;
	delta_sum = 0;
	while((v = rd_delta()) != EOF){
		delta_sum += v;
		sec = tempo_sec + (double)(delta_sum - tempo_delta_sum) / div4 * tempo * 0.000001;
		
		if((v = rd()) & 0x80){
			hi = (v >> 4) & 0xf;
			low  = v & 0xf;
		}else bk(v);

		data_out(&otr, sec);

		ch = low;
		switch(hi){
		case 8:
		case 9:
			note = rd();
			velo = rd();
			note_onoff(hi == 9, sec, ch, note, velo);
			break;
		case 0xb: /* control change */
			type = rd();
			v = rd();
			switch(type){
			case 7: /* channel volume msb */
				msb_set(&ch_inf[ch].vol, v);
				break;
			case 39: /* channel volume lsb */
				lsb_set(&ch_inf[ch].vol, v);
				break;
			case 10: /* pan msb */
				msb_set(&ch_inf[ch].pan, v);
				break;
			case 42: /* pan lsb */
				lsb_set(&ch_inf[ch].pan, v);
				break;
			case 100: /* rpn lsb */
				lsb_set(&ch_inf[ch].rpn, v);
				break;
			case 101: /* rpn msb */
				msb_set(&ch_inf[ch].rpn, v);
				break;
			case 6: /* data entry msb */
				switch(ch_inf[ch].rpn){
				case 0: /* pitch bend range */
					ch_inf[ch].bend_range = v;
					break;
				}
				break;
			}
			break;
		case 0xa:
			rd();
			rd();
			break;
		case 0xe: /* pitch wheel change */
			bend_note_update(ch, sec);
			v = rd();
			v |= rd() << 7;
			ch_inf[ch].bend = v - 8192;
			break;
		case 0xc: /* program number */
			v = rd();
			ch_inf[ch].prog = v;
			break;
		case 0xd:
			rd();
			break;
		case 0xf:
			type = rd();
			switch(low){
			case 0:
				while(rd() != 0xf7);
				break;
			case 1:
			case 3:
				rd();
				break;
			case 2:
				rd();
				rd();
				break;
			case 0xf: /* meta */
				n = rd();
				switch(type){
				case 0x51: /* set tempo */
					v = rd_int(n);
					tempo = v;
					tempo_delta_sum = delta_sum;
					tempo_sec = sec;
					break;
				default:
					for(i=0; i<n; i++) rd();
					break;
				}
				break;
			default:
				break;
			}
			break;
		}
	}
	if(otr.fp != stdout) pclose(otr.fp);
	return 0;
}

/* EOF */


#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <math.h>

#define MSG(s) fprintf(stderr, "%s() %s L%d : %s\n", __func__, __FILE__, __LINE__, s)
#define ERR(s) do{ fprintf(stderr, "ERR "); MSG(s); exit(1); }while(0)

int bk_buf = -1;

int
rd(void)
{
	int v;

	if((v = bk_buf) < 0) return getchar();
	bk_buf = -1;
	return v;
}

void
bk(int v)
{
	if(bk_buf >= 0) ERR("give up");
	bk_buf = v;
}

void
rd_str(int n, char *s)
{
	int i;

	for(i=0; i<n; i++) s[i] = rd();
	s[i] = '\0';
}

int
rd_str_chk(int n, char *s)
{
	char buf[256];

	rd_str(n, buf);
	return strcmp(buf, s) == 0;
}

int
rd_int(int n) /* big endian */
{
	int i, v;

	v = 0;
	for(i=0; i<n; i++) v = (v << 8) | rd();
	return v;
}

int
rd_delta(void)
{
	int v, c;

	v = 0;
	do{
		if((c = rd()) == EOF) return EOF;
		v = (v << 7) | (c & 0x7f);
	}while(c & 0x80);
	return v;
}


int
opt_idx(char *key, int ac, char **av)
{
	int i;

	for(i=1; i<ac; i++) if(strcmp(av[i], key) == 0) return i;
	return -1;
}

char *
opt_str(char *key, int ac, char **av, char *def)
{
	int i;

	i = opt_idx(key, ac, av);
	if(i < 0 || i+1 >= ac) return def;
	return av[i+1];
}

int
opt_int(char *key, int ac, char **av, int def)
{
	char *s;

	if((s = opt_str(key, ac, av, NULL)) == NULL) return def;
	return strtol(s, NULL, 0);
}

struct out_rec{
	int smp_freq, smp_cnt;
	int bit_len;
	int sign;
	int ch_num;
	FILE *fp;

	int base;
	int amp;
	int iv_min;
	int iv_max;
	double smp_t, sec;
};

int
sox_version(void)
{
	FILE *fp;
	int v1, v2, v3;

	if((fp = popen("sox --version | sed -e 's/^.*v//'", "r")) == NULL) return -1;
	fscanf(fp, "%d.%d.%d", &v1, &v2, &v3);
	pclose(fp);
	return v1*10000 + v2*100 + v3;
}

char *
sox_bit_len_fmt(int bit_len)
{
	return sox_version() >= 140400 ? 
		(bit_len == 8 ? "-b 8" : "-b 16") : 
		(bit_len == 8 ? "-b" : "-w");
}

void
out_init(struct out_rec *ot, int ac, char **av)
{
	char cmd[1024], *fn;

	ot->smp_freq = opt_int("-r", ac, av, 44100);
	ot->smp_cnt = 0;
	ot->bit_len = opt_int("-b", ac, av, 16);
	if(ot->bit_len != 8 && ot->bit_len != 16) ERR("bit_len");
	ot->sign = (opt_idx("-u", ac, av) < 0);
	ot->ch_num = opt_int("-c", ac, av, 2);

	ot->fp = stdout;
	cmd[0] = '\0';
	fn = "";
	if(opt_idx("-play", ac, av) >= 0){
		strcat(cmd, "play");
	}else if(opt_idx("-sox", ac, av) >= 0){
		strcat(cmd, "sox");
		fn = opt_str("-sox", ac, av, "-d");
	}
	if(cmd[0]){
		sprintf(cmd + strlen(cmd), " -t raw -r %d %s %s -c %d - %s",
			ot->smp_freq, sox_bit_len_fmt(ot->bit_len),
			ot->sign ? "-s" : "-u",
			ot->ch_num, fn);
		if((ot->fp = popen(cmd, "w")) == NULL) ERR("popen");
	}
	ot->amp = ot->bit_len == 8 ? 127 : 32767;
	ot->base = ot->sign ? 0 : ot->amp + 1;
	ot->iv_min = ot->base - (ot->amp + 1);
	ot->iv_max = ot->base + ot->amp;

	ot->smp_t = 1.0 / ot->smp_freq;
}

void
out_do(struct out_rec *ot, double v)
{
	int iv;

	iv = ot->base + (int)(v * ot->amp);
	if(iv > ot->iv_max) iv = ot->iv_max;
	if(iv < ot->iv_min) iv = ot->iv_min;
	switch(ot->bit_len){
	case 8:
		fputc(iv, ot->fp);
		break;
	case 16:
		fputc(iv & 0xff, ot->fp);
		fputc((iv >> 8) & 0xff, ot->fp);
		break;
	}
}

#define OFF		0
#define ON		1

#define LPF		1
#define HPF		2
#define BPF		3

struct filter_rec{
	int type; /* OFF, LPF, HPF, BPF */
	double freq, Q;
};

struct filter_stat_rec{
	int idx;
	double in[4], out[4];
	double a0, a1, a2, b0, b1, b2, div_a0;
};

void
filter_update(struct filter_rec *fl, struct filter_stat_rec *stat, struct out_rec *ot)
{
	double w0, alpha, cos_w0;

	if(fl->type == OFF) return;

	w0 = 2 * M_PI * fl->freq * ot->smp_t;
	cos_w0 = cos(w0);
	alpha = sin(w0) / (2 * fl->Q);

	switch(fl->type){
	case LPF:
		stat->b1 = 1 - cos_w0;
		stat->b0 = stat->b2 = stat->b1 * 0.5;
		break;
	case HPF:
		stat->b1 = -(1 + cos_w0);
		stat->b0 = stat->b2 = -stat->b1 * 0.5;
		break;
	case BPF:
		stat->b0 = fl->Q * alpha;
		stat->b1 = 0;
		stat->b2 = -stat->b0;
		break;
	}
	stat->a0 = 1 + alpha;
	stat->a1 = -2 * cos_w0;
	stat->a2 = 1 - alpha;
	if(stat->a0 != 0) stat->div_a0 = 1 / stat->a0;
}

void
filter_init(struct filter_rec *fl, struct filter_stat_rec *stat, struct out_rec *ot)
{
	int i;

	for(i=0; i<4; i++) stat->in[i] = stat->out[i] = 0;
	stat->idx = 0;

	filter_update(fl, stat, ot);
}

double
filter_out(struct filter_stat_rec *stat, double in)
{
	double *out_p;
	int i_1, i_2;

	stat->in[stat->idx] = in;
	out_p = &stat->out[stat->idx];

	if(stat->a0 != 0){
		i_1 = (stat->idx + 4 - 1) & 3;
		i_2 = (i_1 + 4 - 1) & 3;
		*out_p = (stat->b0 * in
			+ stat->b1 * stat->in[i_1]
			+ stat->b2 * stat->in[i_2]
			- stat->a1 * stat->out[i_1]
			- stat->a2 * stat->out[i_2] ) * stat->div_a0;
	}else{
		*out_p = 0;
	}
	stat->idx = (stat->idx + 1) & 3;
	return *out_p;
}


#define NOTE_BUF_N	256
#define STAT_BUF_N	256
// 状態を保持するバッファ数の定義を追加

struct vco_stat_rec{
	double cycle, freq, sec;
};

void
vco_stat_update(struct vco_stat_rec *stat, double freq, double sec)
{
	stat->cycle += freq * (sec - stat->sec);	
	stat->freq = freq;
	stat->sec = sec;
}

#define DELAY_BUF_N	(44100 * 5 / 10) /* max 0.5 sec */

struct note_rec;
struct tone_compo_rec;
// stat_rec 構造体のメンバで参照するので、
// note_rec 構造体と、tone_compo_rec 構造体について
// この位置で宣言だけしておく

struct stat_rec{
	struct vco_stat_rec vco[2];
	struct filter_stat_rec filter[2];
	double off_v;
	int fst_smp_cnt;
	double delay_buf[2][ DELAY_BUF_N ];

	struct note_rec *nt;
	// note_rec 構造体のポインタを追加
	
	struct tone_compo_rec *tone_compo;
	// tone_compo_rec 構造体のポインタを追加
	
	struct stat_rec *next;
	// バッファのチェーン用のポインタを追加
	
} stat_buf[ STAT_BUF_N ];
// 状態を保持するバッファの配列の定義を追加

void
stat_init(struct stat_rec *stat, double sec)
{
	int i;
	struct vco_stat_rec *vco;

	for(i=0; i<2; i++){
		vco = &stat->vco[i];
		vco->cycle = 0;
		vco->sec = sec;
	}
	for(i=0; i<2; i++){
		stat->filter[i].idx = -1;
	}
	stat->fst_smp_cnt = -1;
}

void
stat_buf_init(void)
{
	// stat_rec 構造体のバッファの配列の初期化
	// メンバの note_rec 構造体のポインタを、NULL で初期化
	//
	// このポインタが NULL ならば未使用とする
	
	int i;

	for(i=0; i<STAT_BUF_N; i++) stat_buf[i].nt = NULL;
}

struct note_rec{
	int ch;
	int note;
	int onoff;
	double on_sec;
	double off_sec;
	int velo;

	struct stat_rec *stat; /* current */
	// stat_rec 構造体を、stat_rec 構造体のポインタに変更
	// stat_lst のチェーンの中で、現在処理中のものを指す
	
	struct stat_rec *stat_lst;
	// tone_compo_rec 構造体のポインタを、
	// stat_rec 構造体のポインタに変更
	//
	// stat_rec 構造体は、チェーンリストで複数個割り付けられる
	
} note_buf[NOTE_BUF_N];

int
note_buf_is_free(int i)
{
	return note_buf[i].ch < 0;
}

void
note_buf_free(int i)
{
	note_buf[i].ch = -1;
}

void
note_buf_init(void)
{
	int i;

	for(i=0; i<NOTE_BUF_N; i++) note_buf_free(i);
}

int
note_buf_search(int ch, int note, int onoff)
{
	int i;

	for(i=0; i<NOTE_BUF_N; i++) {
		if( (ch < 0 && note_buf[i].ch < 0) ||
		    (note_buf[i].ch == ch &&
		     note_buf[i].note == note &&
		     note_buf[i].onoff == onoff) ) return i;
	}
	return -1;
}

int
header(void)
{
	int v;

	if(!rd_str_chk(4, "MThd")) ERR("header id");
	if(rd_int(4) != 6) ERR("header size");
	if(rd_int(2) != 0) ERR("header format type");
	if(rd_int(2) != 1) ERR("header track num");
	if((v = rd_int(2)) & 0x8000) ERR("header division");
	return v; /* div4 */
}

double
note_to_freq(int note)
{
	return 440 * pow(2, (note - 69) / 12.0);
}

#define WAVE_SIN	0
#define WAVE_SAW	1
#define WAVE_SQUARE	2
#define WAVE_NOISE	3

double
wave_out(int wave, double cycle)
{
	cycle -= (int)cycle;

	switch(wave){
	case WAVE_SIN:
		return sin(2 * M_PI * cycle);
	case WAVE_SAW:
		cycle *= 2;
		if(cycle > 1) cycle -= 2;
		return cycle;
	case WAVE_SQUARE:
		return cycle < 0.5 ? 1 : -1;
	case WAVE_NOISE:
		return ((double)rand() / RAND_MAX) * 2 - 1;
	}
	return 0;
}

struct vco_rec{
	int wave1, wave2;
	int tune; /* for vco2 */
	double mix;
	int ring;
};

struct modu_rec{
	int pitch1, pitch2, filter1, filter2;
};

struct lfo_rec{
	int wave;
	double freq, delay;
};

struct env_rec{
	double attack;	/* sec */
	double decay;	/* sec */
	double sustain;	/* 0..1 */
	double release;	/* sec */
};

struct delay_rec{
	int onoff;
	double sec, gain;
};

struct tone_rec{
	struct vco_rec vco;
	struct filter_rec fl1, fl2;
	struct env_rec env;
	double level;
	struct modu_rec lfo_modu;
	struct lfo_rec lfo;
	struct modu_rec env_modu;
	struct delay_rec delay;
	int chorus;
} tone_inf[] = {
	{	/* strings */
		{ WAVE_SAW, WAVE_SAW, 12, 0.5, OFF },
		{ LPF, 3000, 1.5 }, { OFF, },
		{ 0.15, 0.5, 0.8, 0.5 },
		1.0,
		{ OFF, 12, OFF, OFF }, { WAVE_SIN, 4, 0.3 },
		{ OFF, OFF, OFF, OFF },
		{ OFF, }, ON,
	},{	/* bass */
		{ WAVE_SAW, WAVE_SQUARE, OFF, 0.5, OFF },
		{ LPF, 1000, 1.5 }, { OFF, },
		{ 0.05, 0.2, 0.4, 0.2 },
		1.0,
		{ OFF, 60, OFF, OFF }, { WAVE_SIN, 1.5, 0.2 },
		{ OFF, OFF, OFF, OFF },
		{ OFF, }, ON,
	},{	/* lead */
		{ WAVE_SQUARE, WAVE_SQUARE, 10, 0.5, OFF },
		{ LPF, 2000, 4 }, { OFF, },
		{ 0.01, 0.2, 0.8, 0.3 },
		1.0,
		{ OFF, 1, 5, OFF }, { WAVE_SIN, 4, 0.3 },
		{ OFF, OFF, OFF, OFF },
		{ ON, 0.2, 0.4}, OFF,
	},{	/* SIN */
		{ WAVE_SIN, WAVE_SIN, OFF, 0, OFF },
		{ LPF, 20000, 0.8 }, { OFF, },
		{ 0, 0.3, 0.2, 0.3 },
		1.4,
		{ 25, OFF, OFF, OFF }, { WAVE_SIN, 6, 0.3 },
		{ OFF, OFF, OFF, OFF },
		{ OFF, }, OFF,
	}
}, drum_tone_inf[] = {
	{	/* bass */
		{ WAVE_SIN, WAVE_NOISE, OFF, 0.4, OFF },
		{ LPF, 400, 1 }, { OFF, },
		{ 0.01, 0.18, 0, 0.18 },
		9.0,
		{ 100, OFF, 30, OFF }, { WAVE_NOISE, 0, 0.5 },
		{ OFF, OFF, OFF, OFF },
		{ OFF, }, OFF,
	},{	/* snare */
		{ WAVE_SQUARE, WAVE_NOISE, OFF, 0.8, ON },
		{ LPF, 1500, 1.7 }, { OFF, }, 
		{ 0, 0.4, 0.3, 0.4 },
		5,
		{ OFF, OFF, OFF, OFF }, {},
		{ OFF, OFF, OFF, OFF },
		{ OFF, }, OFF,
	},{	/* tom */
		{ WAVE_SQUARE, WAVE_NOISE, OFF, 0.5, ON },
		{ LPF, 800, 2.5 }, { OFF, },
		{ 0, 0.03, 0.1, 0.4 },
		5,
		{ OFF, OFF, OFF, OFF }, {},
		{ 200, OFF, 1200, OFF },
		{ OFF, }, OFF,
	},{	/* hi-hat close */
		{ WAVE_SQUARE, WAVE_SQUARE, 700, 0.9, ON },
		{ LPF, 16000, 2 }, { OFF, },
		{ 0, 0.15, 0, 0.15 },
		0.6,
		{ OFF, OFF, OFF, OFF }, {},
		{ OFF, OFF, OFF, OFF },
		{ OFF, }, OFF,
	},{	/* hi-hat open */
		{ WAVE_SQUARE, WAVE_SQUARE, 700, 0.9, ON },
		{ LPF, 16000, 2 }, { OFF, },
		{ 0, 0, 1, 0.35 },
		0.6,
		{ OFF, OFF, OFF, OFF }, {},
		{ OFF, OFF, OFF, OFF },
		{ OFF, }, OFF,
	},{	/* cymbal */
		{ WAVE_NOISE, WAVE_SQUARE, OFF, 0.8, ON },
		{ LPF, 4000, 2 }, { OFF, },
		{ 0, 0.01, 0.2, 0.8 },
		9,
		{ OFF, OFF, OFF, OFF }, {},
		{ OFF, OFF, 600, OFF }, 
		{ OFF, }, OFF,
	},{	/* side stick */
		{ WAVE_NOISE, WAVE_SQUARE, OFF, 0.2, OFF },
		{ LPF, 1700, 3 }, { OFF, },
		{ 0, 0.012, 0.1, 0.7 },
		10,
		{ OFF, OFF, OFF, OFF }, {},
		{ OFF, OFF, OFF, OFF },
		{ OFF, }, OFF,
	}
};

struct tone_compo_rec{
	struct tone_rec *tone;
	int note; /* -1 : event note */
	double rate;
};

#define PROG_DRUM	0

struct{
	int prog, note; /* note for ch 9 */
	struct tone_compo_rec *tone_compo;
} tones_lst[] = {
	{
		PROG_DRUM, 36, /* bass drum1 */
		(struct tone_compo_rec []){
			{ &drum_tone_inf[0], 28, 1.0 }, { NULL, }
		}
	},{
		PROG_DRUM, 37, /* side stick */
		(struct tone_compo_rec []){
			{ &drum_tone_inf[6], 110, 1.0 }, { NULL, }
		}
	},{
		PROG_DRUM, 40, /* electric snare */
		(struct tone_compo_rec []){
			{ &drum_tone_inf[1], 69, 1.0 }, { NULL, }
		}
	},{
		PROG_DRUM, 41, /* low floor tom */
		(struct tone_compo_rec []){
			{ &drum_tone_inf[2], 50, 1.0 }, { NULL, }
		}
	},{
		PROG_DRUM, 42, /* closed hi-hat */
		(struct tone_compo_rec []){
			{ &drum_tone_inf[3], 115 + 8, 1.0 }, { NULL, }
		}
	},{
		PROG_DRUM, 46, /* open hi-hat */
		(struct tone_compo_rec []){
			{ &drum_tone_inf[4], 115 + 8, 1.0 }, { NULL, }
		}
	},{
		PROG_DRUM, 49, /* crash cymbal 1 */
		(struct tone_compo_rec []){
			{ &drum_tone_inf[5], 75, 1.0 }, { NULL, }
		}
	},{
		PROG_DRUM, 57, /* crash cymbal 2 */
		(struct tone_compo_rec []){
			{ &drum_tone_inf[5], 85, 1.0 }, { NULL, }
		}
	},{
		48, -1, /* timpani */
		(struct tone_compo_rec []){
			{ &tone_inf[0], -1, 1.0 }, { NULL, }
		}
	},{
		50, -1, /* strings ensamble 2 */
		(struct tone_compo_rec []){
			{ &tone_inf[0], -1, 1.0 }, { NULL, }
		}
	},{
		35, -1, /* electric bass (pick) */
		(struct tone_compo_rec []){
			{ &tone_inf[1], -1, 1.0 }, { NULL, }
		}
	},{
		79, -1, /* whistle */
		(struct tone_compo_rec []){
			{ &tone_inf[2], -1, 1.0 }, { NULL, }
		}
	},{
		81, -1, /* lead 1 (square) */
		(struct tone_compo_rec []){
			{ &tone_inf[2], -1, 1.0 }, { NULL, }
		}
	},{
		87, -1, /* lead 7 (fifths) */
		(struct tone_compo_rec []){
			{ &tone_inf[2], -1, 1.0 }, { NULL, }
		}
	},{
		24, -1, /* tango accordion */
		(struct tone_compo_rec []){
			{ &tone_inf[3], -1, 1.0 }, { NULL, }
		}
	},{
		67, -1, /* tenor sax */
		(struct tone_compo_rec []){
			{ &tone_inf[3], -1, 1.0 }, { NULL, }
		}
	},{
		-1, /* tail */
	}
};

void
stat_lst_free(struct stat_rec *stat)
{
	// stat_rec 構造体の解放処理
	//
	// メンバの note_rec 構造体のポインタを NULL に設定し
	// 未使用の状態にする
	//
	// 続いてチェーンリストの後続の構造体も、
	// 再帰呼び出しで、同様に解放する
	
	if(!stat) return;
	stat->nt = NULL;
	stat_lst_free(stat->next);
}

struct stat_rec *
stat_lst_alloc_init(int n, double sec, struct note_rec *nt, struct tone_compo_rec *tone_compo_arr, struct stat_rec *next)
{
	// 複数個の stat_rec 構造体を、チェーンリストで割り付ける処理
	// 
	// n は要求個数
	// sec は stat_rec 構造体の初期化時に指定するイベント時刻
	
	struct stat_rec *stat;
	int i;

	if(n > 1){
		next = stat_lst_alloc_init(n - 1, sec, nt, tone_compo_arr + 1, next);
		// n が2個以上なら、再帰呼び出しで、まず後続分を割り付ける
		
		if(next == NULL) return NULL;
	}
	for(i=0; i<STAT_BUF_N; i++) if(stat_buf[i].nt == NULL) break;
	// stat_rec 構造体のバッファの配列をサーチして、
	// 未使用の構造体を1つ探す
	
	if(i >= STAT_BUF_N){
		stat_lst_free(next);
		return NULL;
	}
	stat = &stat_buf[i];
	stat->nt = nt;
	stat->tone_compo = tone_compo_arr;
	stat->next = next;
	// stat_rec 構造体に追加したメンバを設定
	// next で、後続分を結合
	
	stat_init(stat, sec);
	// 従来のメンバ部分の初期化
	
	return stat;
}

#define MIDI_CH_N	16
struct ch_rec{
	int vol;
	int pan;
	int bend;
	int rpn;
	int bend_range;
	int prog;
} ch_inf[ MIDI_CH_N ];

#define CH_PROG(ch)	( (ch) == 9 ? 0 : ch_inf[ch].prog )

struct tone_compo_rec *
tone_compo_get(int ch, int note, int *ret_n)
{
	struct tone_compo_rec *tone_compo;
	int prog, i;

	prog = CH_PROG(ch);
	for(i=0; tones_lst[i].prog >= 0; i++){
		if(tones_lst[i].prog == prog &&
		   (tones_lst[i].note == note || tones_lst[i].note < 0)) break;
	}
	if(tones_lst[i].prog < 0) return NULL; /* not found */
	tone_compo = tones_lst[i].tone_compo;
	if(ret_n){
		for(i=0; tone_compo[i].tone; i++);
		*ret_n = i;
	}
	return tone_compo;
}

double
env_out(struct note_rec *nt, double sec)
{
	struct tone_rec *tn;
	struct env_rec *e;
	double v;

	tn = nt->stat->tone_compo->tone;
	// note_rec 構造体のメンバだった、tone_compo_rec 構造体の配列は、廃止
	// 代わりに stat_rec 構造体に、tone_compo_rec 構造体のポインタ(1つ分)を追加
	// stat_rec 構造体経由で、tone_rec 構造体を取得する
	
	e = &tn->env;
	if(nt->onoff){
		sec -= nt->on_sec;
		if(sec < e->attack){
			v = sec / e->attack;
			return log10(1 + v * 9);
		}
		sec -= e->attack;
		if(sec < e->decay){
			v = sec / e->decay;
			v = log10(1 + v * 9);
			return 1 - v * (1 - e->sustain);
		}
		return e->sustain;
	}
	sec -= nt->off_sec;
	if(sec < e->release){
		v = sec / e->release;
		v = log10(1 + v * 9);
		return (1 - v) * nt->stat->off_v;
		// note_rec 構造体のメンバ stat を
		// 構造体から、構造体のポインタへ変更したので、
		// その対応
		
	}
	return 0;
}

void
modu_out(double v, struct modu_rec *modu, double *ret_arr)
{
	if(modu->pitch1) ret_arr[0] += v * modu->pitch1 * (1.0 / 1200);
	if(modu->pitch2) ret_arr[1] += v * modu->pitch2 * (1.0 / 1200);
	if(modu->filter1) ret_arr[2] += v * modu->filter1 * (1.0 / 1200);
	if(modu->filter2) ret_arr[3] += v * modu->filter2 * (1.0 / 1200);
}

double
lfo_out(struct lfo_rec *lfo, struct modu_rec *modu, double sec, double on_sec)
{
	double dsec;

	if(!(modu->pitch1 || modu->pitch2 || modu->filter1 || modu->filter2)) return 0;
	if((dsec = sec - on_sec - lfo->delay) <= 0) return 0;
	return wave_out(lfo->wave, lfo->freq * dsec);
}

double
vco_out(int wave, struct vco_stat_rec *stat, double freq, double sec, double modu_v)
{
	if(modu_v != 0) freq *= pow(2, modu_v);
	vco_stat_update(stat, freq, sec);
	return wave_out(wave, stat->cycle);
}

double
vcf_out(struct filter_rec *fl, struct filter_stat_rec *stat, struct out_rec *ot, double modu_v, double v)
{
	struct filter_rec tmp;

	if(stat->idx < 0) filter_init(fl, stat, ot);
	if(modu_v != 0){
		tmp = *fl;
		tmp.freq *= pow(2, modu_v);
		filter_update(&tmp, stat, ot);
	}
	return filter_out(stat, v);
}

void
delay_buf_set(struct out_rec *ot, struct note_rec *nt, double v, double env_v)
{
	int i;

	i = (ot->smp_cnt - nt->stat->fst_smp_cnt) % DELAY_BUF_N;
	nt->stat->delay_buf[0][i] = v;
	nt->stat->delay_buf[1][i] = env_v;
	// note_rec 構造体のメンバ stat を
	// 構造体から、構造体のポインタへ変更したので、
	// その対応
	
}

#define MIX(a, b, rate)		( (a) * (1 - (rate)) + (b) * (rate) )

double
tbl_lookup(double *tbl, int n, double d_idx)
{
	int i;

	i = (int)d_idx;
	d_idx -= i;
	i %= n;
	return MIX(tbl[i], tbl[(i+1)%n], d_idx);
}

double
delay_buf_lookup(struct out_rec *ot, struct note_rec *nt, double sec, double *ret_env_v)
{
	double cycle;

	cycle = ot->smp_freq * sec - nt->stat->fst_smp_cnt;
	if(ret_env_v) *ret_env_v = tbl_lookup(nt->stat->delay_buf[1], DELAY_BUF_N, cycle);
	return tbl_lookup(nt->stat->delay_buf[0], DELAY_BUF_N, cycle);
	// note_rec 構造体のメンバ stat を
	// 構造体から、構造体のポインタへ変更したので、
	// その対応
	
}

double
delay_out(struct out_rec *ot, struct note_rec *nt, struct delay_rec *delay, double *ret_env_v)
{
	double v;

	if(ot->sec - nt->on_sec < delay->sec) return 0;
	v = delay_buf_lookup(ot, nt, ot->sec - delay->sec, ret_env_v) * delay->gain;
	if(ret_env_v) *ret_env_v *= delay->gain;
	return v;
}

double
chorus_out(struct out_rec *ot, struct note_rec *nt)
{
	double dsec, bak_sec;

	dsec = ot->sec - nt->on_sec;
	bak_sec = 0.01 + 0.001 * sin(2 * M_PI * 0.8 * dsec);
	if(dsec < bak_sec) return 0;
	return delay_buf_lookup(ot, nt, ot->sec - bak_sec, NULL);
}

double
tone_out(struct out_rec *ot, struct note_rec *nt, struct tone_rec *tn, double freq, double env_v)
{
	int i;
	double v, v1, v2, lfo_v, modu_v[4];
	struct vco_rec *vco;

	lfo_v = lfo_out(&tn->lfo, &tn->lfo_modu, ot->sec, nt->on_sec);

	for(i=0; i<4; i++) modu_v[i] = 0;
	modu_out(lfo_v, &tn->lfo_modu, modu_v);
	modu_out(env_v, &tn->env_modu, modu_v);

	vco = &tn->vco;
	v1 = vco_out(vco->wave1, &nt->stat->vco[0], freq, ot->sec, modu_v[0]);
	// note_rec 構造体のメンバ stat を
	// 構造体から、構造体のポインタへ変更したので、
	// その対応
	
	modu_v[1] += vco->tune * (1.0 / 1200);
	v2 = vco_out(vco->wave2, &nt->stat->vco[1], freq, ot->sec, modu_v[1]);
	// note_rec 構造体のメンバ stat を
	// 構造体から、構造体のポインタへ変更したので、
	// その対応
	
	if(vco->ring){
		v = v1 * v2;
		v1 = (v1 + v2) * 0.5;
		v2 = v;
	}
	v = MIX(v1, v2, vco->mix);

	if(tn->fl1.type != OFF) v = vcf_out(&tn->fl1, &nt->stat->filter[0], ot, modu_v[2], v);
	if(tn->fl2.type != OFF) v = vcf_out(&tn->fl2, &nt->stat->filter[1], ot, modu_v[3], v);
	// note_rec 構造体のメンバ stat を
	// 構造体から、構造体のポインタへ変更したので、
	// その対応
	
	v *= env_v * tn->level;
	return v;
}

int
note_out(struct out_rec *ot, struct note_rec *nt, double *vl, double *vr)
{
	// 従来の旧note_out()関数の処理は、forループの中へ移動
	
	double v, sum_v, freq, pan, env_v, d_env_v;
	int nch, cnt;
	struct tone_rec *tn;
	struct tone_compo_rec *tone_compo;
	struct stat_rec *stat;

	nch = nt->ch;
	cnt = 0;
	sum_v = 0;
	for(stat=nt->stat_lst; stat; stat=stat->next){
		tone_compo = stat->tone_compo;
		if(tone_compo == NULL) continue;
		cnt++;
		nt->stat = stat; /* back compati */
		// 互換性のため
		// stat_rec 構造体のチェーンリストから、カレントのポインタを
		// note_rec 構造体のメンバ stat に記録して処理する
		
		tn = tone_compo->tone;
		freq = note_to_freq(tone_compo->note >= 0 ? tone_compo->note : nt->note);

		if(nt->stat->fst_smp_cnt < 0) nt->stat->fst_smp_cnt = ot->smp_cnt;
		if(ch_inf[nch].bend != 0) freq *= pow(2, ch_inf[nch].bend * ch_inf[nch].bend_range * (1.0 / (8192 * 12)));

		env_v = env_out(nt, ot->sec);
		v = (env_v > 0) ? tone_out(ot, nt, tn, freq, env_v) : 0;

		d_env_v = 0;
		if(tn->delay.onoff) v += delay_out(ot, nt, &tn->delay, &d_env_v);
		d_env_v += env_v;
		delay_buf_set(ot, nt, v, d_env_v);
		if(tn->chorus) v += chorus_out(ot, nt);

		sum_v += v * tone_compo->rate;

		if(nt->onoff == 0 && ot->sec - nt->off_sec >= tn->env.release && (!tn->delay.onoff || d_env_v < 0.01)){
			nt->stat->tone_compo = NULL;
		}
	}
	v = sum_v;

	v *= (nt->velo * (1.0 / 127)) * (ch_inf[nch].vol * (1.0 / ((1<<14)-1)));
	if(ot->ch_num == 1){
		*vl += v;
	}else{
		pan = ch_inf[nch].pan * (1.0 / (1<<14));
		*vl += (1 - pan) * v;
		*vr += pan * v;
	}
	return cnt == 0;
	// 鍵盤オン・オフ情報に割り付けられた、各音色の状態が全て終了した状態になり、
	// stat_rec 構造体の更新が無くなれば、
	// その鍵盤オン・オフ情報の処理は終了となる
	
}

void
data_out(struct out_rec *ot, double evt_sec)
{
	double vl, vr;
	int i;
	struct note_rec *nt;

	while((ot->sec = ot->smp_t * ot->smp_cnt) < evt_sec){
		vl = vr = 0;
		for(i=0; i<NOTE_BUF_N; i++){
			if(note_buf_is_free(i)) continue;
			nt = &note_buf[i];
			if(note_out(ot, nt, &vl, &vr)){
				stat_lst_free(nt->stat_lst);
				// 鍵盤オン・オフ情報の処理が終了時に、
				// stat_rec 構造体のバッファの解放処理を追加
				
				note_buf_free(i);
			}
		}
		out_do(ot, vl * (1.0 / 16));
		if(ot->ch_num > 1) out_do(ot, vr * (1.0 / 16));
		ot->smp_cnt++;
	}
}

void
note_onoff(int onoff, double evt_sec, int ch, int note, int velo)
{
	int i, tone_n;
	struct note_rec *nt;
	struct stat_rec *stat;
	struct tone_compo_rec *tone_compo;

	if(onoff){
		if((i = note_buf_search(-1, -1, -1)) < 0){
			MSG("note_buf full");
			return;
		}
		nt = &note_buf[i];
		// 従来の配列によるアクセスを、ポインタに変更
		
		nt->note = note;
		nt->ch = ch;
		nt->onoff = 1;
		nt->on_sec = evt_sec;
		nt->velo = velo;

		if((tone_compo = tone_compo_get(ch, note, &tone_n)) == NULL){
			note_buf_free(i);
			return;
		}
		if((nt->stat_lst = stat_lst_alloc_init(tone_n, evt_sec, nt, tone_compo, NULL)) == NULL){
			note_buf_free(i);
		}
		// stat_rec 構造体のバッファを、音色数分、チェーンリストで割り付けて初期化する
		
	}else{
		if((i = note_buf_search(ch, note, 1)) < 0) return;
		nt = &note_buf[i];
		for(stat=nt->stat_lst; stat; stat=stat->next){
			nt->stat = stat; /* back compati */
			nt->stat->off_v = env_out(nt, evt_sec);
		}
		// 鍵盤オフ時のエンベロープ出力の記録は、
		// 音色の数分だけ処理するように変更
		//
		// 互換性のため
		// stat_rec 構造体のチェーンリストから、カレントのポインタを
		// note_rec 構造体のメンバ stat に記録して処理する
		
		nt->onoff = 0;
		nt->off_sec = evt_sec;
	}
}

void
msb_set(int *vp, int v)
{
	*vp &= ~(127<<7);
	*vp |= v<<7;
}

void
lsb_set(int *vp, int v)
{
	*vp &= ~127;
	*vp |= v;
}

void
bend_note_update(int ch, double sec)
{
	int i, j;
	struct note_rec *nt;
	struct vco_stat_rec *vco_stat;
	struct stat_rec *stat;

	for(i=0; i<NOTE_BUF_N; i++){
		if(note_buf_is_free(i)) continue;
		nt = &note_buf[i];
		if(nt->ch != ch) continue;
		for(stat=nt->stat_lst; stat; stat=stat->next){
			for(j=0; j<2; j++){
				vco_stat = &stat->vco[j];
				vco_stat_update(vco_stat, vco_stat->freq, sec);
			}
		}
		// VCOの状態を更新する処理も、
		// 複数の音色分の stat_rec 構造体のチェーンリストを参照し、
		// 各音色分を全て更新するように変更
		
	}
}

int
main(int ac, char **av)
{
	int div4, delta_sum;
	int i, n, v, hi, low, note, velo;
	int ch, type;
	double sec;
	struct out_rec otr;
	int tempo, tempo_delta_sum;
	double tempo_sec;

	out_init(&otr, ac, av);
	note_buf_init();
	stat_buf_init();
	// stat_rec 構造体のバッファの配列の初期化を追加
	
	for(i=0; i<MIDI_CH_N; i++){
		ch_inf[i].vol = 0;
		ch_inf[i].pan = 1<<(14-1);
		ch_inf[i].bend = 0;
		ch_inf[i].rpn = 0;
		ch_inf[i].bend_range = 2;
		ch_inf[i].prog =-1;
	}
	tempo = 500000;
	tempo_delta_sum = 0;
	tempo_sec = 0;

	div4 = header();

	if(!rd_str_chk(4, "MTrk")) ERR("track id");
	v = rd_int(4); /* skip */

	hi = low = 0;
	delta_sum = 0;
	while((v = rd_delta()) != EOF){
		delta_sum += v;
		sec = tempo_sec + (double)(delta_sum - tempo_delta_sum) / div4 * tempo * 0.000001;
		
		if((v = rd()) & 0x80){
			hi = (v >> 4) & 0xf;
			low  = v & 0xf;
		}else bk(v);

		data_out(&otr, sec);

		ch = low;
		switch(hi){
		case 8:
		case 9:
			note = rd();
			velo = rd();
			note_onoff(hi == 9, sec, ch, note, velo);
			break;
		case 0xb: /* control change */
			type = rd();
			v = rd();
			switch(type){
			case 7: /* channel volume msb */
				msb_set(&ch_inf[ch].vol, v);
				break;
			case 39: /* channel volume lsb */
				lsb_set(&ch_inf[ch].vol, v);
				break;
			case 10: /* pan msb */
				msb_set(&ch_inf[ch].pan, v);
				break;
			case 42: /* pan lsb */
				lsb_set(&ch_inf[ch].pan, v);
				break;
			case 100: /* rpn lsb */
				lsb_set(&ch_inf[ch].rpn, v);
				break;
			case 101: /* rpn msb */
				msb_set(&ch_inf[ch].rpn, v);
				break;
			case 6: /* data entry msb */
				switch(ch_inf[ch].rpn){
				case 0: /* pitch bend range */
					ch_inf[ch].bend_range = v;
					break;
				}
				break;
			}
			break;
		case 0xa:
			rd();
			rd();
			break;
		case 0xe: /* pitch wheel change */
			bend_note_update(ch, sec);
			v = rd();
			v |= rd() << 7;
			ch_inf[ch].bend = v - 8192;
			break;
		case 0xc: /* program number */
			v = rd();
			ch_inf[ch].prog = v;
			break;
		case 0xd:
			rd();
			break;
		case 0xf:
			type = rd();
			switch(low){
			case 0:
				while(rd() != 0xf7);
				break;
			case 1:
			case 3:
				rd();
				break;
			case 2:
				rd();
				rd();
				break;
			case 0xf: /* meta */
				n = rd();
				switch(type){
				case 0x51: /* set tempo */
					v = rd_int(n);
					tempo = v;
					tempo_delta_sum = delta_sum;
					tempo_sec = sec;
					break;
				default:
					for(i=0; i<n; i++) rd();
					break;
				}
				break;
			default:
				break;
			}
			break;
		}
	}
	if(otr.fp != stdout) pclose(otr.fp);
	return 0;
}

/* EOF */


prog25.c 解説

prog24.c からの変更箇所のみ

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <math.h>

#define MSG(s) fprintf(stderr, "%s() %s L%d : %s\n", __func__, __FILE__, __LINE__, s)
#define ERR(s) do{ fprintf(stderr, "ERR "); MSG(s); exit(1); }while(0)

int bk_buf = -1;

int
rd(void)
{
	int v;

	if((v = bk_buf) < 0) return getchar();
	bk_buf = -1;
	return v;
}

void
bk(int v)
{
	if(bk_buf >= 0) ERR("give up");
	bk_buf = v;
}

void
rd_str(int n, char *s)
{
	int i;

	for(i=0; i<n; i++) s[i] = rd();
	s[i] = '\0';
}

int
rd_str_chk(int n, char *s)
{
	char buf[256];

	rd_str(n, buf);
	return strcmp(buf, s) == 0;
}

int
rd_int(int n) /* big endian */
{
	int i, v;

	v = 0;
	for(i=0; i<n; i++) v = (v << 8) | rd();
	return v;
}

int
rd_delta(void)
{
	int v, c;

	v = 0;
	do{
		if((c = rd()) == EOF) return EOF;
		v = (v << 7) | (c & 0x7f);
	}while(c & 0x80);
	return v;
}


int
opt_idx(char *key, int ac, char **av)
{
	int i;

	for(i=1; i<ac; i++) if(strcmp(av[i], key) == 0) return i;
	return -1;
}

char *
opt_str(char *key, int ac, char **av, char *def)
{
	int i;

	i = opt_idx(key, ac, av);
	if(i < 0 || i+1 >= ac) return def;
	return av[i+1];
}

int
opt_int(char *key, int ac, char **av, int def)
{
	char *s;

	if((s = opt_str(key, ac, av, NULL)) == NULL) return def;
	return strtol(s, NULL, 0);
}

struct out_rec{
	int smp_freq, smp_cnt;
	int bit_len;
	int sign;
	int ch_num;
	FILE *fp;

	int base;
	int amp;
	int iv_min;
	int iv_max;
	double smp_t, sec;
};

int
sox_version(void)
{
	FILE *fp;
	int v1, v2, v3;

	if((fp = popen("sox --version | sed -e 's/^.*v//'", "r")) == NULL) return -1;
	fscanf(fp, "%d.%d.%d", &v1, &v2, &v3);
	pclose(fp);
	return v1*10000 + v2*100 + v3;
}

char *
sox_bit_len_fmt(int bit_len)
{
	return sox_version() >= 140400 ? 
		(bit_len == 8 ? "-b 8" : "-b 16") : 
		(bit_len == 8 ? "-b" : "-w");
}

void
out_init(struct out_rec *ot, int ac, char **av)
{
	char cmd[1024], *fn;

	ot->smp_freq = opt_int("-r", ac, av, 44100);
	ot->smp_cnt = 0;
	ot->bit_len = opt_int("-b", ac, av, 16);
	if(ot->bit_len != 8 && ot->bit_len != 16) ERR("bit_len");
	ot->sign = (opt_idx("-u", ac, av) < 0);
	ot->ch_num = opt_int("-c", ac, av, 2);

	ot->fp = stdout;
	cmd[0] = '\0';
	fn = "";
	if(opt_idx("-play", ac, av) >= 0){
		strcat(cmd, "play");
	}else if(opt_idx("-sox", ac, av) >= 0){
		strcat(cmd, "sox");
		fn = opt_str("-sox", ac, av, "-d");
	}
	if(cmd[0]){
		sprintf(cmd + strlen(cmd), " -t raw -r %d %s %s -c %d - %s",
			ot->smp_freq, sox_bit_len_fmt(ot->bit_len),
			ot->sign ? "-s" : "-u",
			ot->ch_num, fn);
		if((ot->fp = popen(cmd, "w")) == NULL) ERR("popen");
	}
	ot->amp = ot->bit_len == 8 ? 127 : 32767;
	ot->base = ot->sign ? 0 : ot->amp + 1;
	ot->iv_min = ot->base - (ot->amp + 1);
	ot->iv_max = ot->base + ot->amp;

	ot->smp_t = 1.0 / ot->smp_freq;
}

void
out_do(struct out_rec *ot, double v)
{
	int iv;

	iv = ot->base + (int)(v * ot->amp);
	if(iv > ot->iv_max) iv = ot->iv_max;
	if(iv < ot->iv_min) iv = ot->iv_min;
	switch(ot->bit_len){
	case 8:
		fputc(iv, ot->fp);
		break;
	case 16:
		fputc(iv & 0xff, ot->fp);
		fputc((iv >> 8) & 0xff, ot->fp);
		break;
	}
}

#define OFF		0
#define ON		1

#define LPF		1
#define HPF		2
#define BPF		3

struct filter_rec{
	int type; /* OFF, LPF, HPF, BPF */
	double freq, Q;
};

struct filter_stat_rec{
	int idx;
	double in[4], out[4];
	double a0, a1, a2, b0, b1, b2, div_a0;
};

void
filter_update(struct filter_rec *fl, struct filter_stat_rec *stat, double smp_t)
{
	double w0, alpha, cos_w0;

	if(fl->type == OFF) return;

	w0 = 2 * M_PI * fl->freq * smp_t;
	cos_w0 = cos(w0);
	alpha = sin(w0) / (2 * fl->Q);

	switch(fl->type){
	case LPF:
		stat->b1 = 1 - cos_w0;
		stat->b0 = stat->b2 = stat->b1 * 0.5;
		break;
	case HPF:
		stat->b1 = -(1 + cos_w0);
		stat->b0 = stat->b2 = -stat->b1 * 0.5;
		break;
	case BPF:
		stat->b0 = fl->Q * alpha;
		stat->b1 = 0;
		stat->b2 = -stat->b0;
		break;
	}
	stat->a0 = 1 + alpha;
	stat->a1 = -2 * cos_w0;
	stat->a2 = 1 - alpha;
	if(stat->a0 != 0) stat->div_a0 = 1 / stat->a0;
}

void
filter_init(struct filter_rec *fl, struct filter_stat_rec *stat, double smp_t)
{
	int i;

	for(i=0; i<4; i++) stat->in[i] = stat->out[i] = 0;
	stat->idx = 0;

	filter_update(fl, stat, smp_t);
}

double
filter_out(struct filter_stat_rec *stat, double in)
{
	double *out_p;
	int i_1, i_2;

	stat->in[stat->idx] = in;
	out_p = &stat->out[stat->idx];

	if(stat->a0 != 0){
		i_1 = (stat->idx + 4 - 1) & 3;
		i_2 = (i_1 + 4 - 1) & 3;
		*out_p = (stat->b0 * in
			+ stat->b1 * stat->in[i_1]
			+ stat->b2 * stat->in[i_2]
			- stat->a1 * stat->out[i_1]
			- stat->a2 * stat->out[i_2] ) * stat->div_a0;
	}else{
		*out_p = 0;
	}
	stat->idx = (stat->idx + 1) & 3;
	return *out_p;
}


#define NOTE_BUF_N	256
#define STAT_BUF_N	256

struct vco_stat_rec{
	double cycle, freq, sec;
};

void
vco_stat_update(struct vco_stat_rec *stat, double freq, double sec)
{
	stat->cycle += freq * (sec - stat->sec);	
	stat->freq = freq;
	stat->sec = sec;
}

#define DELAY_BUF_N	(44100 * 5 / 10) /* max 0.5 sec */

struct note_rec;
struct tone_compo_rec;

struct stat_rec{
	struct vco_stat_rec vco[2];
	struct filter_stat_rec filter[2];
	double off_v;
	int fst_smp_cnt;
	double delay_buf[2][ DELAY_BUF_N ];

	struct note_rec *nt;
	struct tone_compo_rec *tone_compo;
	struct stat_rec *next;
} stat_buf[ STAT_BUF_N ];

void
stat_init(struct stat_rec *stat, double sec)
{
	int i;
	struct vco_stat_rec *vco;

	for(i=0; i<2; i++){
		vco = &stat->vco[i];
		vco->cycle = 0;
		vco->sec = sec;
	}
	for(i=0; i<2; i++){
		stat->filter[i].idx = -1;
	}
	stat->fst_smp_cnt = -1;
}

void
stat_buf_init(void)
{
	int i;

	for(i=0; i<STAT_BUF_N; i++) stat_buf[i].nt = NULL;
}

struct note_rec{
	int ch;
	int note;
	int onoff;
	double on_sec;
	double off_sec;
	int velo;

	struct out_rec *ot;
	struct stat_rec *stat_lst;
} note_buf[NOTE_BUF_N];

int
note_buf_is_free(int i)
{
	return note_buf[i].ch < 0;
}

void
note_buf_free(int i)
{
	note_buf[i].ch = -1;
}

void
note_buf_init(void)
{
	int i;

	for(i=0; i<NOTE_BUF_N; i++) note_buf_free(i);
}

int
note_buf_search(int ch, int note, int onoff)
{
	int i;

	for(i=0; i<NOTE_BUF_N; i++) {
		if( (ch < 0 && note_buf[i].ch < 0) ||
		    (note_buf[i].ch == ch &&
		     note_buf[i].note == note &&
		     note_buf[i].onoff == onoff) ) return i;
	}
	return -1;
}

int
header(void)
{
	int v;

	if(!rd_str_chk(4, "MThd")) ERR("header id");
	if(rd_int(4) != 6) ERR("header size");
	if(rd_int(2) != 0) ERR("header format type");
	if(rd_int(2) != 1) ERR("header track num");
	if((v = rd_int(2)) & 0x8000) ERR("header division");
	return v; /* div4 */
}

double
note_to_freq(int note)
{
	return 440 * pow(2, (note - 69) / 12.0);
}

#define WAVE_SIN	0
#define WAVE_SAW	1
#define WAVE_SQUARE	2
#define WAVE_NOISE	3

double
wave_out(int wave, double cycle)
{
	cycle -= (int)cycle;

	switch(wave){
	case WAVE_SIN:
		return sin(2 * M_PI * cycle);
	case WAVE_SAW:
		cycle *= 2;
		if(cycle > 1) cycle -= 2;
		return cycle;
	case WAVE_SQUARE:
		return cycle < 0.5 ? 1 : -1;
	case WAVE_NOISE:
		return ((double)rand() / RAND_MAX) * 2 - 1;
	}
	return 0;
}

struct vco_rec{
	int wave1, wave2;
	int tune; /* for vco2 */
	double mix;
	int ring;
};

struct modu_rec{
	int pitch1, pitch2, filter1, filter2;
};

struct lfo_rec{
	int wave;
	double freq, delay;
};

struct env_rec{
	double attack;	/* sec */
	double decay;	/* sec */
	double sustain;	/* 0..1 */
	double release;	/* sec */
};

struct delay_rec{
	int onoff;
	double sec, gain;
};

struct tone_rec{
	struct vco_rec vco;
	struct filter_rec fl1, fl2;
	struct env_rec env;
	double level;
	struct modu_rec lfo_modu;
	struct lfo_rec lfo;
	struct modu_rec env_modu;
	struct delay_rec delay;
	int chorus;
} tone_inf[] = {
	{	/* strings */
		{ WAVE_SAW, WAVE_SAW, 12, 0.5, OFF },
		{ LPF, 3000, 1.5 }, { OFF, },
		{ 0.15, 0.5, 0.8, 0.5 },
		1.0,
		{ OFF, 12, OFF, OFF }, { WAVE_SIN, 4, 0.3 },
		{ OFF, OFF, OFF, OFF },
		{ OFF, }, ON,
	},{	/* bass */
		{ WAVE_SAW, WAVE_SQUARE, OFF, 0.5, OFF },
		{ LPF, 1000, 1.5 }, { OFF, },
		{ 0.05, 0.2, 0.4, 0.2 },
		1.0,
		{ OFF, 60, OFF, OFF }, { WAVE_SIN, 1.5, 0.2 },
		{ OFF, OFF, OFF, OFF },
		{ OFF, }, ON,
	},{	/* lead */
		{ WAVE_SQUARE, WAVE_SQUARE, 10, 0.5, OFF },
		{ LPF, 2000, 4 }, { OFF, },
		{ 0.01, 0.2, 0.8, 0.3 },
		1.0,
		{ OFF, 1, 5, OFF }, { WAVE_SIN, 4, 0.3 },
		{ OFF, OFF, OFF, OFF },
		{ ON, 0.2, 0.4}, OFF,
	},{	/* SIN */
		{ WAVE_SIN, WAVE_SIN, OFF, 0, OFF },
		{ LPF, 20000, 0.8 }, { OFF, },
		{ 0, 0.3, 0.2, 0.3 },
		1.4,
		{ 25, OFF, OFF, OFF }, { WAVE_SIN, 6, 0.3 },
		{ OFF, OFF, OFF, OFF },
		{ OFF, }, OFF,
	}
}, drum_tone_inf[] = {
	{	/* bass */
		{ WAVE_SIN, WAVE_NOISE, OFF, 0.4, OFF },
		{ LPF, 400, 1 }, { OFF, },
		{ 0.01, 0.18, 0, 0.18 },
		9.0,
		{ 100, OFF, 30, OFF }, { WAVE_NOISE, 0, 0.5 },
		{ OFF, OFF, OFF, OFF },
		{ OFF, }, OFF,
	},{	/* snare */
		{ WAVE_SQUARE, WAVE_NOISE, OFF, 0.8, ON },
		{ LPF, 1500, 1.7 }, { OFF, }, 
		{ 0, 0.4, 0.3, 0.4 },
		5,
		{ OFF, OFF, OFF, OFF }, {},
		{ OFF, OFF, OFF, OFF },
		{ OFF, }, OFF,
	},{	/* tom */
		{ WAVE_SQUARE, WAVE_NOISE, OFF, 0.5, ON },
		{ LPF, 800, 2.5 }, { OFF, },
		{ 0, 0.03, 0.1, 0.4 },
		5,
		{ OFF, OFF, OFF, OFF }, {},
		{ 200, OFF, 1200, OFF },
		{ OFF, }, OFF,
	},{	/* hi-hat close */
		{ WAVE_SQUARE, WAVE_SQUARE, 700, 0.9, ON },
		{ LPF, 16000, 2 }, { OFF, },
		{ 0, 0.15, 0, 0.15 },
		0.6,
		{ OFF, OFF, OFF, OFF }, {},
		{ OFF, OFF, OFF, OFF },
		{ OFF, }, OFF,
	},{	/* hi-hat open */
		{ WAVE_SQUARE, WAVE_SQUARE, 700, 0.9, ON },
		{ LPF, 16000, 2 }, { OFF, },
		{ 0, 0, 1, 0.35 },
		0.6,
		{ OFF, OFF, OFF, OFF }, {},
		{ OFF, OFF, OFF, OFF },
		{ OFF, }, OFF,
	},{	/* cymbal */
		{ WAVE_NOISE, WAVE_SQUARE, OFF, 0.8, ON },
		{ LPF, 4000, 2 }, { OFF, },
		{ 0, 0.01, 0.2, 0.8 },
		9,
		{ OFF, OFF, OFF, OFF }, {},
		{ OFF, OFF, 600, OFF }, 
		{ OFF, }, OFF,
	},{	/* side stick */
		{ WAVE_NOISE, WAVE_SQUARE, OFF, 0.2, OFF },
		{ LPF, 1700, 3 }, { OFF, },
		{ 0, 0.012, 0.1, 0.7 },
		10,
		{ OFF, OFF, OFF, OFF }, {},
		{ OFF, OFF, OFF, OFF },
		{ OFF, }, OFF,
	}
};

struct tone_compo_rec{
	struct tone_rec *tone;
	int note; /* -1 : event note */
	double rate;
};

#define PROG_DRUM	0

struct{
	int prog, note; /* note for ch 9 */
	struct tone_compo_rec *tone_compo;
} tones_lst[] = {
	{
		PROG_DRUM, 36, /* bass drum1 */
		(struct tone_compo_rec []){
			{ &drum_tone_inf[0], 28, 1.0 }, { NULL, }
		}
	},{
		PROG_DRUM, 37, /* side stick */
		(struct tone_compo_rec []){
			{ &drum_tone_inf[6], 110, 1.0 }, { NULL, }
		}
	},{
		PROG_DRUM, 40, /* electric snare */
		(struct tone_compo_rec []){
			{ &drum_tone_inf[1], 69, 1.0 }, { NULL, }
		}
	},{
		PROG_DRUM, 41, /* low floor tom */
		(struct tone_compo_rec []){
			{ &drum_tone_inf[2], 50, 1.0 }, { NULL, }
		}
	},{
		PROG_DRUM, 42, /* closed hi-hat */
		(struct tone_compo_rec []){
			{ &drum_tone_inf[3], 115 + 8, 1.0 }, { NULL, }
		}
	},{
		PROG_DRUM, 46, /* open hi-hat */
		(struct tone_compo_rec []){
			{ &drum_tone_inf[4], 115 + 8, 1.0 }, { NULL, }
		}
	},{
		PROG_DRUM, 49, /* crash cymbal 1 */
		(struct tone_compo_rec []){
			{ &drum_tone_inf[5], 75, 1.0 }, { NULL, }
		}
	},{
		PROG_DRUM, 57, /* crash cymbal 2 */
		(struct tone_compo_rec []){
			{ &drum_tone_inf[5], 85, 1.0 }, { NULL, }
		}
	},{
		48, -1, /* timpani */
		(struct tone_compo_rec []){
			{ &tone_inf[0], -1, 1.0 }, { NULL, }
		}
	},{
		50, -1, /* strings ensamble 2 */
		(struct tone_compo_rec []){
			{ &tone_inf[0], -1, 1.0 }, { NULL, }
		}
	},{
		35, -1, /* electric bass (pick) */
		(struct tone_compo_rec []){
			{ &tone_inf[1], -1, 1.0 }, { NULL, }
		}
	},{
		79, -1, /* whistle */
		(struct tone_compo_rec []){
			{ &tone_inf[2], -1, 1.0 }, { NULL, }
		}
	},{
		81, -1, /* lead 1 (square) */
		(struct tone_compo_rec []){
			{ &tone_inf[2], -1, 1.0 }, { NULL, }
		}
	},{
		87, -1, /* lead 7 (fifths) */
		(struct tone_compo_rec []){
			{ &tone_inf[2], -1, 1.0 }, { NULL, }
		}
	},{
		24, -1, /* tango accordion */
		(struct tone_compo_rec []){
			{ &tone_inf[3], -1, 1.0 }, { NULL, }
		}
	},{
		67, -1, /* tenor sax */
		(struct tone_compo_rec []){
			{ &tone_inf[3], -1, 1.0 }, { NULL, }
		}
	},{
		-1, /* tail */
	}
};

void
stat_lst_free(struct stat_rec *stat)
{
	if(!stat) return;
	stat->nt = NULL;
	stat_lst_free(stat->next);
}

struct stat_rec *
stat_lst_alloc_init(int n, double sec, struct note_rec *nt, struct tone_compo_rec *tone_compo_arr, struct stat_rec *next)
{
	struct stat_rec *stat;
	int i;

	if(n > 1){
		next = stat_lst_alloc_init(n - 1, sec, nt, tone_compo_arr + 1, next);
		if(next == NULL) return NULL;
	}
	for(i=0; i<STAT_BUF_N; i++) if(stat_buf[i].nt == NULL) break;
	if(i >= STAT_BUF_N){
		stat_lst_free(next);
		return NULL;
	}
	stat = &stat_buf[i];
	stat->nt = nt;
	stat->tone_compo = tone_compo_arr;
	stat->next = next;
	stat_init(stat, sec);
	return stat;
}

#define MIDI_CH_N	16
struct ch_rec{
	int vol;
	int pan;
	int bend;
	int rpn;
	int bend_range;
	int prog;
} ch_inf[ MIDI_CH_N ];

#define CH_PROG(ch)	( (ch) == 9 ? 0 : ch_inf[ch].prog )

struct tone_compo_rec *
tone_compo_get(int ch, int note, int *ret_n)
{
	struct tone_compo_rec *tone_compo;
	int prog, i;

	prog = CH_PROG(ch);
	for(i=0; tones_lst[i].prog >= 0; i++){
		if(tones_lst[i].prog == prog &&
		   (tones_lst[i].note == note || tones_lst[i].note < 0)) break;
	}
	if(tones_lst[i].prog < 0) return NULL; /* not found */
	tone_compo = tones_lst[i].tone_compo;
	if(ret_n){
		for(i=0; tone_compo[i].tone; i++);
		*ret_n = i;
	}
	return tone_compo;
}

double
env_out(struct stat_rec *stat, double sec)
{
	struct note_rec *nt;
	struct env_rec *e;
	double v;

	nt = stat->nt;
	e = &stat->tone_compo->tone->env;
	if(nt->onoff){
		sec -= nt->on_sec;
		if(sec < e->attack){
			v = sec / e->attack;
			return log10(1 + v * 9);
		}
		sec -= e->attack;
		if(sec < e->decay){
			v = sec / e->decay;
			v = log10(1 + v * 9);
			return 1 - v * (1 - e->sustain);
		}
		return e->sustain;
	}
	sec -= nt->off_sec;
	if(sec < e->release){
		v = sec / e->release;
		v = log10(1 + v * 9);
		return (1 - v) * stat->off_v;
	}
	return 0;
}

void
modu_out(double v, struct modu_rec *modu, double *ret_arr)
{
	if(modu->pitch1) ret_arr[0] += v * modu->pitch1 * (1.0 / 1200);
	if(modu->pitch2) ret_arr[1] += v * modu->pitch2 * (1.0 / 1200);
	if(modu->filter1) ret_arr[2] += v * modu->filter1 * (1.0 / 1200);
	if(modu->filter2) ret_arr[3] += v * modu->filter2 * (1.0 / 1200);
}

double
lfo_out(struct lfo_rec *lfo, struct modu_rec *modu, double sec, double on_sec)
{
	double dsec;

	if(!(modu->pitch1 || modu->pitch2 || modu->filter1 || modu->filter2)) return 0;
	if((dsec = sec - on_sec - lfo->delay) <= 0) return 0;
	return wave_out(lfo->wave, lfo->freq * dsec);
}

double
vco_out(int wave, struct vco_stat_rec *stat, double freq, double sec, double modu_v)
{
	if(modu_v != 0) freq *= pow(2, modu_v);
	vco_stat_update(stat, freq, sec);
	return wave_out(wave, stat->cycle);
}

double
vcf_out(struct filter_rec *fl, struct filter_stat_rec *stat, double smp_t, double modu_v, double v)
{
	struct filter_rec tmp;

	if(stat->idx < 0) filter_init(fl, stat, smp_t);
	if(modu_v != 0){
		tmp = *fl;
		tmp.freq *= pow(2, modu_v);
		filter_update(&tmp, stat, smp_t);
	}
	return filter_out(stat, v);
}

void
delay_buf_set(struct stat_rec *stat, double v, double env_v)
{
	int i;

	i = (stat->nt->ot->smp_cnt - stat->fst_smp_cnt) % DELAY_BUF_N;
	stat->delay_buf[0][i] = v;
	stat->delay_buf[1][i] = env_v;
}

#define MIX(a, b, rate)		( (a) * (1 - (rate)) + (b) * (rate) )

double
tbl_lookup(double *tbl, int n, double d_idx)
{
	int i;

	i = (int)d_idx;
	d_idx -= i;
	i %= n;
	return MIX(tbl[i], tbl[(i+1)%n], d_idx);
}

double
delay_buf_lookup(struct stat_rec *stat, double sec, double *ret_env_v)
{
	double cycle;

	cycle = stat->nt->ot->smp_freq * sec - stat->fst_smp_cnt;
	if(ret_env_v) *ret_env_v = tbl_lookup(stat->delay_buf[1], DELAY_BUF_N, cycle);
	return tbl_lookup(stat->delay_buf[0], DELAY_BUF_N, cycle);
}

double
delay_out(struct stat_rec *stat, struct delay_rec *delay, double *ret_env_v)
{
	double v, sec;

	sec = stat->nt->ot->sec;
	if(sec - stat->nt->on_sec < delay->sec) return 0;
	v = delay_buf_lookup(stat, sec - delay->sec, ret_env_v) * delay->gain;
	if(ret_env_v) *ret_env_v *= delay->gain;
	return v;
}

double
chorus_out(struct stat_rec *stat)
{
	double sec,dsec, bak_sec;

	sec = stat->nt->ot->sec;
	dsec = sec - stat->nt->on_sec;
	bak_sec = 0.01 + 0.001 * sin(2 * M_PI * 0.8 * dsec);
	if(dsec < bak_sec) return 0;
	return delay_buf_lookup(stat, sec - bak_sec, NULL);
}

double
tone_out(struct stat_rec *stat, double freq, double env_v)
{
	struct tone_rec *tn;
	int i;
	double v, v1, v2, lfo_v, modu_v[4];
	struct vco_rec *vco;
	struct out_rec *ot;

	tn = stat->tone_compo->tone;
	ot = stat->nt->ot;

	lfo_v = lfo_out(&tn->lfo, &tn->lfo_modu, ot->sec, stat->nt->on_sec);

	for(i=0; i<4; i++) modu_v[i] = 0;
	modu_out(lfo_v, &tn->lfo_modu, modu_v);
	modu_out(env_v, &tn->env_modu, modu_v);

	vco = &tn->vco;
	v1 = vco_out(vco->wave1, &stat->vco[0], freq, ot->sec, modu_v[0]);

	modu_v[1] += vco->tune * (1.0 / 1200);
	v2 = vco_out(vco->wave2, &stat->vco[1], freq, ot->sec, modu_v[1]);
	if(vco->ring){
		v = v1 * v2;
		v1 = (v1 + v2) * 0.5;
		v2 = v;
	}
	v = MIX(v1, v2, vco->mix);

	if(tn->fl1.type != OFF) v = vcf_out(&tn->fl1, &stat->filter[0], ot->smp_t, modu_v[2], v);
	if(tn->fl2.type != OFF) v = vcf_out(&tn->fl2, &stat->filter[1], ot->smp_t, modu_v[3], v);

	v *= env_v * tn->level;
	return v;
}

int
note_out(struct note_rec *nt, double *vl, double *vr)
{
	double v, sum_v, freq, pan, env_v, d_env_v;
	int nch, cnt;
	struct tone_rec *tn;
	struct tone_compo_rec *tone_compo;
	struct stat_rec *stat;
	struct out_rec *ot;

	nch = nt->ch;
	ot = nt->ot;
	cnt = 0;
	sum_v = 0;
	for(stat=nt->stat_lst; stat; stat=stat->next){
		tone_compo = stat->tone_compo;
		if(tone_compo == NULL) continue;
		cnt++;
		tn = tone_compo->tone;
		freq = note_to_freq(tone_compo->note >= 0 ? tone_compo->note : nt->note);

		if(stat->fst_smp_cnt < 0) stat->fst_smp_cnt = ot->smp_cnt;
		if(ch_inf[nch].bend != 0) freq *= pow(2, ch_inf[nch].bend * ch_inf[nch].bend_range * (1.0 / (8192 * 12)));

		env_v = env_out(stat, ot->sec);
		v = (env_v > 0) ? tone_out(stat, freq, env_v) : 0;

		d_env_v = 0;
		if(tn->delay.onoff) v += delay_out(stat, &tn->delay, &d_env_v);
		d_env_v += env_v;
		delay_buf_set(stat, v, d_env_v);
		if(tn->chorus) v += chorus_out(stat);

		sum_v += v * tone_compo->rate;

		if(nt->onoff == 0 && ot->sec - nt->off_sec >= tn->env.release && (!tn->delay.onoff || d_env_v < 0.01)){
			stat->tone_compo = NULL;
		}
	}
	v = sum_v;

	v *= (nt->velo * (1.0 / 127)) * (ch_inf[nch].vol * (1.0 / ((1<<14)-1)));
	if(ot->ch_num == 1){
		*vl += v;
	}else{
		pan = ch_inf[nch].pan * (1.0 / (1<<14));
		*vl += (1 - pan) * v;
		*vr += pan * v;
	}
	return cnt == 0;
}

void
data_out(struct out_rec *ot, double evt_sec)
{
	double vl, vr;
	int i;
	struct note_rec *nt;

	while((ot->sec = ot->smp_t * ot->smp_cnt) < evt_sec){
		vl = vr = 0;
		for(i=0; i<NOTE_BUF_N; i++){
			if(note_buf_is_free(i)) continue;
			nt = &note_buf[i];
			nt->ot = ot;
			if(note_out(nt, &vl, &vr)){
				stat_lst_free(nt->stat_lst);
				note_buf_free(i);
			}
		}
		out_do(ot, vl * (1.0 / 16));
		if(ot->ch_num > 1) out_do(ot, vr * (1.0 / 16));
		ot->smp_cnt++;
	}
}

void
note_onoff(int onoff, double evt_sec, int ch, int note, int velo)
{
	int i, tone_n;
	struct note_rec *nt;
	struct stat_rec *stat;
	struct tone_compo_rec *tone_compo;

	if(onoff){
		if((i = note_buf_search(-1, -1, -1)) < 0){
			MSG("note_buf full");
			return;
		}
		nt = &note_buf[i];
		nt->note = note;
		nt->ch = ch;
		nt->onoff = 1;
		nt->on_sec = evt_sec;
		nt->velo = velo;

		if((tone_compo = tone_compo_get(ch, note, &tone_n)) == NULL){
			note_buf_free(i);
			return;
		}
		if((nt->stat_lst = stat_lst_alloc_init(tone_n, evt_sec, nt, tone_compo, NULL)) == NULL){
			note_buf_free(i);
		}
	}else{
		if((i = note_buf_search(ch, note, 1)) < 0) return;
		nt = &note_buf[i];
		for(stat=nt->stat_lst; stat; stat=stat->next){
			stat->off_v = env_out(stat, evt_sec);
		}
		nt->onoff = 0;
		nt->off_sec = evt_sec;
	}
}

void
msb_set(int *vp, int v)
{
	*vp &= ~(127<<7);
	*vp |= v<<7;
}

void
lsb_set(int *vp, int v)
{
	*vp &= ~127;
	*vp |= v;
}

void
bend_note_update(int ch, double sec)
{
	int i, j;
	struct note_rec *nt;
	struct vco_stat_rec *vco_stat;
	struct stat_rec *stat;

	for(i=0; i<NOTE_BUF_N; i++){
		if(note_buf_is_free(i)) continue;
		nt = &note_buf[i];
		if(nt->ch != ch) continue;
		for(stat=nt->stat_lst; stat; stat=stat->next){
			for(j=0; j<2; j++){
				vco_stat = &stat->vco[j];
				vco_stat_update(vco_stat, vco_stat->freq, sec);
			}
		}
	}
}

int
main(int ac, char **av)
{
	int div4, delta_sum;
	int i, n, v, hi, low, note, velo;
	int ch, type;
	double sec;
	struct out_rec otr;
	int tempo, tempo_delta_sum;
	double tempo_sec;

	out_init(&otr, ac, av);
	note_buf_init();
	stat_buf_init();
	for(i=0; i<MIDI_CH_N; i++){
		ch_inf[i].vol = 0;
		ch_inf[i].pan = 1<<(14-1);
		ch_inf[i].bend = 0;
		ch_inf[i].rpn = 0;
		ch_inf[i].bend_range = 2;
		ch_inf[i].prog =-1;
	}
	tempo = 500000;
	tempo_delta_sum = 0;
	tempo_sec = 0;

	div4 = header();

	if(!rd_str_chk(4, "MTrk")) ERR("track id");
	v = rd_int(4); /* skip */

	hi = low = 0;
	delta_sum = 0;
	while((v = rd_delta()) != EOF){
		delta_sum += v;
		sec = tempo_sec + (double)(delta_sum - tempo_delta_sum) / div4 * tempo * 0.000001;
		
		if((v = rd()) & 0x80){
			hi = (v >> 4) & 0xf;
			low  = v & 0xf;
		}else bk(v);

		data_out(&otr, sec);

		ch = low;
		switch(hi){
		case 8:
		case 9:
			note = rd();
			velo = rd();
			note_onoff(hi == 9, sec, ch, note, velo);
			break;
		case 0xb: /* control change */
			type = rd();
			v = rd();
			switch(type){
			case 7: /* channel volume msb */
				msb_set(&ch_inf[ch].vol, v);
				break;
			case 39: /* channel volume lsb */
				lsb_set(&ch_inf[ch].vol, v);
				break;
			case 10: /* pan msb */
				msb_set(&ch_inf[ch].pan, v);
				break;
			case 42: /* pan lsb */
				lsb_set(&ch_inf[ch].pan, v);
				break;
			case 100: /* rpn lsb */
				lsb_set(&ch_inf[ch].rpn, v);
				break;
			case 101: /* rpn msb */
				msb_set(&ch_inf[ch].rpn, v);
				break;
			case 6: /* data entry msb */
				switch(ch_inf[ch].rpn){
				case 0: /* pitch bend range */
					ch_inf[ch].bend_range = v;
					break;
				}
				break;
			}
			break;
		case 0xa:
			rd();
			rd();
			break;
		case 0xe: /* pitch wheel change */
			bend_note_update(ch, sec);
			v = rd();
			v |= rd() << 7;
			ch_inf[ch].bend = v - 8192;
			break;
		case 0xc: /* program number */
			v = rd();
			ch_inf[ch].prog = v;
			break;
		case 0xd:
			rd();
			break;
		case 0xf:
			type = rd();
			switch(low){
			case 0:
				while(rd() != 0xf7);
				break;
			case 1:
			case 3:
				rd();
				break;
			case 2:
				rd();
				rd();
				break;
			case 0xf: /* meta */
				n = rd();
				switch(type){
				case 0x51: /* set tempo */
					v = rd_int(n);
					tempo = v;
					tempo_delta_sum = delta_sum;
					tempo_sec = sec;
					break;
				default:
					for(i=0; i<n; i++) rd();
					break;
				}
				break;
			default:
				break;
			}
			break;
		}
	}
	if(otr.fp != stdout) pclose(otr.fp);
	return 0;
}

/* EOF */


#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <math.h>

#define MSG(s) fprintf(stderr, "%s() %s L%d : %s\n", __func__, __FILE__, __LINE__, s)
#define ERR(s) do{ fprintf(stderr, "ERR "); MSG(s); exit(1); }while(0)

int bk_buf = -1;

int
rd(void)
{
	int v;

	if((v = bk_buf) < 0) return getchar();
	bk_buf = -1;
	return v;
}

void
bk(int v)
{
	if(bk_buf >= 0) ERR("give up");
	bk_buf = v;
}

void
rd_str(int n, char *s)
{
	int i;

	for(i=0; i<n; i++) s[i] = rd();
	s[i] = '\0';
}

int
rd_str_chk(int n, char *s)
{
	char buf[256];

	rd_str(n, buf);
	return strcmp(buf, s) == 0;
}

int
rd_int(int n) /* big endian */
{
	int i, v;

	v = 0;
	for(i=0; i<n; i++) v = (v << 8) | rd();
	return v;
}

int
rd_delta(void)
{
	int v, c;

	v = 0;
	do{
		if((c = rd()) == EOF) return EOF;
		v = (v << 7) | (c & 0x7f);
	}while(c & 0x80);
	return v;
}


int
opt_idx(char *key, int ac, char **av)
{
	int i;

	for(i=1; i<ac; i++) if(strcmp(av[i], key) == 0) return i;
	return -1;
}

char *
opt_str(char *key, int ac, char **av, char *def)
{
	int i;

	i = opt_idx(key, ac, av);
	if(i < 0 || i+1 >= ac) return def;
	return av[i+1];
}

int
opt_int(char *key, int ac, char **av, int def)
{
	char *s;

	if((s = opt_str(key, ac, av, NULL)) == NULL) return def;
	return strtol(s, NULL, 0);
}

struct out_rec{
	int smp_freq, smp_cnt;
	int bit_len;
	int sign;
	int ch_num;
	FILE *fp;

	int base;
	int amp;
	int iv_min;
	int iv_max;
	double smp_t, sec;
};

int
sox_version(void)
{
	FILE *fp;
	int v1, v2, v3;

	if((fp = popen("sox --version | sed -e 's/^.*v//'", "r")) == NULL) return -1;
	fscanf(fp, "%d.%d.%d", &v1, &v2, &v3);
	pclose(fp);
	return v1*10000 + v2*100 + v3;
}

char *
sox_bit_len_fmt(int bit_len)
{
	return sox_version() >= 140400 ? 
		(bit_len == 8 ? "-b 8" : "-b 16") : 
		(bit_len == 8 ? "-b" : "-w");
}

void
out_init(struct out_rec *ot, int ac, char **av)
{
	char cmd[1024], *fn;

	ot->smp_freq = opt_int("-r", ac, av, 44100);
	ot->smp_cnt = 0;
	ot->bit_len = opt_int("-b", ac, av, 16);
	if(ot->bit_len != 8 && ot->bit_len != 16) ERR("bit_len");
	ot->sign = (opt_idx("-u", ac, av) < 0);
	ot->ch_num = opt_int("-c", ac, av, 2);

	ot->fp = stdout;
	cmd[0] = '\0';
	fn = "";
	if(opt_idx("-play", ac, av) >= 0){
		strcat(cmd, "play");
	}else if(opt_idx("-sox", ac, av) >= 0){
		strcat(cmd, "sox");
		fn = opt_str("-sox", ac, av, "-d");
	}
	if(cmd[0]){
		sprintf(cmd + strlen(cmd), " -t raw -r %d %s %s -c %d - %s",
			ot->smp_freq, sox_bit_len_fmt(ot->bit_len),
			ot->sign ? "-s" : "-u",
			ot->ch_num, fn);
		if((ot->fp = popen(cmd, "w")) == NULL) ERR("popen");
	}
	ot->amp = ot->bit_len == 8 ? 127 : 32767;
	ot->base = ot->sign ? 0 : ot->amp + 1;
	ot->iv_min = ot->base - (ot->amp + 1);
	ot->iv_max = ot->base + ot->amp;

	ot->smp_t = 1.0 / ot->smp_freq;
}

void
out_do(struct out_rec *ot, double v)
{
	int iv;

	iv = ot->base + (int)(v * ot->amp);
	if(iv > ot->iv_max) iv = ot->iv_max;
	if(iv < ot->iv_min) iv = ot->iv_min;
	switch(ot->bit_len){
	case 8:
		fputc(iv, ot->fp);
		break;
	case 16:
		fputc(iv & 0xff, ot->fp);
		fputc((iv >> 8) & 0xff, ot->fp);
		break;
	}
}

#define OFF		0
#define ON		1

#define LPF		1
#define HPF		2
#define BPF		3

struct filter_rec{
	int type; /* OFF, LPF, HPF, BPF */
	double freq, Q;
};

struct filter_stat_rec{
	int idx;
	double in[4], out[4];
	double a0, a1, a2, b0, b1, b2, div_a0;
};

void
filter_update(struct filter_rec *fl, struct filter_stat_rec *stat, double smp_t)
{
	// 引数の out_rec 構造体を、使ってる smp_t だけに変更
	
	double w0, alpha, cos_w0;

	if(fl->type == OFF) return;

	w0 = 2 * M_PI * fl->freq * smp_t;
	// 引数の out_rec 構造体を、使ってる smp_t だけに変更
	
	cos_w0 = cos(w0);
	alpha = sin(w0) / (2 * fl->Q);

	switch(fl->type){
	case LPF:
		stat->b1 = 1 - cos_w0;
		stat->b0 = stat->b2 = stat->b1 * 0.5;
		break;
	case HPF:
		stat->b1 = -(1 + cos_w0);
		stat->b0 = stat->b2 = -stat->b1 * 0.5;
		break;
	case BPF:
		stat->b0 = fl->Q * alpha;
		stat->b1 = 0;
		stat->b2 = -stat->b0;
		break;
	}
	stat->a0 = 1 + alpha;
	stat->a1 = -2 * cos_w0;
	stat->a2 = 1 - alpha;
	if(stat->a0 != 0) stat->div_a0 = 1 / stat->a0;
}

void
filter_init(struct filter_rec *fl, struct filter_stat_rec *stat, double smp_t)
{
	// 引数の out_rec 構造体を、使ってる smp_t だけに変更
	
	int i;

	for(i=0; i<4; i++) stat->in[i] = stat->out[i] = 0;
	stat->idx = 0;

	filter_update(fl, stat, smp_t);
	// 引数の out_rec 構造体を、使ってる smp_t だけに変更
	
}

double
filter_out(struct filter_stat_rec *stat, double in)
{
	double *out_p;
	int i_1, i_2;

	stat->in[stat->idx] = in;
	out_p = &stat->out[stat->idx];

	if(stat->a0 != 0){
		i_1 = (stat->idx + 4 - 1) & 3;
		i_2 = (i_1 + 4 - 1) & 3;
		*out_p = (stat->b0 * in
			+ stat->b1 * stat->in[i_1]
			+ stat->b2 * stat->in[i_2]
			- stat->a1 * stat->out[i_1]
			- stat->a2 * stat->out[i_2] ) * stat->div_a0;
	}else{
		*out_p = 0;
	}
	stat->idx = (stat->idx + 1) & 3;
	return *out_p;
}


#define NOTE_BUF_N	256
#define STAT_BUF_N	256

struct vco_stat_rec{
	double cycle, freq, sec;
};

void
vco_stat_update(struct vco_stat_rec *stat, double freq, double sec)
{
	stat->cycle += freq * (sec - stat->sec);	
	stat->freq = freq;
	stat->sec = sec;
}

#define DELAY_BUF_N	(44100 * 5 / 10) /* max 0.5 sec */

struct note_rec;
struct tone_compo_rec;

struct stat_rec{
	struct vco_stat_rec vco[2];
	struct filter_stat_rec filter[2];
	double off_v;
	int fst_smp_cnt;
	double delay_buf[2][ DELAY_BUF_N ];

	struct note_rec *nt;
	struct tone_compo_rec *tone_compo;
	struct stat_rec *next;
} stat_buf[ STAT_BUF_N ];

void
stat_init(struct stat_rec *stat, double sec)
{
	int i;
	struct vco_stat_rec *vco;

	for(i=0; i<2; i++){
		vco = &stat->vco[i];
		vco->cycle = 0;
		vco->sec = sec;
	}
	for(i=0; i<2; i++){
		stat->filter[i].idx = -1;
	}
	stat->fst_smp_cnt = -1;
}

void
stat_buf_init(void)
{
	int i;

	for(i=0; i<STAT_BUF_N; i++) stat_buf[i].nt = NULL;
}

struct note_rec{
	int ch;
	int note;
	int onoff;
	double on_sec;
	double off_sec;
	int velo;

	struct out_rec *ot;
	// 現在処理中の stat_rec 構造体のポインタを廃止して
	// out_rec 構造体のポインタを追加
	
	struct stat_rec *stat_lst;
} note_buf[NOTE_BUF_N];

int
note_buf_is_free(int i)
{
	return note_buf[i].ch < 0;
}

void
note_buf_free(int i)
{
	note_buf[i].ch = -1;
}

void
note_buf_init(void)
{
	int i;

	for(i=0; i<NOTE_BUF_N; i++) note_buf_free(i);
}

int
note_buf_search(int ch, int note, int onoff)
{
	int i;

	for(i=0; i<NOTE_BUF_N; i++) {
		if( (ch < 0 && note_buf[i].ch < 0) ||
		    (note_buf[i].ch == ch &&
		     note_buf[i].note == note &&
		     note_buf[i].onoff == onoff) ) return i;
	}
	return -1;
}

int
header(void)
{
	int v;

	if(!rd_str_chk(4, "MThd")) ERR("header id");
	if(rd_int(4) != 6) ERR("header size");
	if(rd_int(2) != 0) ERR("header format type");
	if(rd_int(2) != 1) ERR("header track num");
	if((v = rd_int(2)) & 0x8000) ERR("header division");
	return v; /* div4 */
}

double
note_to_freq(int note)
{
	return 440 * pow(2, (note - 69) / 12.0);
}

#define WAVE_SIN	0
#define WAVE_SAW	1
#define WAVE_SQUARE	2
#define WAVE_NOISE	3

double
wave_out(int wave, double cycle)
{
	cycle -= (int)cycle;

	switch(wave){
	case WAVE_SIN:
		return sin(2 * M_PI * cycle);
	case WAVE_SAW:
		cycle *= 2;
		if(cycle > 1) cycle -= 2;
		return cycle;
	case WAVE_SQUARE:
		return cycle < 0.5 ? 1 : -1;
	case WAVE_NOISE:
		return ((double)rand() / RAND_MAX) * 2 - 1;
	}
	return 0;
}

struct vco_rec{
	int wave1, wave2;
	int tune; /* for vco2 */
	double mix;
	int ring;
};

struct modu_rec{
	int pitch1, pitch2, filter1, filter2;
};

struct lfo_rec{
	int wave;
	double freq, delay;
};

struct env_rec{
	double attack;	/* sec */
	double decay;	/* sec */
	double sustain;	/* 0..1 */
	double release;	/* sec */
};

struct delay_rec{
	int onoff;
	double sec, gain;
};

struct tone_rec{
	struct vco_rec vco;
	struct filter_rec fl1, fl2;
	struct env_rec env;
	double level;
	struct modu_rec lfo_modu;
	struct lfo_rec lfo;
	struct modu_rec env_modu;
	struct delay_rec delay;
	int chorus;
} tone_inf[] = {
	{	/* strings */
		{ WAVE_SAW, WAVE_SAW, 12, 0.5, OFF },
		{ LPF, 3000, 1.5 }, { OFF, },
		{ 0.15, 0.5, 0.8, 0.5 },
		1.0,
		{ OFF, 12, OFF, OFF }, { WAVE_SIN, 4, 0.3 },
		{ OFF, OFF, OFF, OFF },
		{ OFF, }, ON,
	},{	/* bass */
		{ WAVE_SAW, WAVE_SQUARE, OFF, 0.5, OFF },
		{ LPF, 1000, 1.5 }, { OFF, },
		{ 0.05, 0.2, 0.4, 0.2 },
		1.0,
		{ OFF, 60, OFF, OFF }, { WAVE_SIN, 1.5, 0.2 },
		{ OFF, OFF, OFF, OFF },
		{ OFF, }, ON,
	},{	/* lead */
		{ WAVE_SQUARE, WAVE_SQUARE, 10, 0.5, OFF },
		{ LPF, 2000, 4 }, { OFF, },
		{ 0.01, 0.2, 0.8, 0.3 },
		1.0,
		{ OFF, 1, 5, OFF }, { WAVE_SIN, 4, 0.3 },
		{ OFF, OFF, OFF, OFF },
		{ ON, 0.2, 0.4}, OFF,
	},{	/* SIN */
		{ WAVE_SIN, WAVE_SIN, OFF, 0, OFF },
		{ LPF, 20000, 0.8 }, { OFF, },
		{ 0, 0.3, 0.2, 0.3 },
		1.4,
		{ 25, OFF, OFF, OFF }, { WAVE_SIN, 6, 0.3 },
		{ OFF, OFF, OFF, OFF },
		{ OFF, }, OFF,
	}
}, drum_tone_inf[] = {
	{	/* bass */
		{ WAVE_SIN, WAVE_NOISE, OFF, 0.4, OFF },
		{ LPF, 400, 1 }, { OFF, },
		{ 0.01, 0.18, 0, 0.18 },
		9.0,
		{ 100, OFF, 30, OFF }, { WAVE_NOISE, 0, 0.5 },
		{ OFF, OFF, OFF, OFF },
		{ OFF, }, OFF,
	},{	/* snare */
		{ WAVE_SQUARE, WAVE_NOISE, OFF, 0.8, ON },
		{ LPF, 1500, 1.7 }, { OFF, }, 
		{ 0, 0.4, 0.3, 0.4 },
		5,
		{ OFF, OFF, OFF, OFF }, {},
		{ OFF, OFF, OFF, OFF },
		{ OFF, }, OFF,
	},{	/* tom */
		{ WAVE_SQUARE, WAVE_NOISE, OFF, 0.5, ON },
		{ LPF, 800, 2.5 }, { OFF, },
		{ 0, 0.03, 0.1, 0.4 },
		5,
		{ OFF, OFF, OFF, OFF }, {},
		{ 200, OFF, 1200, OFF },
		{ OFF, }, OFF,
	},{	/* hi-hat close */
		{ WAVE_SQUARE, WAVE_SQUARE, 700, 0.9, ON },
		{ LPF, 16000, 2 }, { OFF, },
		{ 0, 0.15, 0, 0.15 },
		0.6,
		{ OFF, OFF, OFF, OFF }, {},
		{ OFF, OFF, OFF, OFF },
		{ OFF, }, OFF,
	},{	/* hi-hat open */
		{ WAVE_SQUARE, WAVE_SQUARE, 700, 0.9, ON },
		{ LPF, 16000, 2 }, { OFF, },
		{ 0, 0, 1, 0.35 },
		0.6,
		{ OFF, OFF, OFF, OFF }, {},
		{ OFF, OFF, OFF, OFF },
		{ OFF, }, OFF,
	},{	/* cymbal */
		{ WAVE_NOISE, WAVE_SQUARE, OFF, 0.8, ON },
		{ LPF, 4000, 2 }, { OFF, },
		{ 0, 0.01, 0.2, 0.8 },
		9,
		{ OFF, OFF, OFF, OFF }, {},
		{ OFF, OFF, 600, OFF }, 
		{ OFF, }, OFF,
	},{	/* side stick */
		{ WAVE_NOISE, WAVE_SQUARE, OFF, 0.2, OFF },
		{ LPF, 1700, 3 }, { OFF, },
		{ 0, 0.012, 0.1, 0.7 },
		10,
		{ OFF, OFF, OFF, OFF }, {},
		{ OFF, OFF, OFF, OFF },
		{ OFF, }, OFF,
	}
};

struct tone_compo_rec{
	struct tone_rec *tone;
	int note; /* -1 : event note */
	double rate;
};

#define PROG_DRUM	0

struct{
	int prog, note; /* note for ch 9 */
	struct tone_compo_rec *tone_compo;
} tones_lst[] = {
	{
		PROG_DRUM, 36, /* bass drum1 */
		(struct tone_compo_rec []){
			{ &drum_tone_inf[0], 28, 1.0 }, { NULL, }
		}
	},{
		PROG_DRUM, 37, /* side stick */
		(struct tone_compo_rec []){
			{ &drum_tone_inf[6], 110, 1.0 }, { NULL, }
		}
	},{
		PROG_DRUM, 40, /* electric snare */
		(struct tone_compo_rec []){
			{ &drum_tone_inf[1], 69, 1.0 }, { NULL, }
		}
	},{
		PROG_DRUM, 41, /* low floor tom */
		(struct tone_compo_rec []){
			{ &drum_tone_inf[2], 50, 1.0 }, { NULL, }
		}
	},{
		PROG_DRUM, 42, /* closed hi-hat */
		(struct tone_compo_rec []){
			{ &drum_tone_inf[3], 115 + 8, 1.0 }, { NULL, }
		}
	},{
		PROG_DRUM, 46, /* open hi-hat */
		(struct tone_compo_rec []){
			{ &drum_tone_inf[4], 115 + 8, 1.0 }, { NULL, }
		}
	},{
		PROG_DRUM, 49, /* crash cymbal 1 */
		(struct tone_compo_rec []){
			{ &drum_tone_inf[5], 75, 1.0 }, { NULL, }
		}
	},{
		PROG_DRUM, 57, /* crash cymbal 2 */
		(struct tone_compo_rec []){
			{ &drum_tone_inf[5], 85, 1.0 }, { NULL, }
		}
	},{
		48, -1, /* timpani */
		(struct tone_compo_rec []){
			{ &tone_inf[0], -1, 1.0 }, { NULL, }
		}
	},{
		50, -1, /* strings ensamble 2 */
		(struct tone_compo_rec []){
			{ &tone_inf[0], -1, 1.0 }, { NULL, }
		}
	},{
		35, -1, /* electric bass (pick) */
		(struct tone_compo_rec []){
			{ &tone_inf[1], -1, 1.0 }, { NULL, }
		}
	},{
		79, -1, /* whistle */
		(struct tone_compo_rec []){
			{ &tone_inf[2], -1, 1.0 }, { NULL, }
		}
	},{
		81, -1, /* lead 1 (square) */
		(struct tone_compo_rec []){
			{ &tone_inf[2], -1, 1.0 }, { NULL, }
		}
	},{
		87, -1, /* lead 7 (fifths) */
		(struct tone_compo_rec []){
			{ &tone_inf[2], -1, 1.0 }, { NULL, }
		}
	},{
		24, -1, /* tango accordion */
		(struct tone_compo_rec []){
			{ &tone_inf[3], -1, 1.0 }, { NULL, }
		}
	},{
		67, -1, /* tenor sax */
		(struct tone_compo_rec []){
			{ &tone_inf[3], -1, 1.0 }, { NULL, }
		}
	},{
		-1, /* tail */
	}
};

void
stat_lst_free(struct stat_rec *stat)
{
	if(!stat) return;
	stat->nt = NULL;
	stat_lst_free(stat->next);
}

struct stat_rec *
stat_lst_alloc_init(int n, double sec, struct note_rec *nt, struct tone_compo_rec *tone_compo_arr, struct stat_rec *next)
{
	struct stat_rec *stat;
	int i;

	if(n > 1){
		next = stat_lst_alloc_init(n - 1, sec, nt, tone_compo_arr + 1, next);
		if(next == NULL) return NULL;
	}
	for(i=0; i<STAT_BUF_N; i++) if(stat_buf[i].nt == NULL) break;
	if(i >= STAT_BUF_N){
		stat_lst_free(next);
		return NULL;
	}
	stat = &stat_buf[i];
	stat->nt = nt;
	stat->tone_compo = tone_compo_arr;
	stat->next = next;
	stat_init(stat, sec);
	return stat;
}

#define MIDI_CH_N	16
struct ch_rec{
	int vol;
	int pan;
	int bend;
	int rpn;
	int bend_range;
	int prog;
} ch_inf[ MIDI_CH_N ];

#define CH_PROG(ch)	( (ch) == 9 ? 0 : ch_inf[ch].prog )

struct tone_compo_rec *
tone_compo_get(int ch, int note, int *ret_n)
{
	struct tone_compo_rec *tone_compo;
	int prog, i;

	prog = CH_PROG(ch);
	for(i=0; tones_lst[i].prog >= 0; i++){
		if(tones_lst[i].prog == prog &&
		   (tones_lst[i].note == note || tones_lst[i].note < 0)) break;
	}
	if(tones_lst[i].prog < 0) return NULL; /* not found */
	tone_compo = tones_lst[i].tone_compo;
	if(ret_n){
		for(i=0; tone_compo[i].tone; i++);
		*ret_n = i;
	}
	return tone_compo;
}

double
env_out(struct stat_rec *stat, double sec)
{
	// 引数を note_rec 構造体から stat_rec 構造体に変更
	
	struct note_rec *nt;
	struct env_rec *e;
	double v;

	nt = stat->nt;
	e = &stat->tone_compo->tone->env;
	if(nt->onoff){
		sec -= nt->on_sec;
		if(sec < e->attack){
			v = sec / e->attack;
			return log10(1 + v * 9);
		}
		sec -= e->attack;
		if(sec < e->decay){
			v = sec / e->decay;
			v = log10(1 + v * 9);
			return 1 - v * (1 - e->sustain);
		}
		return e->sustain;
	}
	sec -= nt->off_sec;
	if(sec < e->release){
		v = sec / e->release;
		v = log10(1 + v * 9);
		return (1 - v) * stat->off_v;
	}
	return 0;
}

void
modu_out(double v, struct modu_rec *modu, double *ret_arr)
{
	if(modu->pitch1) ret_arr[0] += v * modu->pitch1 * (1.0 / 1200);
	if(modu->pitch2) ret_arr[1] += v * modu->pitch2 * (1.0 / 1200);
	if(modu->filter1) ret_arr[2] += v * modu->filter1 * (1.0 / 1200);
	if(modu->filter2) ret_arr[3] += v * modu->filter2 * (1.0 / 1200);
}

double
lfo_out(struct lfo_rec *lfo, struct modu_rec *modu, double sec, double on_sec)
{
	double dsec;

	if(!(modu->pitch1 || modu->pitch2 || modu->filter1 || modu->filter2)) return 0;
	if((dsec = sec - on_sec - lfo->delay) <= 0) return 0;
	return wave_out(lfo->wave, lfo->freq * dsec);
}

double
vco_out(int wave, struct vco_stat_rec *stat, double freq, double sec, double modu_v)
{
	if(modu_v != 0) freq *= pow(2, modu_v);
	vco_stat_update(stat, freq, sec);
	return wave_out(wave, stat->cycle);
}

double
vcf_out(struct filter_rec *fl, struct filter_stat_rec *stat, double smp_t, double modu_v, double v)
{
	// 引数の out_rec 構造体を、使ってる smp_t だけに変更
	
	struct filter_rec tmp;

	if(stat->idx < 0) filter_init(fl, stat, smp_t);
	// 引数の out_rec 構造体を、使ってる smp_t だけに変更
	
	if(modu_v != 0){
		tmp = *fl;
		tmp.freq *= pow(2, modu_v);
		filter_update(&tmp, stat, smp_t);
		// 引数の out_rec 構造体を、使ってる smp_t だけに変更
		
	}
	return filter_out(stat, v);
}

void
delay_buf_set(struct stat_rec *stat, double v, double env_v)
{
	// 引数の out_rec 構造体、note_rec 構造体を、
	// stat_rec 構造体に変更
	
	int i;

	i = (stat->nt->ot->smp_cnt - stat->fst_smp_cnt) % DELAY_BUF_N;
	stat->delay_buf[0][i] = v;
	stat->delay_buf[1][i] = env_v;
}

#define MIX(a, b, rate)		( (a) * (1 - (rate)) + (b) * (rate) )

double
tbl_lookup(double *tbl, int n, double d_idx)
{
	int i;

	i = (int)d_idx;
	d_idx -= i;
	i %= n;
	return MIX(tbl[i], tbl[(i+1)%n], d_idx);
}

double
delay_buf_lookup(struct stat_rec *stat, double sec, double *ret_env_v)
{
	// 引数の out_rec 構造体、note_rec 構造体を、
	// stat_rec 構造体に変更
	
	double cycle;

	cycle = stat->nt->ot->smp_freq * sec - stat->fst_smp_cnt;
	if(ret_env_v) *ret_env_v = tbl_lookup(stat->delay_buf[1], DELAY_BUF_N, cycle);
	return tbl_lookup(stat->delay_buf[0], DELAY_BUF_N, cycle);
}

double
delay_out(struct stat_rec *stat, struct delay_rec *delay, double *ret_env_v)
{
	// 引数の out_rec 構造体、note_rec 構造体を、
	// stat_rec 構造体に変更
	
	double v, sec;

	sec = stat->nt->ot->sec;
	if(sec - stat->nt->on_sec < delay->sec) return 0;
	v = delay_buf_lookup(stat, sec - delay->sec, ret_env_v) * delay->gain;
	if(ret_env_v) *ret_env_v *= delay->gain;
	return v;
}

double
chorus_out(struct stat_rec *stat)
{
	// 引数の out_rec 構造体、note_rec 構造体を、
	// stat_rec 構造体に変更
	
	double sec,dsec, bak_sec;

	sec = stat->nt->ot->sec;
	dsec = sec - stat->nt->on_sec;
	bak_sec = 0.01 + 0.001 * sin(2 * M_PI * 0.8 * dsec);
	if(dsec < bak_sec) return 0;
	return delay_buf_lookup(stat, sec - bak_sec, NULL);
}

double
tone_out(struct stat_rec *stat, double freq, double env_v)
{
	// 引数の out_rec 構造体、note_rec 構造体を、
	// stat_rec 構造体に変更
	
	struct tone_rec *tn;
	int i;
	double v, v1, v2, lfo_v, modu_v[4];
	struct vco_rec *vco;
	struct out_rec *ot;

	tn = stat->tone_compo->tone;
	ot = stat->nt->ot;

	lfo_v = lfo_out(&tn->lfo, &tn->lfo_modu, ot->sec, stat->nt->on_sec);

	for(i=0; i<4; i++) modu_v[i] = 0;
	modu_out(lfo_v, &tn->lfo_modu, modu_v);
	modu_out(env_v, &tn->env_modu, modu_v);

	vco = &tn->vco;
	v1 = vco_out(vco->wave1, &stat->vco[0], freq, ot->sec, modu_v[0]);

	modu_v[1] += vco->tune * (1.0 / 1200);
	v2 = vco_out(vco->wave2, &stat->vco[1], freq, ot->sec, modu_v[1]);
	if(vco->ring){
		v = v1 * v2;
		v1 = (v1 + v2) * 0.5;
		v2 = v;
	}
	v = MIX(v1, v2, vco->mix);

	if(tn->fl1.type != OFF) v = vcf_out(&tn->fl1, &stat->filter[0], ot->smp_t, modu_v[2], v);
	if(tn->fl2.type != OFF) v = vcf_out(&tn->fl2, &stat->filter[1], ot->smp_t, modu_v[3], v);

	v *= env_v * tn->level;
	return v;
}

int
note_out(struct note_rec *nt, double *vl, double *vr)
{
	// 引数の out_rec 構造体を削除
	
	double v, sum_v, freq, pan, env_v, d_env_v;
	int nch, cnt;
	struct tone_rec *tn;
	struct tone_compo_rec *tone_compo;
	struct stat_rec *stat;
	struct out_rec *ot;

	nch = nt->ch;
	ot = nt->ot;
	// ここで out_rec 構造体を取得
	
	cnt = 0;
	sum_v = 0;
	for(stat=nt->stat_lst; stat; stat=stat->next){
		tone_compo = stat->tone_compo;
		if(tone_compo == NULL) continue;
		cnt++;
		tn = tone_compo->tone;
		freq = note_to_freq(tone_compo->note >= 0 ? tone_compo->note : nt->note);

		if(stat->fst_smp_cnt < 0) stat->fst_smp_cnt = ot->smp_cnt;
		if(ch_inf[nch].bend != 0) freq *= pow(2, ch_inf[nch].bend * ch_inf[nch].bend_range * (1.0 / (8192 * 12)));

		env_v = env_out(stat, ot->sec);
		v = (env_v > 0) ? tone_out(stat, freq, env_v) : 0;

		d_env_v = 0;
		if(tn->delay.onoff) v += delay_out(stat, &tn->delay, &d_env_v);
		d_env_v += env_v;
		delay_buf_set(stat, v, d_env_v);
		if(tn->chorus) v += chorus_out(stat);

		sum_v += v * tone_compo->rate;

		if(nt->onoff == 0 && ot->sec - nt->off_sec >= tn->env.release && (!tn->delay.onoff || d_env_v < 0.01)){
			stat->tone_compo = NULL;
		}
	}
	v = sum_v;

	v *= (nt->velo * (1.0 / 127)) * (ch_inf[nch].vol * (1.0 / ((1<<14)-1)));
	if(ot->ch_num == 1){
		*vl += v;
	}else{
		pan = ch_inf[nch].pan * (1.0 / (1<<14));
		*vl += (1 - pan) * v;
		*vr += pan * v;
	}
	return cnt == 0;
}

void
data_out(struct out_rec *ot, double evt_sec)
{
	double vl, vr;
	int i;
	struct note_rec *nt;

	while((ot->sec = ot->smp_t * ot->smp_cnt) < evt_sec){
		vl = vr = 0;
		for(i=0; i<NOTE_BUF_N; i++){
			if(note_buf_is_free(i)) continue;
			nt = &note_buf[i];
			nt->ot = ot;
			// ここで out_rec 構造体を設定
			
			if(note_out(nt, &vl, &vr)){
			// 引数の out_rec 構造体を削除
			
				stat_lst_free(nt->stat_lst);
				note_buf_free(i);
			}
		}
		out_do(ot, vl * (1.0 / 16));
		if(ot->ch_num > 1) out_do(ot, vr * (1.0 / 16));
		ot->smp_cnt++;
	}
}

void
note_onoff(int onoff, double evt_sec, int ch, int note, int velo)
{
	int i, tone_n;
	struct note_rec *nt;
	struct stat_rec *stat;
	struct tone_compo_rec *tone_compo;

	if(onoff){
		if((i = note_buf_search(-1, -1, -1)) < 0){
			MSG("note_buf full");
			return;
		}
		nt = &note_buf[i];
		nt->note = note;
		nt->ch = ch;
		nt->onoff = 1;
		nt->on_sec = evt_sec;
		nt->velo = velo;

		if((tone_compo = tone_compo_get(ch, note, &tone_n)) == NULL){
			note_buf_free(i);
			return;
		}
		if((nt->stat_lst = stat_lst_alloc_init(tone_n, evt_sec, nt, tone_compo, NULL)) == NULL){
			note_buf_free(i);
		}
	}else{
		if((i = note_buf_search(ch, note, 1)) < 0) return;
		nt = &note_buf[i];
		for(stat=nt->stat_lst; stat; stat=stat->next){
			stat->off_v = env_out(stat, evt_sec);
		}
		nt->onoff = 0;
		nt->off_sec = evt_sec;
	}
}

void
msb_set(int *vp, int v)
{
	*vp &= ~(127<<7);
	*vp |= v<<7;
}

void
lsb_set(int *vp, int v)
{
	*vp &= ~127;
	*vp |= v;
}

void
bend_note_update(int ch, double sec)
{
	int i, j;
	struct note_rec *nt;
	struct vco_stat_rec *vco_stat;
	struct stat_rec *stat;

	for(i=0; i<NOTE_BUF_N; i++){
		if(note_buf_is_free(i)) continue;
		nt = &note_buf[i];
		if(nt->ch != ch) continue;
		for(stat=nt->stat_lst; stat; stat=stat->next){
			for(j=0; j<2; j++){
				vco_stat = &stat->vco[j];
				vco_stat_update(vco_stat, vco_stat->freq, sec);
			}
		}
	}
}

int
main(int ac, char **av)
{
	int div4, delta_sum;
	int i, n, v, hi, low, note, velo;
	int ch, type;
	double sec;
	struct out_rec otr;
	int tempo, tempo_delta_sum;
	double tempo_sec;

	out_init(&otr, ac, av);
	note_buf_init();
	stat_buf_init();
	for(i=0; i<MIDI_CH_N; i++){
		ch_inf[i].vol = 0;
		ch_inf[i].pan = 1<<(14-1);
		ch_inf[i].bend = 0;
		ch_inf[i].rpn = 0;
		ch_inf[i].bend_range = 2;
		ch_inf[i].prog =-1;
	}
	tempo = 500000;
	tempo_delta_sum = 0;
	tempo_sec = 0;

	div4 = header();

	if(!rd_str_chk(4, "MTrk")) ERR("track id");
	v = rd_int(4); /* skip */

	hi = low = 0;
	delta_sum = 0;
	while((v = rd_delta()) != EOF){
		delta_sum += v;
		sec = tempo_sec + (double)(delta_sum - tempo_delta_sum) / div4 * tempo * 0.000001;
		
		if((v = rd()) & 0x80){
			hi = (v >> 4) & 0xf;
			low  = v & 0xf;
		}else bk(v);

		data_out(&otr, sec);

		ch = low;
		switch(hi){
		case 8:
		case 9:
			note = rd();
			velo = rd();
			note_onoff(hi == 9, sec, ch, note, velo);
			break;
		case 0xb: /* control change */
			type = rd();
			v = rd();
			switch(type){
			case 7: /* channel volume msb */
				msb_set(&ch_inf[ch].vol, v);
				break;
			case 39: /* channel volume lsb */
				lsb_set(&ch_inf[ch].vol, v);
				break;
			case 10: /* pan msb */
				msb_set(&ch_inf[ch].pan, v);
				break;
			case 42: /* pan lsb */
				lsb_set(&ch_inf[ch].pan, v);
				break;
			case 100: /* rpn lsb */
				lsb_set(&ch_inf[ch].rpn, v);
				break;
			case 101: /* rpn msb */
				msb_set(&ch_inf[ch].rpn, v);
				break;
			case 6: /* data entry msb */
				switch(ch_inf[ch].rpn){
				case 0: /* pitch bend range */
					ch_inf[ch].bend_range = v;
					break;
				}
				break;
			}
			break;
		case 0xa:
			rd();
			rd();
			break;
		case 0xe: /* pitch wheel change */
			bend_note_update(ch, sec);
			v = rd();
			v |= rd() << 7;
			ch_inf[ch].bend = v - 8192;
			break;
		case 0xc: /* program number */
			v = rd();
			ch_inf[ch].prog = v;
			break;
		case 0xd:
			rd();
			break;
		case 0xf:
			type = rd();
			switch(low){
			case 0:
				while(rd() != 0xf7);
				break;
			case 1:
			case 3:
				rd();
				break;
			case 2:
				rd();
				rd();
				break;
			case 0xf: /* meta */
				n = rd();
				switch(type){
				case 0x51: /* set tempo */
					v = rd_int(n);
					tempo = v;
					tempo_delta_sum = delta_sum;
					tempo_sec = sec;
					break;
				default:
					for(i=0; i<n; i++) rd();
					break;
				}
				break;
			default:
				break;
			}
			break;
		}
	}
	if(otr.fp != stdout) pclose(otr.fp);
	return 0;
}

/* EOF */



工事中...