1 /* $Id: main.c,v 1.9 2006/09/16 10:36:23 toad32767 Exp $ */
2 /**
3  ** 2005, 2006 by Marco Trillo
4  ** This file is part of UModPlayer, and is released by
5  ** its autors to the Public Domain.
6  ** In case it's not legally possible, its autors grant
7  ** anyone the right to use, redistribute and modify
8  ** this software for any purpose, without any conditions,
9  ** unless such conditions are required by law.
10  **
11  ** THIS FILE COMES WITHOUT ANY WARRANTY. THE AUTHORS
12  ** SHALL NOT BE LIABLE FOR ANY DAMAGE RESULTING BY THE
13  ** USE OR MISUSE OF THIS SOFTWARE.
14  **/
15 
16 #include <umodplayer.h>
17 #include <options.h>
18 #include <coresound.h>
19 #include <ipret.h>
20 #include <file_write.h>
21 #include <file_read.h>
22 #include <file_parse.h>
23 #include <text.h>
24 
25 #include <signal.h>
26 
27 /* global variables */
28 EXPORT struct file file = {FALSE, NULL, NULL}; /* the module file loaded */
29 EXPORT struct oFlags sets; /* settings (configuration) */
30 EXPORT char **rr = NULL; /* text to be printed out by the table callback */
31 EXPORT int startpos = 0; /* start position for exportings */
32 EXPORT int endpos = -1; /* end position for exportings */
33 EXPORT int CoreSound_BitsPerSample = 0; /* bits per sample */
34 EXPORT char *AudioDriver = NULL; /* audio driver */
35 EXPORT Bool AudioActive = FALSE; /* audio active */
36 EXPORT ao_device *AO_Device = NULL; /* device for LibAo */
37 
38 /*
39  * Catch the SIGINT & SIGTERM signals
40  */
41 void
CatchSignal(int sig)42 CatchSignal(int sig)
43 {
44 	if (AudioActive == TRUE)
45 		CoreSound_Quit();
46 	if (file.name != NULL)
47 		UFreeFile();
48 
49 	notice("\n[exiting by signal %d]\n", sig);
50 	exit(UM_OK);
51 }
52 
53 /*
54  * Print the version banner
55  */
56 EXPORT void
PrintBanner()57 PrintBanner()
58 {
59 	puts(UMODPLAYER_VERSION);
60 	puts(COMPILATION_DATE);
61 }
62 
63 /*
64  * Display the program usage
65  */
66 LOCAL void
DisplayUsage(char * progname)67 DisplayUsage(char *progname)
68 {
69 	fprintf(stderr, "Usage: %s [<module file>] [<options>]\n\n"
70 	    "Options\n"
71 	    "-V : print the UModPlayer version and exit.\n"
72 	    "-i : Interactive mode (this is the default mode\n"
73 	    "     when no module file is given on command line.\n"
74 	    "-q : Quiet; Do not print the status bar.\n"
75 	    "-a <pos> : Start playback/export at order position <pos>.\n"
76 	    "-z <pos> : End playback/export at order position <pos>.\n"
77 	    "-o <output file> : Export loaded module to <output file>.\n"
78 	    "-f <output format> : Select a format to export loaded module.\n"
79 	    "                     Available formats:\n"
80 	    "                     it, wav, aiff, s16se, s16le, s16be\n", progname);
81 	fprintf(stderr, "-d : Use the default config scheme.\n"
82 	    "-w : Save the current config scheme.\n"
83 	    "-m <output file> : Export module text message to <output file>.\n"
84 	    "-s <output file> : Export module samplenames to <output file>.\n"
85 	    "-I <output file> : Export module instrumentnames to <output file>.\n");
86 	fprintf(stderr, "Audio options:\n"
87 	    "-v <level> : Volume level (1-512)\n"
88 	    "-c <channels> : N. of channels. Possible values\n"
89 	    "                1 = mono ; 2 = stereo\n"
90 	    "-O <driver> : audio driver\n"
91 	    "              alsa09, alsa, oss, sun, macosx, arts, irix, esd, null\n"
92 	    "-r <rate> : Sampling rate in Hz. Available values:\n"
93 	    "            11025, 16000, 22050, 24000, 32000, 44100\n"
94 	    "-M <mode> : Resampling mode. Available modes:\n"
95 	    "            NO_INTERPOLATE, LINEAR, SPLINE, FIR_FILTER\n"
96 	    "+N,+R,+B,+S : Enable Noise Reduction, reverb, megabass\n"
97 	    "              & surround.\n"
98 	    "-N,-R,-B,-S : Disable Noise Reduction, reverb, megabass\n"
99 	    "              & surround.\n");
100 	return;
101 }
102 
103 /*
104  * A bogus monitor function for `no-status' mode.
105  */
106 void
QuietPlay()107 QuietPlay()
108 {
109 	/* only interrupted when finished or killed by a signal */
110 	for (;;) {
111 		CoreSound_InjectPCM();
112 
113 		if (AudioActive == FALSE) {
114 			CoreSound_Quit();
115 			return;
116 		}
117 	}
118 }
119 
120 
121 
122 /*
123  * umodplayer -- module player
124  */
125 EXPORT int
main(int argc,char ** argv)126 main(int argc, char **argv)
127 {
128 	int i;
129 	int interactive = 0, status = 1, saveSettings = 0;
130 	char *ofile = NULL;
131 	int ofmt = 0, obps = 16;
132 	char *txt_ofile = NULL;
133 	char *spl_ofile = NULL;
134 	char *ins_ofile = NULL;
135 
136 	if (argc == 2 && (strcmp("--help", argv[1]) == 0 || strcmp("-h", argv[1]) == 0)) {
137 		DisplayUsage(argv[0]);
138 		exit(UM_OK);
139 	}
140 
141 	InitOptions(&sets);
142 
143 	/*
144 	 * Parse the command line options
145 	 */
146 	for (i = 1; i < argc; ++i) {
147 		char *p = argv[i], *h;
148 
149 		/*
150 		 * (-)
151 		 */
152 		if (*p == '-') {
153 			switch (*(++p)) {
154 			case 'i':
155 				interactive = 1;
156 				break;
157 			case 'a':
158 				i++;
159 				if (argc <= i)
160 					break;
161 				startpos = atoi(argv[i]);
162 				if (startpos < 0)
163 					startpos = 0;
164 				break;
165 			case 'z':
166 				i++;
167 				if (argc <= i)
168 					break;
169 				endpos = atoi(argv[i]);
170 				if (endpos <= startpos)
171 					endpos = -1;
172 				break;
173 			case 'o':
174 				i++;
175 				if (argc <= i)
176 					break;
177 				ofile = argv[i];
178 				h = strrchr(ofile, '.');
179 				if (!h)
180 					break;
181 				if (strcasecmp(h, ".it") == 0)
182 					ofmt = EXPORT_TYPE_IT;
183 				else if (strcasecmp(h, ".wav") == 0)
184 					ofmt = EXPORT_TYPE_WAV;
185 				else if (strcasecmp(h, ".aiff") == 0
186 				    || strcasecmp(h, ".aif") == 0) {
187 					obps = 16;
188 					ofmt = EXPORT_TYPE_AIFF;
189 				} else if (strcasecmp(h, ".pcm") == 0)
190 					ofmt = EXPORT_TYPE_PCM | EXPORT_SYS_ENDIAN;
191 				else if (strcasecmp(h, ".raw") == 0)
192 					ofmt = EXPORT_TYPE_PCM | EXPORT_LTE_ENDIAN;
193 				else
194 					ofmt = 0;
195 				break;
196 			case 'f':
197 				i++;
198 				if (argc <= i)
199 					break;
200 				h = argv[i];
201 				if (strcmp(h, "it") == 0)
202 					ofmt = EXPORT_TYPE_IT;
203 				else if (strcmp(h, "wav") == 0)
204 					ofmt = EXPORT_TYPE_WAV;
205 				else if (strcmp(h, "aiff16") == 0) {
206 					ofmt = EXPORT_TYPE_AIFF;
207 					obps = 16;
208 				} else if (strcmp(h, "aiff24") == 0) {
209 					ofmt = EXPORT_TYPE_AIFF;
210 					obps = 24;
211 				} else if (strcmp(h, "s16se") == 0)
212 					ofmt = EXPORT_TYPE_PCM | EXPORT_SYS_ENDIAN;
213 				else if (strcmp(h, "s16le") == 0)
214 					ofmt = EXPORT_TYPE_PCM | EXPORT_LTE_ENDIAN;
215 				else if (strcmp(h, "s16be") == 0)
216 					ofmt = EXPORT_TYPE_PCM | EXPORT_BIG_ENDIAN;
217 				else
218 					fprintf(stderr, "Invalid format -- %s\n", h);
219 				break;
220 			case 'd':
221 				DefaultOptions(&sets);
222 				break;
223 			case 'w':
224 				saveSettings = 1;
225 				break;
226 			case 'm':
227 				++i;
228 				if (argc <= i)
229 					break;
230 				txt_ofile = argv[i];
231 				break;
232 			case 's':
233 				++i;
234 				if (argc <= i)
235 					break;
236 				spl_ofile = argv[i];
237 				break;
238 			case 'I':
239 				++i;
240 				if (argc <= i)
241 					break;
242 				ins_ofile = argv[i];
243 				break;
244 			case 'v':
245 				++i;
246 				if (argc <= i)
247 					break;
248 				sets.vol = (unsigned int) atol(argv[i]);
249 				if (sets.vol > 768) /* XXX - not really sure about the Modplug limit */
250 					sets.vol = 768;
251 				if (sets.vol < 1)
252 					sets.vol = 1;
253 				break;
254 			case 'c':
255 				++i;
256 				if (argc <= i)
257 					break;
258 				sets.channels = atoi(argv[i]);
259 				if (sets.channels < 1)
260 					sets.channels = 1;
261 				if (sets.channels > 2)
262 					sets.channels = 2;
263 				break;
264 			case 'r':
265 				++i;
266 				if (argc <= i)
267 					break;
268 				sets.samplerate = atoi(argv[i]);
269 				switch (sets.samplerate) {
270 				case 11025:
271 				case 16000:
272 				case 22050:
273 				case 24000:
274 				case 32000:
275 				case 44100:
276 					break;
277 				default:
278 					sets.samplerate = 44100;
279 				}
280 				break;
281 			case 'M':
282 				++i;
283 				if (argc <= i)
284 					break;
285 				h = argv[i];
286 				if (strcmp(h, "NO_INTERPOLATE") == 0 ||
287 					strcmp(h, "RESAMPLE") == 0) /* deprecated, compat. only */
288 					sets.resampling = 0;
289 				else if (strcmp(h, "LINEAR") == 0)
290 					sets.resampling = 1;
291 				else if (strcmp(h, "SPLINE") == 0)
292 					sets.resampling = 2;
293 				else if (strcmp(h, "FIR_FILTER") == 0)
294 					sets.resampling = 3;
295 				break;
296 			case 'O':
297 				++i;
298 				if (argc <= i)
299 					break;
300 				AudioDriver = argv[i];
301 				break;
302 			case 'q':
303 				status = 0;
304 				--(sets.verbosity);
305 				break;
306 			case 'V':
307 				PrintBanner();
308 				if (file.name != NULL)
309 					UFreeFile();
310 				exit(UM_OK);
311 				break; /* NOTREACHED */
312 
313 			/* Disable options */
314 			case 'N':
315 				sets.flags &= (~MODPLUG_ENABLE_NOISE_REDUCTION);
316 				break;
317 			case 'R':
318 				sets.flags &= (~MODPLUG_ENABLE_REVERB);
319 				break;
320 			case 'B':
321 				sets.flags &= (~MODPLUG_ENABLE_MEGABASS);
322 				break;
323 			case 'S':
324 				sets.flags &= (~MODPLUG_ENABLE_SURROUND);
325 				break;
326 			}
327 
328 		/*
329 		 * (+)
330 		 */
331 		} else if (*p == '+') {
332 			switch (*(++p)) {
333 				/* Enable options */
334 			case 'N':
335 				sets.flags |= MODPLUG_ENABLE_NOISE_REDUCTION;
336 				break;
337 			case 'R':
338 				sets.flags |= MODPLUG_ENABLE_REVERB;
339 				break;
340 			case 'B':
341 				sets.flags |= MODPLUG_ENABLE_MEGABASS;
342 				break;
343 			case 'S':
344 				sets.flags |= MODPLUG_ENABLE_SURROUND;
345 				break;
346 			}
347 		} else {
348 			file.name = argv[i];
349 			file.malloc = FALSE;
350 		}
351 	}
352 
353 	if (file.name == NULL)
354 		interactive = 1;
355 
356 	/* print version banner? */
357 	if (status > 0 && sets.verbosity > 0) {
358 		PrintBanner();
359 	}
360 
361 	/* save settings? */
362 	if (saveSettings == 1) {
363 		SaveOptions(&sets);
364 	}
365 
366 	/* load a file? */
367 	if (file.name != NULL) {
368 		ULoadFile();
369 	}
370 
371 	/* export the loaded file? */
372 	if (!interactive && file.name != NULL && ofile != NULL) {
373 		int ret;
374 
375 		if (ofmt == 0) {
376 			error("CAN'T guess format of <%s>\n", ofile);
377 			exit(UM_ERR_INVAL);
378 		}
379 
380 		switch (ofmt) {
381 		case EXPORT_TYPE_IT:
382 #ifdef MODPLUG_CAN_SAVE
383 			ret = ModPlug_ExportIT(file.mod, ofile);
384 #else
385 			error("ModPlug compiled without 'save' support\n", stderr);
386 			ret = 0;
387 #endif
388 			break;
389 		case EXPORT_TYPE_WAV:
390 			ret = ((long) WriteWAV(ofile) > 0L);
391 			break;
392 		case EXPORT_TYPE_AIFF:
393 			ret = (int) WriteAIFF(ofile, obps);
394 			break;
395 		case EXPORT_TYPE_PCM:
396 			ret = ((long) WritePCM(ofile, ofmt) > 0L);
397 			break;
398 		default:
399 			ret = 0;
400 		}
401 
402 		UFreeFile();
403 
404 		if (!ret) {
405 			error("export failed!\n");
406 			exit(UM_ERR_INVAL);
407 		} else {
408 			exit(UM_OK);
409 		}
410 	}
411 
412 	/* save misc. stuff */
413 	if (!interactive && file.name && txt_ofile)
414 		SaveSongComments(txt_ofile);
415 
416 	if (!interactive && file.name && spl_ofile) {
417 		int fd;
418 
419 		fd = open(spl_ofile, O_WRONLY | O_TRUNC | O_CREAT, 0644);
420 		if (fd < 0) {
421 			error("file creation error.\n");
422 		} else {
423 			DisplaySamples(fd);
424 			close(fd);
425 		}
426 	}
427 	if (!interactive && file.name && ins_ofile) {
428 		int fd;
429 
430 		fd = open(ins_ofile, O_WRONLY | O_TRUNC | O_CREAT, 0644);
431 		if (fd < 0) {
432 			error("file creation error.\n");
433 		} else {
434 			DisplayInstruments(fd);
435 			close(fd);
436 		}
437 	}
438 	if (!interactive && file.name && (ofile || txt_ofile || spl_ofile || ins_ofile)) {
439 		UFreeFile();
440 		exit(UM_OK);
441 	}
442 
443 	/* catch the SIGINT and SIGTERM signals */
444 	signal(SIGINT, CatchSignal);
445 	signal(SIGTERM, CatchSignal);
446 
447 	if (!interactive) {
448 		if (file.name == NULL) {
449 			error("file load: %s\n", strerror(errno));
450 			exit(UM_ERR_IO);
451 		}
452 		if (status > 0) {
453 			DrawInfoTable();
454 			CoreSound_StartMonitor();
455 		} else {
456 			CoreSound_Start(QuietPlay);
457 		}
458 
459 		UFreeFile();
460 		exit(UM_OK);
461 	} else {
462 		/*
463 		 * Launch the command interpreter
464 		 */
465 		notice("Launching the command interpreter...\n");
466 		notice("Type 'help' and <ENTER> to get a list of available commands.\n");
467 		notice("Configure the advanced features with the 'setadvanced' command.\n");
468 		CommandInterpreter();
469 		UFreeFile();
470 		exit(UM_OK);
471 	}
472 
473 	/* NOTREACHED */
474 	return UM_OK;
475 }
476 
477 
478