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