1 /* Extended Module Player
2 * Copyright (C) 1996-2016 Claudio Matsuoka and Hipolito Carraro Jr
3 *
4 * This file is part of the Extended Module Player and is distributed
5 * under the terms of the GNU General Public License. See the COPYING
6 * file for more information.
7 */
8
9 #include <stdio.h>
10 #include <string.h>
11 #include <stdarg.h>
12 #include <xmp.h>
13 #include "common.h"
14
15 static int max_channels = -1;
16
info_help(void)17 void info_help(void)
18 {
19 report(
20 "COMMAND KEYS SUMMARY\n"
21 " Space Pause/unpause\n"
22 " q, Esc Stop module and quit the player\n"
23 " f, Right Advance to next order\n"
24 " b, Left Return to previous order\n"
25 " n, Up Advance to next module\n"
26 " p, Down Return to previous module\n"
27 " h, ? Display available commands\n"
28 " 1 - 0 Mute/unmute channels\n"
29 " ! Unmute all channels\n"
30 " X Display current mixer type\n"
31 " a Enable amiga mixer\n"
32 " Z Display current sequence\n"
33 " z Toggle subsong explorer mode\n"
34 " l Toggle loop mode\n"
35 " m Display module information\n"
36 " i Display combined instrument/sample list\n"
37 " I Display instrument list\n"
38 " S Display sample list\n"
39 " c Display comment, if any\n"
40 " < Play previous sequence\n"
41 " > Play next sequence\n"
42 );
43 }
44
info_mod(struct xmp_module_info * mi,int mode)45 void info_mod(struct xmp_module_info *mi, int mode)
46 {
47 int i;
48 int num_seq;
49 int total_time;
50
51 report("Module name : %s\n", mi->mod->name);
52 report("Module type : %s", mi->mod->type);
53
54 if (mode != XMP_MODE_AUTO) {
55 struct player_mode *pm;
56 for (pm = pmode; pm->name != NULL; pm++) {
57 if (pm->mode == mode) {
58 report(" [play as:%s]", pm->desc);
59 break;
60 }
61 }
62 }
63
64 report("\nModule length: %d patterns\n", mi->mod->len);
65 report("Patterns : %d\n", mi->mod->pat);
66 report("Instruments : %d\n", mi->mod->ins);
67 report("Samples : %d\n", mi->mod->smp);
68 report("Channels : %d [ ", mi->mod->chn);
69
70 for (i = 0; i < mi->mod->chn; i++) {
71 if (mi->mod->xxc[i].flg & XMP_CHANNEL_SYNTH) {
72 report("S ");
73 } else if (mi->mod->xxc[i].flg & XMP_CHANNEL_MUTE) {
74 report("- ");
75 } else if (mi->mod->xxc[i].flg & XMP_CHANNEL_SURROUND) {
76 report("^ ");
77 } else {
78 report("%x ", mi->mod->xxc[i].pan >> 4);
79 }
80 }
81 report("]\n");
82
83 total_time = mi->seq_data[0].duration;
84
85 report("Duration : %dmin%02ds", (total_time + 500) / 60000,
86 ((total_time + 500) / 1000) % 60);
87
88 /* Check non-zero-length sequences */
89 num_seq = 0;
90 for (i = 0; i < mi->num_sequences; i++) {
91 if (mi->seq_data[i].duration > 0)
92 num_seq++;
93 }
94
95 if (num_seq > 1) {
96 report(" (main sequence)\n");
97 for (i = 1; i < mi->num_sequences; i++) {
98 int dur = mi->seq_data[i].duration;
99
100 if (dur == 0) {
101 continue;
102 }
103
104 report(" %dmin%02ds "
105 "(sequence %d at position %02X)\n",
106 (dur + 500) / 60000, ((dur + 500) / 1000) % 60,
107 i, mi->seq_data[i].entry_point);
108 }
109 } else {
110 report("\n");
111 }
112 }
113
info_frame_init(void)114 void info_frame_init(void)
115 {
116 max_channels = 0;
117 }
118
119 #define MSG_SIZE 80
120 static int msg_timer = 0;
121 static char msg_text[MSG_SIZE];
122
info_message(char * format,...)123 void info_message(char *format, ...)
124 {
125 va_list ap;
126
127 va_start(ap, format);
128 msg_timer = 300000;
129 vsnprintf(msg_text, MSG_SIZE, format, ap);
130 va_end(ap);
131 }
132
fix_info_02x(int val,char * buf)133 static void fix_info_02x(int val, char *buf)
134 {
135 if (val <= 0xff) {
136 snprintf(buf, 3, "%02X", val);
137 } else if (val <= 0xfff) {
138 snprintf(buf, 3, "+%X", val >> 8);
139 } else {
140 strcpy(buf, "++");
141 }
142 }
143
info_frame(struct xmp_module_info * mi,struct xmp_frame_info * fi,struct control * ctl,int reprint)144 void info_frame(struct xmp_module_info *mi, struct xmp_frame_info *fi, struct control *ctl, int reprint)
145 {
146 static int ord = -1, spd = -1, bpm = -1;
147 char rowstr[3], numrowstr[3];
148 char chnstr[3], maxchnstr[3];
149 int time;
150 char x;
151
152 if (fi->virt_used > max_channels)
153 max_channels = fi->virt_used;
154
155 if (!reprint && fi->frame != 0)
156 return;
157
158 time = fi->time / 100;
159
160 /* Show mixer type */
161 x = ' ';
162 if (ctl->amiga) {
163 switch (ctl->mixer_type) {
164 case XMP_MIXER_STANDARD:
165 x = '-';
166 break;
167 case XMP_MIXER_A500:
168 x = 'A';
169 break;
170 case XMP_MIXER_A500F:
171 x = 'F';
172 break;
173 default:
174 x = 'x';
175 }
176 }
177
178 if (msg_timer > 0) {
179 report("\r%-61.61s %c%c%c", msg_text,
180 ctl->explore ? 'Z' : ' ',
181 ctl->loop ? 'L' : ' ', x);
182 msg_timer -= fi->frame_time * fi->speed / 6;
183 if (msg_timer == 0) {
184 msg_timer--;
185 } else {
186 goto print_time;
187 }
188 }
189
190 if (msg_timer < 0) {
191 reprint = 1;
192 msg_timer = 0;
193 }
194
195 if (reprint || fi->pos != ord || fi->bpm != bpm || fi->speed != spd) {
196 report("\rSpeed[%02X] BPM[%02X] Pos[%02X/%02X] "
197 "Pat[%02X/%02X] Row[ / ] Chn[ / ] 0:00:00.0",
198 fi->speed, fi->bpm,
199 fi->pos, mi->mod->len - 1,
200 fi->pattern, mi->mod->pat - 1);
201 ord = fi->pos;
202 bpm = fi->bpm;
203 spd = fi->speed;
204 }
205
206 fix_info_02x(fi->row, rowstr);
207 fix_info_02x(fi->num_rows - 1, numrowstr);
208 fix_info_02x(fi->virt_used, chnstr);
209 fix_info_02x(max_channels, maxchnstr);
210
211 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"
212 "%2.2s/%2.2s] Chn[%2.2s/%2.2s] %c%c%c",
213 rowstr, numrowstr, chnstr, maxchnstr,
214 ctl->explore ? 'Z' : ' ', ctl->loop ? 'L' : ' ', x);
215
216 print_time:
217
218 if (ctl->pause) {
219 report(" - PAUSED -");
220 } else {
221 report("%3d:%02d:%02d.%d",
222 (int)(time / (60 * 600)), (int)((time / 600) % 60),
223 (int)((time / 10) % 60), (int)(time % 10));
224 }
225
226 fflush(stdout);
227 }
228
info_ins_smp(struct xmp_module_info * mi)229 void info_ins_smp(struct xmp_module_info *mi)
230 {
231 int i, j;
232 struct xmp_module *mod = mi->mod;
233
234 report("Instruments and samples:\n");
235 report(" Instrument name Smp Size Loop End Vol Fine Xpo Pan\n");
236 for (i = 0; i < mod->ins; i++) {
237 struct xmp_instrument *ins = &mod->xxi[i];
238
239 if (strlen(ins->name) == 0 && ins->nsm == 0) {
240 continue;
241 }
242
243 report("%02x %-32.32s ", i + 1, ins->name);
244
245 for (j = 0; j < ins->nsm; j++) {
246 struct xmp_subinstrument *sub = &ins->sub[j];
247 struct xmp_sample *smp = &mod->xxs[sub->sid];
248
249 if (j > 0) {
250 if (smp->len == 0) {
251 continue;
252 }
253 report("%36.36s", " ");
254 }
255
256 report("[%02x] %05x%c%05x %05x%c V%02x %+04d %+03d P%02x\n",
257 sub->sid + 1,
258 smp->len,
259 smp->flg & XMP_SAMPLE_16BIT ? '+' : ' ',
260 smp->lps,
261 smp->lpe,
262 smp->flg & XMP_SAMPLE_LOOP ?
263 smp->flg & XMP_SAMPLE_LOOP_BIDIR ?
264 'B' : 'L' : ' ',
265 sub->vol,
266 sub->fin,
267 sub->xpo,
268 sub->pan & 0xff);
269 }
270
271 if (j == 0) {
272 report("[ ] ----- ----- ----- --- ---- --- ---\n");
273 }
274
275 }
276 }
277
info_instruments(struct xmp_module_info * mi)278 void info_instruments(struct xmp_module_info *mi)
279 {
280 int i, j;
281 struct xmp_module *mod = mi->mod;
282
283 report("Instruments:\n");
284 report(" Instrument name Vl Fade Env Ns Sub Gv Vl Fine Xpo Pan Sm\n");
285 for (i = 0; i < mod->ins; i++) {
286 struct xmp_instrument *ins = &mod->xxi[i];
287
288 if (strlen(ins->name) == 0 && ins->nsm == 0) {
289 continue;
290 }
291
292 report("%02x %-32.32s %02x %04x %c%c%c %02x ",
293 i + 1, ins->name, ins->vol, ins->rls,
294 ins->aei.flg & XMP_ENVELOPE_ON ? 'A' : '-',
295 ins->fei.flg & XMP_ENVELOPE_ON ? 'F' : '-',
296 ins->pei.flg & XMP_ENVELOPE_ON ? 'P' : '-',
297 ins->nsm
298 );
299
300 for (j = 0; j < ins->nsm; j++) {
301 struct xmp_subinstrument *sub = &ins->sub[j];
302 struct xmp_sample *smp = &mod->xxs[sub->sid];
303
304 if (j > 0) {
305 if (smp->len == 0) {
306 continue;
307 }
308 report("%51.51s", " ");
309 }
310
311 report("[%02x] %02x %02x %+04d %+03d P%02x %02x\n",
312 j + 1,
313 sub->gvl,
314 sub->vol,
315 sub->fin,
316 sub->xpo,
317 sub->pan & 0xff,
318 sub->sid);
319 }
320
321 if (j == 0) {
322 report("[ ] -- -- ---- --- --- --\n");
323 }
324
325 }
326 }
327
info_samples(struct xmp_module_info * mi)328 void info_samples(struct xmp_module_info *mi)
329 {
330 int i;
331 struct xmp_module *mod = mi->mod;
332
333 report("Samples:\n");
334 report(" Sample name Length Start End Flags\n");
335 for (i = 0; i < mod->smp; i++) {
336 struct xmp_sample *smp = &mod->xxs[i];
337
338 if (strlen(smp->name) == 0 && smp->len == 0) {
339 continue;
340 }
341
342 report("%02x %-32.32s %06x %06x %06x %s %s %s\n",
343 i + 1, smp->name,
344 smp->len,
345 smp->lps,
346 smp->lpe,
347 smp->flg & XMP_SAMPLE_16BIT ? "16" : "--",
348 smp->flg & XMP_SAMPLE_LOOP ? "L" : "-",
349 smp->flg & XMP_SAMPLE_LOOP_BIDIR ? "B" : "-");
350 }
351 }
352
info_comment(struct xmp_module_info * mi)353 void info_comment(struct xmp_module_info *mi)
354 {
355 char *c = mi->comment;
356
357 if (mi->comment == NULL) {
358 report("No comment.\n");
359 return;
360 }
361
362 while (*c != 0) {
363 report("> ");
364 do {
365 if (*c == 0)
366 break;
367 report("%c", *c);
368 } while (*c++ != '\n');
369 }
370 report("\n\n");
371 }
372
373