The following cumulative patch comprises the following chunks: madplay-input-file.diff Read a list of MP3s via "-f file". madplay-output-dev.diff Allow interactive control when playing to an alternate audio device. madplay-quiet-player.diff Get rid of some annoying messages. madplay-saved-tags.diff Save ID3 tags in memory while playing, so that pressing 'i' will tell you about the current track (as opposed to displaying the information at track start, then throwing it away). --- madplay.c~ 2004-09-20 20:02:04.128371301 +0530 +++ madplay.c 2004-09-20 20:04:14.889627979 +0530 @@ -57,6 +57,8 @@ # define FADE_DEFAULT "0:05" +static char *input_file; + # if defined(EXPERIMENTAL) static int external_mix; static int experimental; @@ -71,6 +73,7 @@ { "bit-depth", required_argument, 0, 'b' }, { "display-time", required_argument, 0, -'t' }, { "downsample", no_argument, 0, -'d' }, + { "file", required_argument, 0, 'f' }, { "fade-in", optional_argument, 0, -'i' }, { "help", no_argument, 0, 'h' }, { "ignore-crc", no_argument, 0, 'i' }, @@ -205,6 +208,8 @@ # endif EPUTS(_("\nMiscellaneous:\n")); + EPUTS(_(" -f, --file=[FILE] " + "Read a list of filenames from FILE\n")); EPUTS(_(" -T, --show-tags-only " "show ID3/encoder tags only (do not decode)\n")); EPUTS(_(" -V, --version display version number and exit\n")); @@ -505,7 +510,7 @@ # endif "12mS" /* channel selection options */ "s:t:zr::" /* playback options */ - "TVh", /* miscellaneous options */ + "f:TVh", /* miscellaneous options */ options, &index)) != -1) { switch (opt) { case 0: @@ -561,6 +566,10 @@ player->options |= PLAYER_OPTION_DOWNSAMPLE; break; + case 'f': + input_file = optarg; + break; + # if 0 case 'g': player->gap = get_time(optarg, 0, _("gap time")); @@ -724,7 +733,7 @@ } } - if (optind == argc) { + if (optind == argc && !input_file) { show_usage(0); exit(2); } @@ -739,6 +748,9 @@ struct player player; int result = 0; + char const **names = 0; + int nindex = 0; + argv0 = argv[0]; /* ensure binary standard I/O */ @@ -811,9 +823,42 @@ player.options |= PLAYER_OPTION_EXPERIMENTAL; # endif - /* run the player */ + /* run the player with suitable input */ + + if (input_file) { + FILE *f; + char s[1024]; + + if (strcmp(input_file, "-") == 0) { + f = stdin; + player.options |= PLAYER_OPTION_TTYCONTROL; + } + else { + f = fopen(input_file, "r"); + } + + if (!f) + die(_("Couldn't open input file \"%s\""), input_file); + + while (fgets(s, 1024, f)) { + int n = strlen(s); + if (s[n-1] == '\n') + s[n-1] = '\0'; + + if (nindex%1024 == 0) { + names = realloc(names, sizeof(char *)*(nindex+1024)); + if (!names) + die(_("Out of memory")); + } + names[nindex++] = strdup(s); + } + } + else { + nindex = argc - optind; + names = &argv[optind]; + } - if (player_run(&player, argc - optind, (char const **) &argv[optind]) == -1) + if (player_run(&player, nindex, names) == -1) result = 4; /* finish up */ --- madplay.c~ 2004-11-23 16:07:26.187876769 +0530 +++ madplay.c 2004-11-23 16:05:38.472594025 +0530 @@ -629,7 +629,7 @@ if (player->output.command == 0) die(_("unknown output format type for \"%s\""), optarg); - if (!ttyset) + if (!ttyset && player->output.command != AUDIO_DEFAULT) player->options &= ~PLAYER_OPTION_TTYCONTROL; break; --- player.c~ 2004-09-20 21:54:34.808771264 +0530 +++ player.c 2004-09-20 21:55:23.906054296 +0530 @@ -632,6 +632,8 @@ { "TENC", N_("Encoder") } }; + return; + /* text information */ for (i = 0; i < sizeof(info) / sizeof(info[0]); ++i) { @@ -1915,8 +1917,7 @@ } } - if (player->verbosity >= 0 && - player->playlist.length > 1) + if (player->verbosity >= 0) message(">> %s\n", player->input.path); /* reset file information */ @@ -1980,12 +1981,12 @@ peak_str = db_str; } - message("%lu %s (%s), %s dB %s, %lu %s\n", + /* message("%lu %s (%s), %s dB %s, %lu %s\n", player->stats.play_framecount, player->stats.play_framecount == 1 ? _("frame decoded") : _("frames decoded"), time_str, peak_str, _("peak amplitude"), player->stats.audio.clipped_samples, player->stats.audio.clipped_samples == 1 ? - _("clipped sample") : _("clipped samples")); + _("clipped sample") : _("clipped samples")); */ } if (player->input.fd != STDIN_FILENO && --- player.h~ 2004-12-25 22:28:01.414805964 +0530 +++ player.h 2004-12-25 22:28:14.134596977 +0530 @@ -123,6 +123,12 @@ int eof; struct tag tag; + struct tagval { + char *tag; + char *value; + } **id3_tags; + int ntags; + int nslots; } input; struct output { --- player.c~ 2004-12-25 22:28:04.900200679 +0530 +++ player.c 2004-12-25 22:36:20.525072691 +0530 @@ -148,6 +148,7 @@ player->input.data = 0; player->input.length = 0; player->input.eof = 0; + player->input.id3_tags = 0; tag_init(&player->input.tag); @@ -598,12 +599,77 @@ return 0; } + +static +void save_id3_tag(struct player *player, + const char *tag, const char *value) +{ + int i; + + if (*value == '\0') + return; + + if (!player->input.id3_tags) { + player->input.ntags = 0; + player->input.nslots = 32; + player->input.id3_tags = + malloc(player->input.nslots*sizeof(struct tagval *)); + } + + if (player->input.ntags == player->input.nslots) { + player->input.nslots *= 2; + player->input.id3_tags = + realloc(player->input.id3_tags, + player->input.nslots*sizeof(struct tagval *)); + } + + i = player->input.ntags; + player->input.id3_tags[i] = malloc(sizeof(struct tagval)); + player->input.id3_tags[i]->tag = tag ? strdup(tag) : 0; + player->input.id3_tags[i]->value = strdup(value); + player->input.ntags++; +} + +static +void clear_saved_id3_tags(struct player *player) +{ + if (player->input.id3_tags) { + int i = 0; + while (i < player->input.ntags) { + free(player->input.id3_tags[i]->tag); + free(player->input.id3_tags[i]->value); + free(player->input.id3_tags[i]); + i++; + } + free(player->input.id3_tags); + player->input.id3_tags = 0; + player->input.nslots = 0; + player->input.ntags = 0; + } +} + +static +void show_saved_id3_tags(struct player *player) +{ + int i = 0; + + if (!player->input.id3_tags) + return; + + while (i < player->input.ntags) { + detail(player->input.id3_tags[i]->tag, 0, + player->input.id3_tags[i]->value ); + i++; + } +} + + /* * NAME: show_id3() * DESCRIPTION: display ID3 tag information */ static -void show_id3(struct id3_tag const *tag) +void show_id3(struct player *player, struct id3_tag const *tag) { unsigned int i; struct id3_frame const *frame; @@ -632,10 +698,10 @@ { "TENC", N_("Encoder") } }; - return; - /* text information */ + clear_saved_id3_tags(player); + for (i = 0; i < sizeof(info) / sizeof(info[0]); ++i) { union id3_field const *field; unsigned int nstrings, j; @@ -659,15 +725,23 @@ goto fail; if (j == 0 && info[i].label) - detail(gettext(info[i].label), 0, latin1); + save_id3_tag(player, gettext(info[i].label), latin1); else { if (strcmp(info[i].id, "TCOP") == 0 || - strcmp(info[i].id, "TPRO") == 0) { - detail(0, "%s %s", (info[i].id[1] == 'C') ? - _("Copyright (C)") : _("Produced (P)"), latin1); + strcmp(info[i].id, "TPRO") == 0) + { + char *value = malloc(strlen(latin1)+32); + if (info[i].id[1] == 'C') + strcat(value, _("Copyright (C)")); + else + strcat(value, _("Produced (P)")); + strcat(value, " " ); + strcat(value, latin1); + save_id3_tag(player, 0, value); + free(value); } else - detail(0, 0, latin1); + save_id3_tag(player, 0, latin1); } free(latin1); @@ -691,7 +765,7 @@ if (latin1 == 0) goto fail; - detail(_("Comment"), 0, latin1); + save_id3_tag(player, _("Comment"), latin1); free(latin1); break; @@ -1190,10 +1264,7 @@ { struct id3_frame const *frame; - /* display the tag */ - - if (player->verbosity >= 0 || (player->options & PLAYER_OPTION_SHOWTAGSONLY)) - show_id3(tag); + show_id3(player, tag); /* * The following is based on information from the @@ -2293,6 +2364,9 @@ goto stop; case KEY_INFO: + show_saved_id3_tags(player); + break; + case '?': if (player->verbosity <= 0) { show_status(&player->stats, 0, player->input.path, 1);