oplplayer/oplplayer.c
2025-03-20 11:02:57 +01:00

966 lines
No EOL
22 KiB
C

#include <stdlib.h>
#include <stdio.h>
#include <math.h>
#include <string.h>
#include <stdint.h>
#include <stdbool.h>
#include <stdarg.h>
#include <errno.h>
#include <signal.h>
#include <termios.h>
#include <unistd.h>
#include <ncurses.h>
#define ALSA_PCM_NEW_HW_PARAMS_API
#include <alsa/asoundlib.h>
#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;
}