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