#include #include #include #include #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= 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; ich; 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> 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