You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

387 lines
8.7 KiB

/* Extended Module Player
* Copyright (C) 1996-2016 Claudio Matsuoka and Hipolito Carraro Jr
*
* This file is part of the Extended Module Player and is distributed
* under the terms of the GNU General Public License. See the COPYING
* file for more information.
*/
#include <stdio.h>
#include <string.h>
#include <stdarg.h>
#include "common.h"
static int max_channels = -1;
void info_help(void)
{
report(
"COMMAND KEYS SUMMARY\n"
" Space Pause/unpause\n"
" q, Esc Stop module and quit the player\n"
" f, Right Advance to next order\n"
" b, Left Return to previous order\n"
" n, Up Advance to next module\n"
" p, Down Return to previous module\n"
" h, ? Display available commands\n"
" 1 - 0 Mute/unmute channels\n"
" ! Unmute all channels\n"
" X Display current mixer type\n"
" a Enable amiga mixer\n"
" Z Display current sequence\n"
" z Toggle subsong explorer mode\n"
" l Toggle loop mode\n"
" m Display module information\n"
" i Display combined instrument/sample list\n"
" I Display instrument list\n"
" S Display sample list\n"
" c Display comment, if any\n"
" < Play previous sequence\n"
" > Play next sequence\n"
);
}
void info_mod(const struct xmp_module_info *mi, int mode)
{
int i;
int num_seq;
int total_time;
report("Module name : %s\n", mi->mod->name);
report("Module type : %s", mi->mod->type);
if (mode != XMP_MODE_AUTO) {
struct player_mode *pm;
for (pm = pmode; pm->name != NULL; pm++) {
if (pm->mode == mode) {
report(" [play as:%s]", pm->desc);
break;
}
}
}
report("\nModule length: %d patterns\n", mi->mod->len);
report("Patterns : %d\n", mi->mod->pat);
report("Instruments : %d\n", mi->mod->ins);
report("Samples : %d\n", mi->mod->smp);
report("Channels : %d [ ", mi->mod->chn);
for (i = 0; i < mi->mod->chn; i++) {
if (mi->mod->xxc[i].flg & XMP_CHANNEL_SYNTH) {
report("S ");
} else if (mi->mod->xxc[i].flg & XMP_CHANNEL_MUTE) {
report("- ");
} else if (mi->mod->xxc[i].flg & XMP_CHANNEL_SURROUND) {
report("^ ");
} else {
report("%x ", mi->mod->xxc[i].pan >> 4);
}
}
report("]\n");
total_time = mi->seq_data[0].duration;
report("Duration : %dmin%02ds", (total_time + 500) / 60000,
((total_time + 500) / 1000) % 60);
/* Check non-zero-length sequences */
num_seq = 0;
for (i = 0; i < mi->num_sequences; i++) {
if (mi->seq_data[i].duration > 0)
num_seq++;
}
if (num_seq > 1) {
report(" (main sequence)\n");
for (i = 1; i < mi->num_sequences; i++) {
int dur = mi->seq_data[i].duration;
if (dur == 0) {
continue;
}
report(" %dmin%02ds "
"(sequence %d at position %02X)\n",
(dur + 500) / 60000, ((dur + 500) / 1000) % 60,
i, mi->seq_data[i].entry_point);
}
} else {
report("\n");
}
}
void info_frame_init(void)
{
max_channels = 0;
}
#define MSG_SIZE 80
static int msg_timer = 0;
static char msg_text[MSG_SIZE];
void info_message(const char *format, ...)
{
va_list ap;
va_start(ap, format);
msg_timer = 300000;
vsnprintf(msg_text, MSG_SIZE, format, ap);
va_end(ap);
}
static void fix_info_02x(int val, char *buf)
{
if (val <= 0xff) {
snprintf(buf, 3, "%02X", val);
} else if (val <= 0xfff) {
snprintf(buf, 3, "+%X", val >> 8);
} else {
strcpy(buf, "++");
}
}
void info_frame(const struct xmp_module_info *mi, const struct xmp_frame_info *fi, struct control *ctl, int reprint)
{
static int ord = -1, spd = -1, bpm = -1;
char rowstr[3], numrowstr[3];
char chnstr[3], maxchnstr[3];
int time;
char x;
if (fi->virt_used > max_channels)
max_channels = fi->virt_used;
if (!reprint && fi->frame != 0)
return;
time = fi->time / 100;
/* Show mixer type */
x = ' ';
if (ctl->amiga_mixer) {
switch (ctl->mixer_type) {
case XMP_MIXER_STANDARD:
x = '-';
break;
case XMP_MIXER_A500:
x = 'A';
break;
case XMP_MIXER_A500F:
x = 'F';
break;
default:
x = 'x';
}
}
if (msg_timer > 0) {
report("\r%-61.61s %c%c%c", msg_text,
ctl->explore ? 'Z' : ' ',
ctl->loop ? 'L' : ' ', x);
msg_timer -= fi->frame_time * fi->speed / 6;
if (msg_timer == 0) {
msg_timer--;
} else {
goto print_time;
}
}
if (msg_timer < 0) {
reprint = 1;
msg_timer = 0;
}
if (reprint || fi->pos != ord || fi->bpm != bpm || fi->speed != spd) {
report("\rSpeed[%02X] BPM[%02X] Pos[%02X/%02X] "
"Pat[%02X/%02X] Row[ / ] Chn[ / ] 0:00:00.0",
fi->speed, fi->bpm,
fi->pos, mi->mod->len - 1,
fi->pattern, mi->mod->pat - 1);
ord = fi->pos;
bpm = fi->bpm;
spd = fi->speed;
}
fix_info_02x(fi->row, rowstr);
fix_info_02x(fi->num_rows - 1, numrowstr);
fix_info_02x(fi->virt_used, chnstr);
fix_info_02x(max_channels, maxchnstr);
report("\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b"
"%2.2s/%2.2s] Chn[%2.2s/%2.2s] %c%c%c",
rowstr, numrowstr, chnstr, maxchnstr,
ctl->explore ? 'Z' : ' ', ctl->loop ? 'L' : ' ', x);
print_time:
if (ctl->pause) {
report(" - PAUSED -");
} else {
report("%3d:%02d:%02d.%d",
(int)(time / (60 * 600)), (int)((time / 600) % 60),
(int)((time / 10) % 60), (int)(time % 10));
}
fflush(stdout);
}
void info_ins_smp(const struct xmp_module_info *mi)
{
int i, j;
const struct xmp_module *mod = mi->mod;
report("Instruments and samples:\n");
report(" Instrument name Smp Size Loop End Vol Fine Xpo Pan\n");
for (i = 0; i < mod->ins; i++) {
struct xmp_instrument *ins = &mod->xxi[i];
int has_sub = 0;
if (strlen(ins->name) == 0 && ins->nsm == 0) {
continue;
}
report("%02x %-32.32s ", i + 1, ins->name);
for (j = 0; j < ins->nsm; j++) {
const struct xmp_subinstrument *sub = &ins->sub[j];
const struct xmp_sample *smp;
/* Some instruments reference samples that don't exist
* (see beek-substitutionology.it). */
if (sub->sid >= mod->smp) {
continue;
}
smp = &mod->xxs[sub->sid];
if (j > 0) {
if (smp->len == 0) {
continue;
}
report("%36.36s", " ");
}
has_sub = 1;
report("[%02x] %05x%c%05x %05x%c V%02x %+04d %+03d P%02x\n",
sub->sid + 1,
smp->len,
smp->flg & XMP_SAMPLE_16BIT ? '+' : ' ',
smp->lps,
smp->lpe,
smp->flg & XMP_SAMPLE_LOOP ?
smp->flg & XMP_SAMPLE_LOOP_BIDIR ?
'B' : 'L' : ' ',
sub->vol,
sub->fin,
sub->xpo,
sub->pan & 0xff);
}
if (has_sub == 0) {
report("[ ] ----- ----- ----- --- ---- --- ---\n");
}
}
}
void info_instruments(const struct xmp_module_info *mi)
{
int i, j;
const struct xmp_module *mod = mi->mod;
report("Instruments:\n");
report(" Instrument name Vl Fade Env Ns Sub Gv Vl Fine Xpo Pan Sm\n");
for (i = 0; i < mod->ins; i++) {
const struct xmp_instrument *ins = &mod->xxi[i];
int has_sub = 0;
if (strlen(ins->name) == 0 && ins->nsm == 0) {
continue;
}
report("%02x %-32.32s %02x %04x %c%c%c %02x ",
i + 1, ins->name, ins->vol, ins->rls,
ins->aei.flg & XMP_ENVELOPE_ON ? 'A' : '-',
ins->fei.flg & XMP_ENVELOPE_ON ? 'F' : '-',
ins->pei.flg & XMP_ENVELOPE_ON ? 'P' : '-',
ins->nsm
);
for (j = 0; j < ins->nsm; j++) {
const struct xmp_subinstrument *sub = &ins->sub[j];
const struct xmp_sample *smp;
if (j > 0) {
/* Some instruments reference samples that don't exist
* (see beek-substitutionology.it). */
if (sub->sid >= mod->smp) {
continue;
}
smp = &mod->xxs[sub->sid];
if (smp->len == 0) {
continue;
}
report("%51.51s", " ");
}
has_sub = 1;
report("[%02x] %02x %02x %+04d %+03d P%02x %02x\n",
j + 1,
sub->gvl,
sub->vol,
sub->fin,
sub->xpo,
sub->pan & 0xff,
sub->sid);
}
if (has_sub == 0) {
report("[ ] -- -- ---- --- --- --\n");
}
}
}
void info_samples(const struct xmp_module_info *mi)
{
int i;
const struct xmp_module *mod = mi->mod;
report("Samples:\n");
report(" Sample name Length Start End Flags\n");
for (i = 0; i < mod->smp; i++) {
const struct xmp_sample *smp = &mod->xxs[i];
if (strlen(smp->name) == 0 && smp->len == 0) {
continue;
}
report("%02x %-32.32s %06x %06x %06x %s %s %s\n",
i + 1, smp->name,
smp->len,
smp->lps,
smp->lpe,
smp->flg & XMP_SAMPLE_16BIT ? "16" : "--",
smp->flg & XMP_SAMPLE_LOOP ? "L" : "-",
smp->flg & XMP_SAMPLE_LOOP_BIDIR ? "B" : "-");
}
}
void info_comment(const struct xmp_module_info *mi)
{
char *c = mi->comment;
if (mi->comment == NULL) {
report("No comment.\n");
return;
}
while (*c != 0) {
report("> ");
do {
if (*c == 0)
break;
report("%c", *c);
} while (*c++ != '\n');
}
report("\n\n");
}