#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 */
#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 = ¬e_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 = ¬e_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 = ¬e_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(¬e_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(¬e_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 = ¬e_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(¬e_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(¬e_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 = ¬e_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(¬e_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(¬e_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 = ¬e_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(¬e_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(¬e_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 = ¬e_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(¬e_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(¬e_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 = ¬e_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(¬e_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(¬e_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 = ¬e_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(¬e_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(¬e_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 = ¬e_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(¬e_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(¬e_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 = ¬e_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(¬e_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(¬e_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 = ¬e_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(¬e_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(¬e_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 = ¬e_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(¬e_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(¬e_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 = ¬e_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 = ¬e_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(¬e_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(¬e_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 = ¬e_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 = ¬e_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(¬e_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(¬e_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 = ¬e_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 = ¬e_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(¬e_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(¬e_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 = ¬e_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 = ¬e_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 = ¬e_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(¬e_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 = ¬e_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 = ¬e_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 = ¬e_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(¬e_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 = ¬e_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 = ¬e_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 = ¬e_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(¬e_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 = ¬e_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 = ¬e_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 = ¬e_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(¬e_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 = ¬e_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 = ¬e_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 = ¬e_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(¬e_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 = ¬e_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 = ¬e_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 = ¬e_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(¬e_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 = ¬e_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 = ¬e_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 = ¬e_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(¬e_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 = ¬e_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 = ¬e_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 = ¬e_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(¬e_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 = ¬e_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 = ¬e_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 = ¬e_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(¬e_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 = ¬e_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 = ¬e_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 = ¬e_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(¬e_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 = ¬e_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 = ¬e_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 = ¬e_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(¬e_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 = ¬e_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 = ¬e_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 = ¬e_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(¬e_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 = ¬e_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 = ¬e_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(¬e_buf[i].stat, evt_sec);
}else{
if((i = note_buf_search(ch, note, 1)) < 0) return;
note_buf[i].stat.off_v = env_out(¬e_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 = ¬e_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 = ¬e_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(¬e_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(¬e_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 = ¬e_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 = ¬e_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(¬e_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(¬e_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 = ¬e_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 = ¬e_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(¬e_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(¬e_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 = ¬e_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 = ¬e_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 = ¬e_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 = ¬e_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 = ¬e_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 = ¬e_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 = ¬e_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 = ¬e_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 = ¬e_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 = ¬e_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 = ¬e_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 = ¬e_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 = ¬e_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 = ¬e_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 = ¬e_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 = ¬e_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 = ¬e_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 */
工事中...