vgmstream123: extra subsong options and info

This commit is contained in:
bnnm 2021-11-30 20:38:46 +01:00
parent a074e9f2d0
commit bc68cccc63
2 changed files with 85 additions and 30 deletions

View File

@ -69,9 +69,10 @@
#define LITTLE_ENDIAN_OUTPUT 1 /* untested in BE */ #define LITTLE_ENDIAN_OUTPUT 1 /* untested in BE */
#define DEFAULT_PARAMS { 0, -1, 2.0, 10.0, 0.0, 0, 0, 0, 0 } #define DEFAULT_PARAMS { 0, 0, -1, 2.0, 10.0, 0.0, 0, 0, 0, 0 }
typedef struct { typedef struct {
int stream_index; int subsong_index;
int subsong_end;
double min_time; double min_time;
double loop_count; double loop_count;
@ -240,7 +241,7 @@ static int play_vgmstream(const char* filename, song_settings_t* cfg) {
vgmstream_set_log_stdout(VGM_LOG_LEVEL_ALL); vgmstream_set_log_stdout(VGM_LOG_LEVEL_ALL);
sf->stream_index = cfg->stream_index; sf->stream_index = cfg->subsong_index;
vgmstream = init_vgmstream_from_STREAMFILE(sf); vgmstream = init_vgmstream_from_STREAMFILE(sf);
close_streamfile(sf); close_streamfile(sf);
@ -249,15 +250,11 @@ static int play_vgmstream(const char* filename, song_settings_t* cfg) {
return -1; return -1;
} }
printf("Playing stream: %s\n", filename); /* force load total subsongs if signalled */
if (cfg->subsong_end == -1) {
/* Print metadata in verbose mode cfg->subsong_end = vgmstream->num_streams;
*/ close_vgmstream(vgmstream);
if (verbose) { return 0;
char description[4096] = { '\0' };
describe_vgmstream(vgmstream, description, sizeof(description));
puts(description);
putchar('\n');
} }
/* If the audio device hasn't been opened yet, then describe it /* If the audio device hasn't been opened yet, then describe it
@ -273,6 +270,27 @@ static int play_vgmstream(const char* filename, song_settings_t* cfg) {
putchar('\n'); putchar('\n');
} }
if (vgmstream->num_streams > 0) {
int subsong = vgmstream->stream_index;
if (!subsong)
subsong = 1;
printf("Playing stream: %s [%i/%i]\n", filename, subsong, vgmstream->num_streams);
}
else {
printf("Playing stream: %s\n", filename);
}
/* Print metadata in verbose mode
*/
if (verbose) {
char description[4096] = { '\0' };
describe_vgmstream(vgmstream, description, sizeof(description));
puts(description);
putchar('\n');
}
/* Stupid hack to hang onto a few low-numbered file descriptors /* Stupid hack to hang onto a few low-numbered file descriptors
* so that play_compressed_file() doesn't break, due to POSIX * so that play_compressed_file() doesn't break, due to POSIX
* wackiness like https://bugs.debian.org/590920 * wackiness like https://bugs.debian.org/590920
@ -494,7 +512,7 @@ static int play_playlist(const char *filename, song_settings_t *default_par) {
else if (PARAM_MATCHES("LOOPCOUNT")) else if (PARAM_MATCHES("LOOPCOUNT"))
par.loop_count = atof(arg); par.loop_count = atof(arg);
else if (PARAM_MATCHES("STREAMINDEX")) else if (PARAM_MATCHES("STREAMINDEX"))
par.stream_index = atoi(arg); par.subsong_index = atoi(arg);
param = strtok(NULL, ","); param = strtok(NULL, ",");
} }
@ -600,23 +618,49 @@ fail:
return ret; return ret;
} }
static int play_file(const char *filename, song_settings_t *par) {
size_t len = strlen(filename);
#define ENDS_IN(EXT) !strcasecmp(EXT, filename + len - sizeof(EXT) + 1) #define ENDS_IN(EXT) !strcasecmp(EXT, filename + len - sizeof(EXT) + 1)
static int play_standard(const char* filename, song_settings_t* cfg) {
int ret, subsong;
/* standard */
if (cfg->subsong_end == 0) {
return play_vgmstream(filename, cfg);
}
/* N subsongs */
/* first call should force load max subsongs */
if (cfg->subsong_end == -1) {
ret = play_vgmstream(filename, cfg);
if (ret) return ret;
}
for (subsong = cfg->subsong_index; subsong < cfg->subsong_end + 1; subsong++) {
cfg->subsong_index = subsong;
ret = play_vgmstream(filename, cfg);
if (ret) return ret;
}
return 0;
}
static int play_file(const char* filename, song_settings_t* cfg) {
size_t len = strlen(filename);
if (ENDS_IN(".m3u") || ENDS_IN(".m3u8")) if (ENDS_IN(".m3u") || ENDS_IN(".m3u8"))
return play_playlist(filename, par); return play_playlist(filename, cfg);
else if (ENDS_IN(".bz2")) else if (ENDS_IN(".bz2"))
return play_compressed_file(filename, par, "bzip2 -cd"); return play_compressed_file(filename, cfg, "bzip2 -cd");
else if (ENDS_IN(".gz")) else if (ENDS_IN(".gz"))
return play_compressed_file(filename, par, "gzip -cd"); return play_compressed_file(filename, cfg, "gzip -cd");
else if (ENDS_IN(".lzma")) else if (ENDS_IN(".lzma"))
return play_compressed_file(filename, par, "lzma -cd"); return play_compressed_file(filename, cfg, "lzma -cd");
else if (ENDS_IN(".xz")) else if (ENDS_IN(".xz"))
return play_compressed_file(filename, par, "xz -cd"); return play_compressed_file(filename, cfg, "xz -cd");
else else
return play_vgmstream(filename, par); return play_standard(filename, cfg);
} }
static void add_driver_option(const char *key_value) { static void add_driver_option(const char *key_value) {
@ -674,8 +718,9 @@ static void usage(const char* progname, int is_help) {
" -@ LSTFILE Read playlist from LSTFILE\n" " -@ LSTFILE Read playlist from LSTFILE\n"
"\n" "\n"
" -o OUTFILE Set output filename for a file driver specified with -D\n" " -o OUTFILE Set output filename for a file driver specified with -D\n"
" -m Display stream metadata and playback progress\n" " -m Print metadata and playback progress\n"
" -s N Play subsong index N\n" " -s N Play subsong N, if the format supports multiple subsongs\n"
" -S N Play up to end subsong N (set 0 for 'all')\n"
" -h Print this help\n" " -h Print this help\n"
"\n" "\n"
"Looping options:\n" "Looping options:\n"
@ -726,7 +771,7 @@ again_opts:
cfg = default_par; cfg = default_par;
} }
while ((opt = getopt(argc, argv, "-D:f:l:M:s:B:d:o:P:@:hrmieEc")) != -1) { while ((opt = getopt(argc, argv, "-D:f:l:M:s:B:d:o:P:@:hrmieEcS:")) != -1) {
switch (opt) { switch (opt) {
case 1: case 1:
/* glibc getopt extension /* glibc getopt extension
@ -758,7 +803,14 @@ again_opts:
cfg.loop_count = -1.0; cfg.loop_count = -1.0;
break; break;
case 's': case 's':
cfg.stream_index = atoi(optarg); cfg.subsong_index = atoi(optarg);
break;
case 'S':
cfg.subsong_end = atoi(optarg);
if (!cfg.subsong_end)
cfg.subsong_end = -1; /* signal up to end (otherwise 0 = not set) */
if (!cfg.subsong_index)
cfg.subsong_index = 1;
break; break;
case 'i': case 'i':
cfg.ignore_loop = 1; cfg.ignore_loop = 1;

View File

@ -121,10 +121,13 @@ document in vgmstream's source code (can be done with CMake or autotools).
Usage: `vgmstream123 [options] INFILE ...` Usage: `vgmstream123 [options] INFILE ...`
The program is meant to be a simple stand-alone player, supporting playback of The program is meant to be a simple stand-alone player, supporting playback of
vgmstream files through libao. On Linux, files compressed with gzip/bzip2/xz also vgmstream files through libao. Most options should be similar to CLI's
work, as identified by a `.gz/.bz2/.xz` extension. The file will be decompressed (`-m`, `-i`, `-s N` and so on, though not fully equivalent), use `-h` for full info.
to a temp dir using the respective utility program (which must be installed
and accessible) and then loaded. On Linux, files compressed with gzip/bzip2/xz also work, as identified by a
`.gz/.bz2/.xz` extension. The file will be decompressed to a temp dir using the
respective utility program (which must be installed and accessible) and then
loaded.
It also supports playlists, and will recognize a special extended-M3U tag It also supports playlists, and will recognize a special extended-M3U tag
specific to vgmstream of the following form: specific to vgmstream of the following form: