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