#include #include #include #include #include #include #include #include #include #include #include #include #define ALSA_PCM_NEW_HW_PARAMS_API #include #include "strings.h" static const char plr_wheel[] = { '/', '-', '\\', '|'}; static const char plr_notes[] = { 'C', 'c', 'D', 'd', 'E', 'F', 'f', 'G', 'g', 'A', 'a', 'B'}; static const char plr_hexn[] = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F'}; static const char plr_waves[] = { 'S', 'H', 'A', 'P', 's', 'a', 'R', 'D'}; static const char *plr_descs[] = { STR_IMID_TITLE, STR_IMID_INFO, STR_IMID_COPY, STR_IMID_WARN, STR_IMID_LANG, STR_IMID_VER }; static const char plr_phases[] = { 'A', 'D', 'S', 'R'}; int32_t log_debug = 0; bool karaoke = false; uint32_t log_pos = 0; uint32_t mlog_pos; uint32_t klog_pos; uint32_t klog_offs; uint32_t midinf_offs[6]; char *logger[4]; char *mlogger[4]; char *klogger[5]; char *midinfo[6]; #define MINFO_DESC 10 int16_t vu_sum[2]; char *tbuffer; int last_w = 0; int last_h = 0; char bankname[36]; void plr_setbnk(const char *dmxname, const char *drmname) { int pos = 0; for(int h = 0; h < (drmname ? 2 : 1); h++) { const char *filename = h ? drmname : dmxname; int len = 0; int dp = 0; char ch; while(ch = filename[len++]) { if((ch == '/') || (ch == '\\')) { dp = len; } } len -= dp+1; len = len > (drmname ? 17 : 35) ? (drmname ? 17 : 35) : len; memcpy(bankname+pos, filename+dp, len); bankname[pos += len] = (h || (drmname == NULL)) ? 0 : '+'; pos++; } } void mid_log(char *format, ...) { va_list ap; va_start(ap, format); logger[log_pos][0] = 0; vsnprintf(logger[log_pos++], 116, format, ap); if(log_pos == 4) { log_pos = 0; } va_end(ap); } void mid_mlog(char *format, ...) { va_list ap; va_start(ap, format); mlogger[mlog_pos][0] = 0; vsnprintf(mlogger[mlog_pos++], 82, format, ap); if(mlog_pos == 4) { mlog_pos = 0; } va_end(ap); } void mid_clog() { klog_pos = 0; klog_offs = 0; if(karaoke) { for(int z = 0; z < 5; z++) { klogger[z][0] = 0; } } else { for(int z = 0; z < 5; z++) { memset(klogger[z], '-', 115); klogger[z][115] = 0; } } } void mid_cmlog() { karaoke = false; mlog_pos = 0; for(int z = 0; z < 4; z++) { mlogger[z][0] = 0; } for(int z = 0; z < 6; z++) { int len = strlen(plr_descs[z]); memcpy(midinfo[z], plr_descs[z], len); memset((midinfo[z])+len, ' ', MINFO_DESC-2-len); midinfo[z][MINFO_DESC-2] = ':'; midinfo[z][MINFO_DESC-1] = ' '; midinfo[z][MINFO_DESC] = 0; midinf_offs[z] = MINFO_DESC; } mid_clog(); } void vu_reset() { vu_sum[0] = vu_sum[1] = 0; } void vu_push(int16_t *buf) { for(int j = 0; j < 2; j++) { vu_sum[j] = ((((int32_t)(buf[j] < 0 ? (-buf[j]) : buf[j])) * 2) + ((int32_t)vu_sum[j])) / 3; } } void mid_kar() { if(karaoke) { return; } karaoke = true; mid_clog(); } void mid_info(int type, char *text) { char *info = midinfo[type]; int32_t offs = midinf_offs[type]; int len = strlen(text); int max = ((type >= 4) ? 57 : 115); max -= (offs != MINFO_DESC) ? 2 : 0; len = (len > (max-offs)) ? (max-offs) : len; if(len <= 0) { return; } if(offs != MINFO_DESC) { info[offs++] = ';'; info[offs++] = ' '; } memcpy(info+offs, text, len); offs += len; info[offs] = 0; midinf_offs[type] = offs; } void mid_tlog(int type, char *text) { int slen = strlen(text); for(int h = 0; h < slen; h++) { text[h] = ((text[h] < 32) || (text[h] > 126)) ? ((h == (slen-1)) ? 0 : '?') : text[h]; } if((type == 1) && (text[0] == '@')) { // text += 1; switch(text[1]) { case 'T': mid_info(0, text+2); return; case 'I': mid_info(1, text+2); return; case 'K': mid_info(2, text+2); return; case 'W': mid_info(3, text+2); return; case 'L': mid_info(4, text+2); return; case 'V': mid_info(5, text+2); return; } // text += (text[0] == 0) ? 0 : 1; } else if((type == 1) && (text[0] == '%') && (text[1] == '-')) { mid_kar(); return; } else if(type == 1 /* || type == 5 */) { switch(text[0]) { case '\\': mid_kar(); mid_clog(); text += 1; slen -= 1; break; case '/': // mid_kar(); if(karaoke) { klog_pos += 1; klog_offs = 0; if(klog_pos == 5) { mid_clog(); } text += 1; slen -= 1; } break; } if(karaoke) { int len; while(slen > 0) { len = (slen > (115-klog_offs)) ? (115-klog_offs) : slen; if(len <= 0) { break; } memcpy((klogger[klog_pos])+klog_offs, text, len); klog_offs += len; klogger[klog_pos][klog_offs] = 0; slen -= len; if(slen > 0) { klog_pos += 1; klog_offs = 0; if(klog_pos == 5) { mid_clog(); } } } return; } } if(log_debug || (type <= 2) || (type >= 5)) { mid_mlog(STR_MID_TEXT, type, text); } } void mid_dlog(char *format, ...) { if(log_debug) { mid_mlog(format); } } #include "opl3.h" #include "dmx.h" #include "bank.h" #include "midi.h" #include "audio.h" #define ARGPARSE_DE #include "../argparse.h" #define PLR_REFRESH 16 #define PLR_BLACK 1 #define PLR_DRED 2 #define PLR_DGREEN 3 #define PLR_DYELLOW 4 #define PLR_DBLUE 5 #define PLR_DMAGENTA 6 #define PLR_DCYAN 7 #define PLR_GRAY 8 #define PLR_DARKGRAY 9 #define PLR_RED 10 #define PLR_GREEN 11 #define PLR_YELLOW 12 #define PLR_BLUE 13 #define PLR_MAGENTA 14 #define PLR_CYAN 15 #define PLR_WHITE 16 enum plr_state { PL_NORMAL, PL_PREV, PL_NEXT, PL_QUIT, PL_INTERRUPT }; int8_t plr_int = PL_NORMAL; void plr_sig(int signum) { plr_int = PL_INTERRUPT; } void plr_skip() { if(plr_int == PL_INTERRUPT) { return; } int c = wgetch(stdscr); switch(c) { case 'n': plr_int = PL_NEXT; break; case 'b': plr_int = PL_PREV; break; case 'q': plr_int = PL_QUIT; break; } } void str_time(char *str, uint64_t time) { uint64_t msecs = time % 1000ULL; uint64_t secs = (time /= 1000ULL) % 60ULL; uint64_t mins = (time /= 60ULL) % 60ULL; time /= 60ULL; sprintf(str, "%02d:%02d:%02d.%03d", time, mins, secs, msecs); } void plr_sep() { color_set(PLR_DARKGRAY, NULL); addch('|'); } void plr_vbdr() { color_set(PLR_DARKGRAY, NULL); addstr("||"); } void plr_newl(int *line) { plr_vbdr(); move((*line)++, 0); } void plr_hbdr(int width) { color_set(PLR_DARKGRAY, NULL); memset(tbuffer, '#', width); tbuffer[width] = 0; addstr(tbuffer); } void plr_pad(int width) { memset(tbuffer, ' ', width); tbuffer[width] = 0; addstr(tbuffer); } void plr_hnbdr(int width, const char *fmt, ...) { va_list ap; va_start(ap, fmt); color_set(PLR_GRAY, NULL); int len = vsprintf(tbuffer, fmt, ap); addstr(tbuffer); addch(' '); plr_hbdr(width - (len+1)); va_end(ap); } void plr_cpfx(char desc, int id, int cl) { color_set(cl, NULL); sprintf(tbuffer, "%c-%02d", desc, id); addstr(tbuffer); } void plr_pfx(const char *desc) { color_set(PLR_DYELLOW, NULL); addstr(desc); } void plr_bv(char ch, int cl, bool on) { color_set(on ? cl : PLR_DBLUE, NULL); addch(on ? ch : '-'); } void plr_dv(const char *s1, int cl1, const char *s2, int cl2, bool sec) { color_set(sec ? cl2 : cl1, NULL); addstr(sec ? s2 : s1); } void plr_fcv(int cl, const char *fmt, ...) { va_list ap; va_start(ap, fmt); color_set(cl, NULL); vsprintf(tbuffer, fmt, ap); addstr(tbuffer); va_end(ap); } void plr_fv(const char *desc, bool dark, const char *fmt, ...) { va_list ap; va_start(ap, fmt); color_set(PLR_GRAY, NULL); addstr(desc); color_set(dark ? PLR_DCYAN : PLR_CYAN, NULL); vsprintf(tbuffer, fmt, ap); addstr(tbuffer); va_end(ap); } void plr_fc(const char *desc, char value) { plr_fv(desc, 0, "%c", value); } void plr_fi(const char *desc, int32_t value) { plr_fv(desc, 0, "%d", value); } void plr_fi2(const char *desc, int32_t value) { plr_fv(desc, 0, "%02d", value); } void plr_fi2d(const char *desc, int32_t value) { plr_fv(desc, 1, "%02d", value); } void plr_fi3(const char *desc, int32_t value) { plr_fv(desc, 0, "%03d", value); } void plr_fi4(const char *desc, int32_t value) { plr_fv(desc, 0, "%04d", value); } void plr_fi5p(const char *desc, int32_t value) { plr_fv(desc, 0, "%+05d", value); } void plr_fi8(const char *desc, int64_t value) { plr_fv(desc, 0, "%08lld", value); } void plr_fi4n(const char *desc, int32_t value) { plr_fv(desc, 0, "%4d", value); } void plr_fhz(const char *desc, int32_t value) { plr_fv(desc, 0, "%6d Hz", value); } void plr_fbit(const char *desc, int32_t value) { plr_fv(desc, 0, "%2d-Bit", value); } void plr_fbpm(const char *desc, int32_t value) { plr_fv(desc, 0, "%4d BPM", value); } void plr_fstr(const char *desc, const char *value) { plr_fv(desc, 0, "%s", value); } void plr_str(const char *str, int cl) { color_set(cl, NULL); addstr(str); } void plr_ncstr(const char *str, int cl, int width) { color_set(cl, NULL); sprintf(tbuffer, "%-*2$.*2$s", str, width); addstr(tbuffer); } void plr_nstr(const char *str, int width) { plr_ncstr(str, PLR_GRAY, width); } void plr_dstr(const char *str, int width) { color_set(PLR_CYAN, NULL); sprintf(tbuffer, "%*2$.*2$s", str, width); addstr(tbuffer); } void plr_printchip(opl3_chip *chip, bank_handle *bank, mid_handle *mid, aud_handle *dev, uint8_t nowait, uint32_t tick, uint64_t mtime, const char *midname, int16_t *aud) { char gfx[33]; move(1, 0); if(dev->iswav) { char *logp = logger[(log_pos+4-1) % 4]; str_time(gfx, mtime); sprintf(tbuffer, "[%s][%08d] %-115s\n", gfx, tick, logp); addstr(tbuffer); refresh(); return; } int line = 1; int sw; int sh; getmaxyx(stdscr, sh, sw); sw = (sw < 176) ? 176 : sw; sh = (sh < 34) ? 34 : sh; if((sw != last_w) || (sh != last_h)) { erase(); } last_w = sw; last_h = sh; int PLR_WIDTH = (sw-2)/39; int PLR_HEIGHT = (sh-34)/3; int pad = (sw-2) - (PLR_WIDTH * 39); int cpad = sw-176; int lpad = sw-121; int nch = chip->n_voices; PLR_HEIGHT = (PLR_HEIGHT > ((nch+PLR_WIDTH-1)/PLR_WIDTH)) ? ((nch+PLR_WIDTH-1)/PLR_WIDTH) : PLR_HEIGHT; int addl = sh - 34 - (PLR_HEIGHT * 3); gfx[16] = 0; plr_vbdr(); plr_hnbdr(sw-4, "%s", STR_PLR_TITLE); plr_newl(&line); for(int p = 0; p < PLR_HEIGHT; p++) { for(int c = 0; c < PLR_WIDTH; c++) { if((p*PLR_WIDTH+c) >= nch) { plr_vbdr(); plr_pad(39*(PLR_WIDTH-c)-2); break; } opl3_channel *channel = &chip->channel[p*PLR_WIDTH+c]; int16_t **out = channel->out; int16_t accm = *out[0] + *out[1] + *out[2] + *out[3]; int32_t chnlvl = 0; for(int n = 0; n < 2; n++) { chnlvl += (int16_t)((accm * channel->level[n]) >> 16); } chnlvl = chnlvl < 0 ? (-chnlvl) : chnlvl; chnlvl = (chnlvl * 16) / 8192; for(int i = 0; i < 16; i++) { gfx[i] = i < chnlvl ? '#' : '-'; } int vid = (p*PLR_WIDTH+c) + 1; uint8_t active = (channel->slots[0]->eg_out <= 0x100) || (channel->slots[1]->eg_out <= 0x100); plr_vbdr(); if(vid < 100) { plr_fcv(active ? PLR_MAGENTA : PLR_DMAGENTA, "%02d", vid); } else { plr_fcv(active ? PLR_MAGENTA : PLR_DMAGENTA, "++"); } plr_sep(); plr_dv("2O", PLR_BLUE, "4O", PLR_GREEN, channel->chtype != ch_2op); plr_sep(); plr_dv("FM", PLR_RED, "AM", PLR_YELLOW, channel->con); plr_sep(); plr_fi("FB", channel->fb); plr_sep(); plr_fi("F", channel->block); plr_fi4("$", channel->f_num); plr_sep(); plr_str(gfx, PLR_GREEN); } if(pad >= 2) { plr_vbdr(); plr_pad(pad-2); } else if(pad == 1) { plr_sep(); } plr_newl(&line); for(int o = 0; o < 2; o++) { for(int c = 0; c < PLR_WIDTH; c++) { if((p*PLR_WIDTH+c) >= nch) { plr_vbdr(); plr_pad(39*(PLR_WIDTH-c)-2); break; } opl3_channel *channel = &chip->channel[p*PLR_WIDTH+c]; opl3_slot *slot = channel->slots[o]; uint8_t trem = slot->trem != (uint8_t*)&slot->chip->zeromod; plr_vbdr(); // plr_fcv(PLR_DMAGENTA, "O%d", o + 1); // plr_sep(); plr_dv(".", PLR_DGREEN, "*", PLR_GREEN, slot->key); plr_sep(); plr_bv('T', PLR_GREEN, trem); plr_bv('V', PLR_YELLOW, slot->reg_vib); plr_bv('S', PLR_RED, slot->reg_type); plr_bv('K', PLR_MAGENTA, slot->reg_ksr); plr_sep(); plr_fi2("M", slot->reg_mult); // plr_sep(); plr_fi2("L", 63-slot->reg_tl); // plr_sep(); plr_fi("K", slot->reg_ksl); // plr_fi3("/", slot->eg_ksl); // plr_sep(); plr_fc("W", plr_waves[slot->reg_wf]); plr_sep(); plr_fi2("E", slot->reg_ar); plr_fi2d("", slot->reg_dr); plr_fi2("", (slot->reg_sl > 15) ? 0 : (15-slot->reg_sl)); plr_fi2d("", slot->reg_rr); plr_sep(); plr_fc("P", plr_phases[slot->eg_gen]); plr_fi3("", slot->eg_rout); plr_fi3("/", slot->eg_out); } if(pad >= 2) { plr_vbdr(); plr_pad(pad-2); } else if(pad == 1) { plr_sep(); } plr_newl(&line); } } for(int l = 0; l < addl; l++) { plr_vbdr(); plr_pad(39*PLR_WIDTH-2); if(pad >= 2) { plr_vbdr(); plr_pad(pad-2); } else if(pad == 1) { plr_sep(); } plr_newl(&line); } plr_vbdr(); plr_hbdr(sw-4); plr_newl(&line); char nid[128+1]; nid[128] = 0; char chid[cpad+1]; chid[cpad] = 0; for(int d = chip->n_voices; d < cpad; d++) { chid[d] = 'x'; } for(int c = 0; c < 16; c++) { bank_channel *channel = &bank->channel[c]; for(int d = 0; d < 128; d++) { nid[d] = (channel->notes[d] == 0xff) ? '-' : '_'; } for(int d = 0; (d < cpad) && (d < chip->n_voices); d++) { bank_voice *voice = &bank->voices[d]; chid[d] = ((voice->note != 0xff) && (voice->channel->ch_num == c)) ? '*' : '.'; } plr_vbdr(); plr_cpfx('M', c + 1, ((channel->pbank != 0) && (channel->pbank != 128)) ? ((bank->flags & BANK_UNKN) ? PLR_YELLOW : PLR_RED) : PLR_DYELLOW); plr_sep(); if((channel->pbank >= 0) && (channel->pbank < 1000)) { plr_fi3("PR", channel->pbank); } else { plr_fstr("PR", "???"); } plr_fi3("/", channel->program); plr_sep(); plr_fi3("VL", channel->volume); plr_sep(); plr_fi3("PN", channel->pan); plr_sep(); plr_fi5p("PT", channel->pitch); plr_sep(); plr_fi3("AC", channel->active); plr_vbdr(); plr_str(nid, PLR_GREEN); plr_vbdr(); plr_str(chid, PLR_GREEN); plr_newl(&line); } for(int d = 0; d < 128; d++) { nid[d] = ' '; } for(int d = 0; d < 11; d++) { nid[d*12] = plr_hexn[d]; } for(int d = 0; d < cpad; d++) { chid[d] = (d == bank->voiceindex) ? '^' : ' '; } str_time(gfx, mtime); plr_vbdr(); plr_pfx("MIDI"); plr_sep(); plr_fi8("TICK ", tick); plr_sep(); plr_fstr("TIME ", gfx); plr_vbdr(); plr_str(nid, PLR_GRAY); plr_vbdr(); plr_str(chid, PLR_GREEN); plr_newl(&line); for(int d = 0; d < 128; d++) { nid[d] = plr_notes[d % 12]; } if(bank->voiceindex < cpad) { chid[bank->voiceindex] = '*'; } plr_vbdr(); plr_bv('K', PLR_YELLOW, bank->flags & BANK_KEEP); plr_bv('U', PLR_RED, bank->flags & BANK_UNKN); plr_bv('W', PLR_MAGENTA, !nowait); plr_bv('?', PLR_GREEN, false); plr_sep(); plr_fi3("USED ", bank->v_used); plr_fi3("/", bank->v_avail); plr_sep(); plr_fbpm("TEMPO ", 60000000 / mid->uspb); plr_fi4n("/", mid->tpqn); plr_vbdr(); plr_str(nid, PLR_GRAY); plr_vbdr(); plr_str(chid, PLR_GREEN); plr_newl(&line); for(int d = 0; d < cpad; d++) { chid[d] = '0' + (((d+1)/10) % 10); } plr_vbdr(); plr_pfx("CARD"); plr_sep(); plr_fbit("FORMAT ", dev->iswide ? 32 : 16); plr_sep(); plr_fhz("RATE ", dev->samplerate); plr_vbdr(); plr_hbdr(128); plr_vbdr(); plr_str(chid, PLR_GRAY); plr_newl(&line); for(int d = 0; d < cpad; d++) { chid[d] = '0' + ((d+1) % 10); } plr_vbdr(); plr_pfx("BANK"); plr_sep(); plr_dstr(bankname, 35); plr_vbdr(); plr_pfx("FILE"); plr_sep(); plr_dstr(midname, 123); plr_vbdr(); plr_str(chid, PLR_GRAY); plr_newl(&line); plr_vbdr(); plr_hbdr(sw-4); plr_newl(&line); for(int l = 0; l < 4; l++) { plr_vbdr(); plr_nstr(midinfo[l], lpad); plr_vbdr(); plr_nstr(klogger[l], 115); plr_newl(&line); } plr_vbdr(); plr_nstr(midinfo[4], lpad/2); plr_sep(); plr_nstr(midinfo[5], (lpad-1)/2); plr_vbdr(); plr_nstr(klogger[4], 115); plr_newl(&line); plr_vbdr(); plr_hbdr(sw-4); plr_newl(&line); gfx[32] = 0; vu_push(aud); for(int l = 0; l < 4; l++) { if((l & 1) == 0) { int32_t chnlvl = vu_sum[l >> 1]; chnlvl = (chnlvl * 32) / 8192; for(int i = 0; i < 32; i++) { gfx[i] = i < chnlvl ? '#' : '-'; } } plr_vbdr(); plr_nstr(logger[(log_pos+l) % 4], lpad); plr_vbdr(); plr_nstr(mlogger[(mlog_pos+l) % 4], 81); plr_vbdr(); plr_ncstr(gfx, PLR_GREEN, 26); plr_ncstr(gfx+26, PLR_YELLOW, 4); plr_ncstr(gfx+30, PLR_RED, 2); plr_newl(&line); } plr_vbdr(); plr_hnbdr(sw-4, "%c %s", plr_wheel[(tick >> 5) & 3], STR_PLR_INFO); plr_newl(&line); plr_skip(); refresh(); } bool plr_play(opl3_chip *chip, bank_handle *bank, aud_handle *dev, const char *midname, const char *dmxname, uint8_t nowait, uint32_t midis, uint32_t num) { mid_handle mid; if(mid_read(&mid, midname) ^ 1) { return false; } mid_log(STR_PLR_PLAY, midname, num+1, midis); uint64_t sampletime = 1000000000ULL / ((uint64_t)dev->samplerate); uint64_t elapsed = 0; uint64_t samples = 0; uint64_t pushed = 0; uint32_t tick = 0; int16_t buf[2]; while((plr_int == PL_NORMAL) && mid_tick(&mid, bank, chip)) { elapsed += ((uint64_t)mid.ticktime) * 1000ULL; while(elapsed >= sampletime) { OPL3_GenerateResampled(chip, buf); aud_push(dev, buf); samples++; if(samples >= (dev->samplerate/PLR_REFRESH)) { pushed += samples; samples = 0; plr_printchip(chip, bank, &mid, dev, nowait, tick, pushed*1000ULL/dev->samplerate, midname, buf); } elapsed -= sampletime; } if(samples >= (dev->samplerate/PLR_REFRESH)) { pushed += samples; samples = 0; plr_printchip(chip, bank, &mid, dev, nowait, tick, pushed*1000ULL/dev->samplerate, midname, buf); } tick++; } bank_alloff(bank); while((plr_int == PL_NORMAL) && (nowait ^ 1) && OPL3_Playing(chip)) { OPL3_GenerateResampled(chip, buf); aud_push(dev, buf); samples++; if(samples >= (dev->samplerate/PLR_REFRESH)) { pushed += samples; samples = 0; plr_printchip(chip, bank, &mid, dev, nowait, tick, pushed*1000ULL/dev->samplerate, midname, buf); } } plr_printchip(chip, bank, &mid, dev, nowait, tick, (pushed+samples)*1000ULL/dev->samplerate, midname, buf); aud_flush(dev); mid_free(&mid); OPL3_Reset(chip); bank_reset(chip, bank); mid_cmlog(); return true; } bool plr_playloop(uint32_t samplerate, uint32_t voices, char **midnames, uint32_t midis, const char *dmxname, const char *drumname, const char *device, uint32_t fsize, uint32_t bufsize, uint8_t widefmt, uint8_t keep, uint8_t useunkn, int8_t velofunc, uint8_t nowait) { bank_instr *instr = bnk_read_banks(dmxname, drumname, 0); if(instr == NULL) { return false; } opl3_chip *chip = OPL3_Alloc(samplerate, voices); bank_handle *bank = bank_alloc(chip, instr, keep, useunkn, velofunc); char *log = malloc(256*19); for(int h = 0; h < 4; h++) { logger[h] = &log[h*256]; logger[h][0] = 0; } for(int h = 0; h < 4; h++) { mlogger[h] = &log[(h+4)*256]; } for(int h = 0; h < 5; h++) { klogger[h] = &log[(h+8)*256]; } for(int h = 0; h < 6; h++) { midinfo[h] = &log[(h+13)*256]; } plr_setbnk(dmxname, drumname); vu_reset(); mid_cmlog(); aud_handle dev; if(aud_open_dev(&dev, device, samplerate, 2, fsize, bufsize, widefmt) ^ 1) { free(instr); free(chip); free(bank); free(log); return false; } samplerate = dev.samplerate; OPL3_Rate(chip, samplerate); signal(SIGINT, plr_sig); initscr(); if(!(dev.iswav)) { start_color(); use_default_colors(); init_pair(PLR_BLACK, 0, -1); init_pair(PLR_DRED, 1, -1); init_pair(PLR_DGREEN, 2, -1); init_pair(PLR_DYELLOW, 3, -1); init_pair(PLR_DBLUE, 4, -1); init_pair(PLR_DMAGENTA, 5, -1); init_pair(PLR_DCYAN, 6, -1); init_pair(PLR_GRAY, 7, -1); init_pair(PLR_DARKGRAY, 8, -1); init_pair(PLR_RED, 9, -1); init_pair(PLR_GREEN, 10, -1); init_pair(PLR_YELLOW, 11, -1); init_pair(PLR_BLUE, 12, -1); init_pair(PLR_MAGENTA, 13, -1); init_pair(PLR_CYAN, 14, -1); init_pair(PLR_WHITE, 15, -1); } cbreak(); noecho(); nodelay(stdscr, true); nonl(); intrflush(stdscr, false); keypad(stdscr, true); curs_set(0); tbuffer = malloc(65536); bool state = false; bool skip = false; for(int h = 0; (h < midis) && (plr_int == PL_NORMAL); h++) { if(plr_play(chip, bank, &dev, midnames[h], dmxname, nowait, midis, h)) { skip = false; state = true; } else if(skip) { plr_int = PL_PREV; } if(plr_int == PL_NEXT) { plr_int = PL_NORMAL; } else if(plr_int == PL_PREV) { plr_int = PL_NORMAL; h -= ((h == 0) ? 1 : 2); skip = h >= 0; } } // vu_reset(); // plr_printchip(chip, bank, &dev, nowait, 0, 0ULL, 0, dev.iswav, "", "", NULL); aud_close(&dev); free(instr); free(chip); free(bank); free(log); free(tbuffer); endwin(); fprintf(stderr, (plr_int == PL_INTERRUPT) ? STR_PLR_INT"\n" : STR_PLR_END"\n"); return state; } int main(int argc, char **argv) { int32_t samplerate = 48000; int32_t voices = 36; char *device = "default"; int32_t bufsize = 0; int32_t fsize = 32; int32_t widefmt = 0; int32_t keep = 0; int32_t useunkn = 0; int32_t velo = 1; int32_t nowait = 0; char *dmxname = "bank.op2"; char *drumname = NULL; int32_t midis = 0; char **midnames = malloc(sizeof(char*) * argc); argp_t *argspec = arg_alloc(14); arg_add_vstr(argspec, STR_ARGS_MIDI, true, midnames, &midis); arg_add_int(argspec, 'r', STR_ARGS_SRATE, 8000, 384000, &samplerate); arg_add_int(argspec, 'v', STR_ARGS_VOICES, 2, 192, &voices); arg_add_str(argspec, 'd', STR_ARGS_DEVICE, &device); arg_add_int(argspec, 'b', STR_ARGS_BUFFER, 0, 1048576, &bufsize); arg_add_int(argspec, 'f', STR_ARGS_FRAMES, 2, 8192, &fsize); arg_add_int(argspec, 'e', STR_ARGS_VELO, -128, 127, &velo); arg_add_bool(argspec, 'w', STR_ARGS_WIDEFT, &widefmt); arg_add_bool(argspec, 'k', STR_ARGS_KEEPV, &keep); arg_add_bool(argspec, 'u', STR_ARGS_USEUNK, &useunkn); arg_add_bool(argspec, 'n', STR_ARGS_DONTWT, &nowait); arg_add_str(argspec, 'p', STR_ARGS_BANK, &dmxname); arg_add_str(argspec, 'q', STR_ARGS_DBANK, &drumname); arg_add_bool(argspec, 'D', STR_ARGS_MDEBUG, &log_debug); if(arg_parse(argspec, argc, argv) ^ 1) { return 1; } if((voices & 1) != 0) { fprintf(stderr, STR_PLR_UNEVEN"\n"); free(midnames); return 1; } bool state = plr_playloop(samplerate, voices, midnames, midis, dmxname, drumname, device, fsize, bufsize, widefmt, keep, useunkn ^ 1, velo, nowait); free(midnames); return state ? 0 : 2; }