#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 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= 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> 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