1 /*
2  * madplay - MPEG audio decoder and player
3  * Copyright (C) 2000-2004 Robert Leslie
4  *
5  * This program is free software; you can redistribute it and/or modify
6  * it under the terms of the GNU General Public License as published by
7  * the Free Software Foundation; either version 2 of the License, or
8  * (at your option) any later version.
9  *
10  * This program is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13  * GNU General Public License for more details.
14  *
15  * You should have received a copy of the GNU General Public License
16  * along with this program; if not, write to the Free Software
17  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
18  *
19  * $Id: madplay.c,v 1.86 2004/02/23 21:34:53 rob Exp $
20  */
21 
22 # ifdef HAVE_CONFIG_H
23 #  include "config.h"
24 # endif
25 
26 # include "global.h"
27 
28 /* include this first to avoid conflicts with MinGW __argc et al. */
29 # include "getopt.h"
30 
31 # include <locale.h>
32 # include <stdio.h>
33 # include <stdarg.h>
34 # include <stdlib.h>
35 # include <string.h>
36 
37 # ifdef HAVE_ASSERT_H
38 #  include <assert.h>
39 # endif
40 
41 # ifdef HAVE_UNISTD_H
42 #  include <unistd.h>
43 # endif
44 
45 # ifdef HAVE_FCNTL_H
46 #  include <fcntl.h>
47 # endif
48 
49 # include <ctype.h>
50 # include <mad.h>
51 
52 # include "gettext.h"
53 
54 # include "version.h"
55 # include "audio.h"
56 # include "player.h"
57 
58 # define FADE_DEFAULT	"0:05"
59 
60 # if defined(EXPERIMENTAL)
61 static int external_mix;
62 static int experimental;
63 # endif
64 
65 static
66 struct option const options[] = {
67   { "adjust-volume",	required_argument,	0,		 'A' },
68   { "amplify",		required_argument,	0,		 'a' },
69   { "ancillary-output",	required_argument,	0,		-'a' },
70   { "attenuate",	required_argument,	0,		 'a' },
71   { "bit-depth",	required_argument,	0,		 'b' },
72   { "display-time",	required_argument,	0,		-'t' },
73   { "downsample",	no_argument,		0,		-'d' },
74   { "fade-in",		optional_argument,	0,		-'i' },
75   { "help",		no_argument,		0,		 'h' },
76   { "ignore-crc",	no_argument,		0,		 'i' },
77   { "left",		no_argument,		0,		 '1' },
78   { "license",		no_argument,		0,		-'l' },
79   { "mono",		no_argument,		0,		 'm' },
80   { "no-dither",	no_argument,		0,		 'd' },
81   { "output",		required_argument,	0,		 'o' },
82   { "pre-amp",		required_argument,	0,		 'a' },
83   { "quiet",		no_argument,		0,		 'q' },
84   { "repeat",		optional_argument,	0,		 'r' },
85   { "replay-gain",	optional_argument,	0,		 'G' },
86   { "right",		no_argument,		0,		 '2' },
87   { "sample-rate",	required_argument,	0,		 'R' },
88   { "show-tags-only",	no_argument,		0,		 'T' },
89   { "shuffle",		no_argument,		0,		 'z' },
90   { "start",		required_argument,	0,		 's' },
91   { "stereo",		no_argument,		0,		 'S' },
92   { "time",		required_argument,	0,		 't' },
93   { "verbose",		no_argument,		0,		 'v' },
94   { "version",		no_argument,		0,		 'V' },
95   { "very-quiet",	no_argument,		0,		 'Q' },
96 # if defined(USE_TTY)
97   { "tty-control",	no_argument,		0,		-'c' },
98   { "no-tty-control",	no_argument,		0,		-'C' },
99 # endif
100 # if 0
101   { "cross-fade",	no_argument,		0,		 'x' },
102   { "fade-out",		optional_argument,	0,		-'o' },
103   { "gap",		required_argument,	0,		 'g' },
104 # endif
105 # if defined(EXPERIMENTAL)
106   { "external-mix",	no_argument,		&external_mix,	  1  },
107   { "experimental",	no_argument,		&experimental,	  1  },
108 # endif
109   { 0 }
110 };
111 
112 char const *argv0;
113 
114 # define EPUTS(str)	fputs(str, stream)
115 
116 /*
117  * NAME:	show_usage()
118  * DESCRIPTION:	display usage message
119  */
120 static
show_usage(int verbose)121 void show_usage(int verbose)
122 {
123   FILE *stream = verbose ? stdout : stderr;
124 
125   fprintf(stream, _("Usage: %s [OPTIONS] FILE [...]\n"), argv0);
126 
127   if (!verbose) {
128     fprintf(stream, _("Try `%s --help' for more information.\n"), argv0);
129     return;
130   }
131 
132   EPUTS(_("Decode and play MPEG audio FILE(s).\n"));
133 
134   /* the following usage text should agree with the option names */
135 
136   EPUTS(_("\nVerbosity:\n"));
137   EPUTS(_("  -v, --verbose                show status while decoding\n"));
138   EPUTS(_("  -q, --quiet                  be quiet but show warnings\n"));
139   EPUTS(_("  -Q, --very-quiet             "
140 	  "be quiet and do not show warnings\n"));
141   EPUTS(_("      --display-time=MODE      "
142 	  "use default verbose time display MODE\n"
143 	  "                                 (remaining, current, overall)\n"));
144 
145   EPUTS(_("\nDecoding:\n"));
146   EPUTS(_("      --downsample             reduce sample rate 2:1\n"));
147   EPUTS(_("  -i, --ignore-crc             ignore CRC errors\n"));
148   EPUTS(_("      --ancillary-output=PATH  write ancillary data to PATH\n"));
149 
150   EPUTS(_("\nAudio output:\n"));
151   EPUTS(_("  -o, --output=[TYPE:]PATH     "
152 	  "write output to PATH with format TYPE (below)\n"));
153   EPUTS(_("  -b, --bit-depth=DEPTH        request DEPTH bits per sample\n"));
154   EPUTS(_("  -R, --sample-rate=HERTZ      "
155 	  "request HERTZ samples per second\n"));
156   EPUTS(_("  -d, --no-dither              "
157 	  "do not dither output PCM samples\n"));
158   fprintf(stream,
159 	_("      --fade-in[=DURATION]     "
160 	  "fade-in songs over DURATION (default %s)\n"), FADE_DEFAULT);
161 # if 0
162   fprintf(stream,
163 	_("      --fade-out[=DURATION]    "
164 	  "fade-out songs over DURATION (default %s)\n"), FADE_DEFAULT);
165   EPUTS(_("  -g, --gap=DURATION           set inter-song gap to DURATION\n"));
166   EPUTS(_("  -x, --cross-fade             "
167 	  "cross-fade songs (use with negative gap)\n"));
168 # endif
169   EPUTS(_("  -a, --attenuate=DECIBELS     "
170 	  "attenuate signal by DECIBELS (-)\n"));
171   EPUTS(_("  -a, --amplify=DECIBELS       amplify signal by DECIBELS (+)\n"));
172   EPUTS(_("  -A, --adjust-volume=DECIBELS "
173 	  "override per-file volume adjustments\n"));
174   EPUTS(_("  -G, --replay-gain[=PROFILE]  "
175 	  "enable Replay Gain volume adjustments using\n"
176 	  "                                 PROFILE (radio, audiophile)\n"));
177 
178   EPUTS(_("\nChannel selection:\n"));
179   EPUTS(_("  -1, --left                   "
180 	  "output first (left) channel only\n"));
181   EPUTS(_("  -2, --right                  "
182 	  "output second (right) channel only\n"));
183   EPUTS(_("  -m, --mono                   "
184 	  "mix left and right channels for monaural output\n"));
185   EPUTS(_("  -S, --stereo                 force stereo output\n"));
186 
187 # if defined(EXPERIMENTAL)
188   EPUTS(_("\nExperimental:\n"));
189   EPUTS(_("      --external-mix           "
190 	  "output pre-synthesis samples for external mixer\n"));
191   EPUTS(_("      --experimental           enable experimental filter\n"));
192 # endif
193 
194   EPUTS(_("\nPlayback:\n"));
195   EPUTS(_("  -s, --start=TIME             "
196 	  "skip to begin at TIME (HH:MM:SS.DDD)\n"));
197   EPUTS(_("  -t, --time=DURATION          "
198 	  "play only for DURATION (HH:MM:SS.DDD)\n"));
199   EPUTS(_("  -z, --shuffle                randomize file list\n"));
200   EPUTS(_("  -r, --repeat[=MAX]           "
201 	  "play files MAX times, or indefinitely\n"));
202 # if defined(USE_TTY)
203   EPUTS(_("      --tty-control            enable keyboard controls\n"));
204   EPUTS(_("      --no-tty-control         disable keyboard controls\n"));
205 # endif
206 
207   EPUTS(_("\nMiscellaneous:\n"));
208   EPUTS(_("  -T, --show-tags-only         "
209 	  "show ID3/encoder tags only (do not decode)\n"));
210   EPUTS(_("  -V, --version                display version number and exit\n"));
211   EPUTS(_("      --license                "
212 	  "show copyright/license message and exit\n"));
213   EPUTS(_("  -h, --help                   display this help and exit\n"));
214 
215   EPUTS(_("\nSupported output formats:\n"));
216   EPUTS(_("  cdda    "
217 	  "CD audio, 16-bit big-endian 44100 Hz stereo PCM (*.cdr, *.cda)\n"));
218   EPUTS(_("  aiff    Audio IFF, [16-bit] PCM (*.aif, *.aiff)\n"));
219   EPUTS(_("  wave    Microsoft RIFF/WAVE, [16-bit] PCM (*.wav)\n"));
220   fprintf(stream,
221 	_("  snd     Sun/NeXT audio, 8-bit ISDN %s (*.au, *.snd)\n"),
222 	  _("mu-law"));
223   EPUTS(_("  raw     binary [16-bit] host-endian linear PCM\n"));
224   EPUTS(_("  hex     ASCII hexadecimal [24-bit] linear PCM\n"));
225 # if defined(HAVE_LIBESD)
226   EPUTS(_("  esd     "
227 	  "Enlightened Sound Daemon [16-bit] (give speaker host as PATH)\n"));
228 # endif
229 # if defined(HAVE_LIBAUDIO)
230   EPUTS(_("  nas     "
231 	  "Network Audio System [16-bit] (give server name as PATH)\n"));
232 # endif
233   EPUTS(_("  null    no output (decode only)\n"));
234 }
235 
236 # undef EPUTS
237 
238 /*
239  * NAME:	verror()
240  * DESCRIPTION:	print error message with program title prefix
241  */
242 static
verror(char const * message,va_list args)243 void verror(char const *message, va_list args)
244 {
245   fprintf(stderr, "%s: ", argv0);
246   vfprintf(stderr, message, args);
247   fputc('\n', stderr);
248 }
249 
250 /*
251  * NAME:	warn()
252  * DESCRIPTION:	print warning message
253  */
254 static
warn(char const * message,...)255 void warn(char const *message, ...)
256 {
257   va_list args;
258 
259   va_start(args, message);
260   verror(message, args);
261   va_end(args);
262 }
263 
264 /*
265  * NAME:	die()
266  * DESCRIPTION:	exit with failure status after printing message
267  */
268 static
die(char const * message,...)269 void die(char const *message, ...)
270 {
271   va_list args;
272 
273   va_start(args, message);
274   verror(message, args);
275   va_end(args);
276 
277   exit(1);
278 }
279 
280 /*
281  * NAME:	parse_time()
282  * DESCRIPTION:	parse a time specification string
283  */
284 static
parse_time(mad_timer_t * timer,char const * str)285 int parse_time(mad_timer_t *timer, char const *str)
286 {
287   mad_timer_t time, accum = mad_timer_zero;
288   signed long decimal;
289   unsigned long seconds, fraction, fracpart;
290   int minus;
291 
292   while (isspace((unsigned char) *str))
293     ++str;
294 
295   do {
296     seconds = fraction = fracpart = 0;
297 
298     switch (*str) {
299     case '-':
300       ++str;
301       minus = 1;
302       break;
303 
304     case '+':
305       ++str;
306     default:
307       minus = 0;
308     }
309 
310     do {
311       decimal = strtol(str, (char **) &str, 10);
312       if (decimal < 0)
313 	return -1;
314 
315       seconds += decimal;
316 
317       if (*str == ':') {
318 	seconds *= 60;
319 	++str;
320       }
321     }
322     while (*str >= '0' && *str <= '9');
323 
324     if (*str == '.'
325 # if defined(HAVE_LOCALECONV)
326 	|| *str == *localeconv()->decimal_point
327 # endif
328 	) {
329       char const *ptr;
330 
331       decimal = strtol(++str, (char **) &ptr, 10);
332       if (decimal < 0)
333 	return -1;
334 
335       fraction = decimal;
336 
337       for (fracpart = 1; str != ptr; ++str)
338 	fracpart *= 10;
339     }
340     else if (*str == '/') {
341       ++str;
342 
343       decimal = strtol(str, (char **) &str, 10);
344       if (decimal < 0)
345 	return -1;
346 
347       fraction = seconds;
348       fracpart = decimal;
349 
350       seconds  = 0;
351     }
352 
353     mad_timer_set(&time, seconds, fraction, fracpart);
354     if (minus)
355       mad_timer_negate(&time);
356 
357     mad_timer_add(&accum, time);
358   }
359   while (*str == '-' || *str == '+');
360 
361   while (isspace((unsigned char) *str))
362     ++str;
363 
364   if (*str != 0)
365     return -1;
366 
367   *timer = accum;
368 
369   return 0;
370 }
371 
372 /*
373  * NAME:	get_time()
374  * DESCRIPTION:	parse a time value or die
375  */
376 static
get_time(char const * str,int positive,char const * name)377 mad_timer_t get_time(char const *str, int positive, char const *name)
378 {
379   mad_timer_t time;
380 
381   if (parse_time(&time, str) == -1)
382     die(_("invalid %s specification \"%s\""), name, str);
383 
384   if (positive && mad_timer_sign(time) <= 0)
385     die(_("%s must be positive"), name);
386 
387   return time;
388 }
389 
390 /*
391  * NAME:	parse_decibels()
392  * DESCRIPTION:	parse a decibel value specification string
393  */
394 static
parse_decibels(double * db,char const * str)395 int parse_decibels(double *db, char const *str)
396 {
397   *db = strtod(str, (char **) &str);
398 
399   while (isspace((unsigned char) *str))
400     ++str;
401 
402   if (strncasecmp(str, "dB", 2) == 0) {
403     str += 2;
404 
405     while (isspace((unsigned char) *str))
406       ++str;
407   }
408 
409   if (*str != 0)
410     return -1;
411 
412   return 0;
413 }
414 
415 /*
416  * NAME:	get_decibels()
417  * DESCRIPTION:	parse a decibel value into a linear ratio or die
418  */
419 static
get_decibels(char const * str)420 double get_decibels(char const *str)
421 {
422   double db;
423 
424   if (parse_decibels(&db, str) == -1)
425     die(_("invalid decibel specification \"%s\""), str);
426 
427   if (db < DB_MIN || db > DB_MAX)
428     die(_("decibel value must be in the range %+d to %+d dB"), DB_MIN, DB_MAX);
429 
430   return db;
431 }
432 
433 /*
434  * NAME:	parse_hertz()
435  * DESCRIPTION:	parse a hertz specification string
436  */
437 static
parse_hertz(double * hz,char const * str)438 int parse_hertz(double *hz, char const *str)
439 {
440   *hz = strtod(str, (char **) &str);
441 
442   while (isspace((unsigned char) *str))
443     ++str;
444 
445   if (*str == 'k' || *str == 'K') {
446     *hz *= 1000;
447 
448     do
449       ++str;
450     while (isspace((unsigned char) *str));
451   }
452 
453   if (strncasecmp(str, "Hz", 2) == 0) {
454     str += 2;
455 
456     while (isspace((unsigned char) *str))
457       ++str;
458   }
459 
460   if (*str != 0)
461     return -1;
462 
463   return 0;
464 }
465 
466 /*
467  * NAME:	get_hertz()
468  * DESCRIPTION:	parse a hertz value or die
469  */
470 static
get_hertz(char const * str)471 unsigned int get_hertz(char const *str)
472 {
473   double hz;
474 
475   enum {
476     HZ_MIN = 1000,
477     HZ_MAX = 0xffff
478   };
479 
480   if (parse_hertz(&hz, str) == -1)
481     die(_("invalid hertz specification \"%s\""), str);
482 
483   if (hz < HZ_MIN || hz > HZ_MAX)
484     die(_("hertz value must be in the range %u to %u Hz"), HZ_MIN, HZ_MAX);
485 
486   return (unsigned int) (hz + 0.5);
487 }
488 
489 /*
490  * NAME:	get_options()
491  * DESCRIPTION:	parse command-line options or die
492  */
493 static
get_options(int argc,char * argv[],struct player * player)494 void get_options(int argc, char *argv[], struct player *player)
495 {
496   int opt, index;
497   int ttyset = 0, preamp = 0;
498 
499   while ((opt = getopt_long(argc, argv,
500 			    "vqQ"		/* verbosity options */
501 			    "i"			/* decoding options */
502 			    "o:b:R:da:A:G::"	/* audio output options */
503 # if 0
504 			    "g:x"
505 # endif
506 			    "12mS"		/* channel selection options */
507 			    "s:t:zr::"		/* playback options */
508 			    "TVh",		/* miscellaneous options */
509 			    options, &index)) != -1) {
510     switch (opt) {
511     case 0:
512       break;
513 
514     case '1':
515     case '2':
516       player->output.select = PLAYER_CHANNEL_LEFT + (opt - '1');
517       break;
518 
519     case 'a':
520       player->output.attamp_db = get_decibels(optarg);
521       preamp = 1;
522       break;
523 
524     case 'A':
525       player->output.voladj_db = get_decibels(optarg);
526       player->options |= PLAYER_OPTION_IGNOREVOLADJ;
527       break;
528 
529     case -'a':
530       if (player->ancillary.path)
531 	die(_("multiple output destinations not supported"));
532 
533       player->ancillary.path = optarg;
534       break;
535 
536     case 'b':
537       opt = atoi(optarg);
538       if (opt <= 0)
539 	die(_("invalid bit depth \"%s\""), optarg);
540 
541       player->output.precision_in = opt;
542       break;
543 
544 # if defined(USE_TTY)
545     case -'c':
546       player->options |= PLAYER_OPTION_TTYCONTROL;
547       ttyset = 1;
548       break;
549 
550     case -'C':
551       player->options &= ~PLAYER_OPTION_TTYCONTROL;
552       ttyset = 1;
553       break;
554 # endif
555 
556     case 'd':
557       player->output.mode = AUDIO_MODE_ROUND;
558       break;
559 
560     case -'d':
561       player->options |= PLAYER_OPTION_DOWNSAMPLE;
562       break;
563 
564 # if 0
565     case 'g':
566       player->gap = get_time(optarg, 0, _("gap time"));
567       player->options |= PLAYER_OPTION_GAP;
568       break;
569 # endif
570 
571     case 'G':
572       player->output.replay_gain |= PLAYER_RGAIN_ENABLED;
573 
574       if (optarg) {
575 	size_t len;
576 
577 	len = strlen(optarg);
578 
579 	if (len && strncmp(optarg, "audiophile", len) == 0)
580 	  player->output.replay_gain |= PLAYER_RGAIN_AUDIOPHILE;
581 	else if (len && strncmp(optarg, "radio", len) == 0)
582 	  ;
583 	else
584 	  die(_("invalid Replay Gain argument \"%s\""), optarg);
585       }
586 
587       if (!preamp)
588 	player->output.attamp_db = +6;  /* default pre-amp */
589       break;
590 
591     case 'h':
592       show_usage(1);
593       exit(0);
594 
595     case 'i':
596       player->options |= PLAYER_OPTION_IGNORECRC;
597       break;
598 
599     case -'i':
600       player->fade_in = get_time(optarg ? optarg : FADE_DEFAULT, 1,
601 				 _("fade-in time"));
602       player->options |= PLAYER_OPTION_FADEIN;
603       break;
604 
605     case -'l':
606       ver_license(stdout);
607       exit(0);
608 
609     case 'm':
610       player->output.select = PLAYER_CHANNEL_MONO;
611       break;
612 
613     case 'o':
614       if (player->output.path)
615 	die(_("multiple output destinations not supported"));
616 
617       player->output.path = optarg;
618 
619       player->output.command = audio_output(&player->output.path);
620       if (player->output.command == 0)
621 	die(_("unknown output format type for \"%s\""), optarg);
622 
623       if (!ttyset)
624 	player->options &= ~PLAYER_OPTION_TTYCONTROL;
625       break;
626 
627 # if 0
628     case -'o':
629       player->fade_out = get_time(optarg ? optarg : FADE_DEFAULT, 1,
630 				  _("fade-out time"));
631       player->options |= PLAYER_OPTION_FADEOUT;
632       break;
633 # endif
634 
635     case 'q':
636       player->verbosity = -1;
637 
638       if (!ttyset)
639 	player->options &= ~PLAYER_OPTION_TTYCONTROL;
640       break;
641 
642     case 'Q':
643       player->verbosity = -2;
644 
645       if (!ttyset)
646 	player->options &= ~PLAYER_OPTION_TTYCONTROL;
647       break;
648 
649     case 'r':
650       if (optarg == 0)
651 	player->repeat = -1;
652       else {
653 	player->repeat = atoi(optarg);
654 	if (player->repeat <= 0)
655 	  die(_("invalid repeat count \"%s\""), optarg);
656       }
657       break;
658 
659     case 'R':
660       player->output.speed_request = get_hertz(optarg);
661       break;
662 
663     case 's':
664       player->global_start = get_time(optarg, 0, _("start time"));
665       player->options |= PLAYER_OPTION_SKIP;
666       break;
667 
668     case 'S':
669       player->output.select = PLAYER_CHANNEL_STEREO;
670       break;
671 
672     case 't':
673       player->global_stop = get_time(optarg, 1, _("playing time"));
674       player->options |= PLAYER_OPTION_TIMED;
675       break;
676 
677     case -'t':
678       {
679 	size_t len;
680 
681 	len = strlen(optarg);
682 
683 	if (len && strncmp(optarg, "remaining", len) == 0)
684 	  player->stats.show = STATS_SHOW_REMAINING;
685 	else if (len && strncmp(optarg, "current", len) == 0)
686 	  player->stats.show = STATS_SHOW_CURRENT;
687 	else if (len && strncmp(optarg, "overall", len) == 0)
688 	  player->stats.show = STATS_SHOW_OVERALL;
689 	else
690 	  die(_("invalid display time argument \"%s\""), optarg);
691       }
692       break;
693 
694     case 'T':
695       player->options |= PLAYER_OPTION_SHOWTAGSONLY;
696       break;
697 
698     case 'v':
699       player->verbosity = +1;
700       break;
701 
702     case 'V':
703       ver_version(stdout);
704       fprintf(stderr, "`%s --license' %s.\n", argv0,
705 	      _("for license and warranty information"));
706       exit(0);
707 
708 # if 0
709     case 'x':
710       player->options |= PLAYER_OPTION_CROSSFADE;
711       break;
712 # endif
713 
714     case 'z':
715       player->options |= PLAYER_OPTION_SHUFFLE;
716       break;
717 
718     case '?':
719       show_usage(0);
720       exit(1);
721 
722     default:
723       assert(!"option handler");
724     }
725   }
726 
727   if (optind == argc) {
728     show_usage(0);
729     exit(2);
730   }
731 }
732 
733 /*
734  * NAME:	main()
735  * DESCRIPTION:	program entry point
736  */
main(int argc,char * argv[])737 int main(int argc, char *argv[])
738 {
739   struct player player;
740   int result = 0;
741 
742   argv0 = argv[0];
743 
744   /* ensure binary standard I/O */
745 
746 # if defined(_WIN32)
747   _setmode(_fileno(stdin),  _O_BINARY);
748   _setmode(_fileno(stdout), _O_BINARY);
749 # endif
750 
751   /* internationalization support */
752 
753 # if defined(ENABLE_NLS)
754   setlocale(LC_ALL, "");
755   bindtextdomain(PACKAGE, LOCALEDIR);
756   textdomain(PACKAGE);
757 # endif
758 
759   /* initialize and get options */
760 
761   player_init(&player);
762 
763 # if !defined(__CYGWIN__)  /* Cygwin support for this is currently buggy */
764   /* check for default tty control */
765   if (isatty(STDIN_FILENO))
766     player.options |= PLAYER_OPTION_TTYCONTROL;
767 # endif
768 
769   get_options(argc, argv, &player);
770 
771   /* main processing */
772 
773   if (player.verbosity >= 0)
774     ver_banner(stderr);
775 
776   if (player.options & PLAYER_OPTION_CROSSFADE) {
777     if (!(player.options & PLAYER_OPTION_GAP))
778       warn(_("cross-fade ignored without gap"));
779     else if (mad_timer_sign(player.gap) >= 0)
780       warn(_("cross-fade ignored without negative gap"));
781   }
782 
783   if (player.output.replay_gain & PLAYER_RGAIN_ENABLED) {
784     if (player.options & PLAYER_OPTION_IGNOREVOLADJ)
785       warn(_("volume adjustment ignored with Replay Gain enabled"));
786     else
787       player.options |= PLAYER_OPTION_IGNOREVOLADJ;
788   }
789 
790   if ((player.options & PLAYER_OPTION_SHOWTAGSONLY) &&
791       player.repeat != 1) {
792     warn(_("ignoring repeat"));
793     player.repeat = 1;
794   }
795 
796   /* make stop time absolute */
797   if (player.options & PLAYER_OPTION_TIMED)
798     mad_timer_add(&player.global_stop, player.global_start);
799 
800   /* get default audio output module */
801   if (player.output.command == 0 &&
802       !(player.options & PLAYER_OPTION_SHOWTAGSONLY))
803     player.output.command = audio_output(0);
804 
805 # if defined(EXPERIMENTAL)
806   if (external_mix) {
807     player.options |= PLAYER_OPTION_EXTERNALMIX;
808     player.output.command = 0;
809   }
810   if (experimental)
811     player.options |= PLAYER_OPTION_EXPERIMENTAL;
812 # endif
813 
814   /* run the player */
815 
816   if (player_run(&player, argc - optind, (char const **) &argv[optind]) == -1)
817     result = 4;
818 
819   /* finish up */
820 
821   player_finish(&player);
822 
823   return result;
824 }
825