966 lines
No EOL
22 KiB
C
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 = "banks/dmx_dmx.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;
|
|
} |