#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 は、 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 */を指定 // 引数 ac, av は、main()関数の引数を指定 // 引数 def は、デフォルト値として返す値を指定
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 は、 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 */を指定 // 引数 ac, av は、main()関数の引数を指定
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 は、 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 */を指定 // 引数 ac, av は、main()関数の引数を指定 // 引数 def は、デフォルト値として返す文字列を指定
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 */
工事中...