2008-02-04 13:11:40 +01:00
|
|
|
#define POSIXLY_CORRECT
|
|
|
|
#include <unistd.h>
|
2008-01-31 07:15:03 +01:00
|
|
|
#include "../src/vgmstream.h"
|
|
|
|
#include "../src/util.h"
|
|
|
|
|
|
|
|
#define BUFSIZE 4000
|
|
|
|
|
2008-02-04 13:11:40 +01:00
|
|
|
extern char * optarg;
|
|
|
|
extern int optind, opterr, optopt;
|
|
|
|
|
|
|
|
void usage(const char * name) {
|
2008-03-14 14:11:14 +01:00
|
|
|
fprintf(stderr,"vgmstream test decoder " VERSION "\n"
|
2008-03-03 23:07:39 +01:00
|
|
|
"Usage: %s [-o outfile.wav] [-l loop count]\n"
|
2008-05-05 00:03:10 +02:00
|
|
|
"\t[-f fade time] [-ipcmxeE] infile\n"
|
2008-02-14 23:38:23 +01:00
|
|
|
"Options:\n"
|
|
|
|
"\t-o outfile.wav: name of output .wav file, default is dump.wav\n"
|
|
|
|
"\t-l loop count: loop count, default 2.0\n"
|
|
|
|
"\t-f fade time: fade time (seconds), default 10.0\n"
|
|
|
|
"\t-i: ignore looping information and play the whole stream once\n"
|
|
|
|
"\t-p: output to stdout (for piping into another program)\n"
|
|
|
|
"\t-c: loop forever (continuously)\n"
|
2008-03-04 08:40:41 +01:00
|
|
|
"\t-m: print metadata only, don't decode\n"
|
|
|
|
"\t-x: decode and print adxencd command line to encode as ADX\n"
|
2008-05-05 00:03:10 +02:00
|
|
|
"\t-e: force end-to-end looping\n"
|
|
|
|
"\t-E: force end-to-end looping even if file has real loop points\n"
|
2008-03-04 08:40:41 +01:00
|
|
|
,name);
|
|
|
|
|
2008-02-04 13:11:40 +01:00
|
|
|
}
|
|
|
|
|
2008-01-31 07:15:03 +01:00
|
|
|
int main(int argc, char ** argv) {
|
|
|
|
VGMSTREAM * s;
|
2008-04-15 17:49:47 +02:00
|
|
|
sample * buf = NULL;
|
2008-01-31 07:15:03 +01:00
|
|
|
int32_t len;
|
2008-02-04 13:11:40 +01:00
|
|
|
int32_t fade_samples;
|
2008-01-31 07:15:03 +01:00
|
|
|
int i;
|
2008-02-04 13:11:40 +01:00
|
|
|
FILE * outfile = NULL;
|
2008-02-14 23:38:23 +01:00
|
|
|
char * outfilename = NULL;
|
2008-02-04 13:11:40 +01:00
|
|
|
int opt;
|
|
|
|
int ignore_loop = 0;
|
2008-05-05 00:03:10 +02:00
|
|
|
int force_loop = 0;
|
|
|
|
int really_force_loop = 0;
|
2008-02-06 21:53:10 +01:00
|
|
|
int play = 0;
|
|
|
|
int forever = 0;
|
2008-02-14 23:38:23 +01:00
|
|
|
int metaonly = 0;
|
2008-03-04 08:40:41 +01:00
|
|
|
int adxencd = 0;
|
2008-02-04 13:11:40 +01:00
|
|
|
double loop_count = 2.0;
|
|
|
|
double fade_time = 10.0;
|
|
|
|
|
2008-05-05 00:03:10 +02:00
|
|
|
while ((opt = getopt(argc, argv, "o:l:f:ipcmxeE")) != -1) {
|
2008-02-04 13:11:40 +01:00
|
|
|
switch (opt) {
|
|
|
|
case 'o':
|
2008-02-14 23:38:23 +01:00
|
|
|
outfilename = optarg;
|
2008-02-04 13:11:40 +01:00
|
|
|
break;
|
|
|
|
case 'l':
|
2008-02-14 23:38:23 +01:00
|
|
|
loop_count = atof(optarg);
|
2008-02-04 13:11:40 +01:00
|
|
|
break;
|
|
|
|
case 'f':
|
2008-02-14 23:38:23 +01:00
|
|
|
fade_time = atof(optarg);
|
2008-02-04 13:11:40 +01:00
|
|
|
break;
|
|
|
|
case 'i':
|
|
|
|
ignore_loop = 1;
|
|
|
|
break;
|
2008-02-06 21:53:10 +01:00
|
|
|
case 'p':
|
|
|
|
play = 1;
|
|
|
|
break;
|
|
|
|
case 'c':
|
|
|
|
forever = 1;
|
|
|
|
break;
|
2008-02-14 23:38:23 +01:00
|
|
|
case 'm':
|
|
|
|
metaonly = 1;
|
|
|
|
break;
|
2008-03-04 08:40:41 +01:00
|
|
|
case 'x':
|
|
|
|
adxencd = 1;
|
|
|
|
break;
|
2008-05-05 00:03:10 +02:00
|
|
|
case 'e':
|
|
|
|
force_loop = 1;
|
|
|
|
break;
|
|
|
|
case 'E':
|
|
|
|
really_force_loop = 1;
|
|
|
|
break;
|
2008-02-04 13:11:40 +01:00
|
|
|
default:
|
|
|
|
usage(argv[0]);
|
|
|
|
return 1;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
2008-01-31 07:15:03 +01:00
|
|
|
|
2008-02-04 13:11:40 +01:00
|
|
|
if (optind!=argc-1) {
|
|
|
|
usage(argv[0]);
|
|
|
|
return 1;
|
|
|
|
}
|
2008-02-06 21:53:10 +01:00
|
|
|
|
|
|
|
if (forever && !play) {
|
|
|
|
fprintf(stderr,"A file of infinite size? Not likely.\n");
|
|
|
|
return 1;
|
|
|
|
}
|
2008-05-05 00:03:10 +02:00
|
|
|
|
|
|
|
if (ignore_loop && force_loop) {
|
|
|
|
fprintf(stderr,"-e and -i are incompatible\n");
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
if (ignore_loop && really_force_loop) {
|
|
|
|
fprintf(stderr,"-E and -i are incompatible\n");
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
if (force_loop && really_force_loop) {
|
|
|
|
fprintf(stderr,"-E and -e are somewhat redundant, are you confused?\n");
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
2008-02-04 13:11:40 +01:00
|
|
|
s = init_vgmstream(argv[optind]);
|
2008-01-31 07:15:03 +01:00
|
|
|
|
|
|
|
if (!s) {
|
2008-02-04 13:11:40 +01:00
|
|
|
fprintf(stderr,"failed opening %s\n",argv[optind]);
|
2008-01-31 07:15:03 +01:00
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
2008-05-05 00:03:10 +02:00
|
|
|
/* force only if there aren't already loop points */
|
|
|
|
if (force_loop && !s->loop_flag) {
|
|
|
|
/* this requires a bit more messing with the VGMSTREAM than I'm
|
|
|
|
* comfortable with... */
|
|
|
|
s->loop_flag=1;
|
|
|
|
s->loop_start_sample=0;
|
|
|
|
s->loop_end_sample=s->num_samples;
|
|
|
|
s->loop_ch=calloc(s->channels,sizeof(VGMSTREAMCHANNEL));
|
|
|
|
}
|
|
|
|
|
|
|
|
/* force even if there are loop points */
|
|
|
|
if (really_force_loop) {
|
|
|
|
if (!s->loop_flag) s->loop_ch=calloc(s->channels,sizeof(VGMSTREAMCHANNEL));
|
|
|
|
s->loop_flag=1;
|
|
|
|
s->loop_start_sample=0;
|
|
|
|
s->loop_end_sample=s->num_samples;
|
|
|
|
}
|
|
|
|
|
2008-02-04 13:11:40 +01:00
|
|
|
if (ignore_loop) s->loop_flag=0;
|
|
|
|
|
2008-02-06 21:53:10 +01:00
|
|
|
if (play) {
|
2008-02-14 23:38:23 +01:00
|
|
|
if (outfilename) {
|
2008-02-06 21:53:10 +01:00
|
|
|
fprintf(stderr,"either -p or -o, make up your mind\n");
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
outfile = stdout;
|
2008-02-14 23:38:23 +01:00
|
|
|
} else if (!metaonly) {
|
|
|
|
if (!outfilename) outfilename = "dump.wav";
|
|
|
|
outfile = fopen(outfilename,"wb");
|
2008-02-04 13:11:40 +01:00
|
|
|
if (!outfile) {
|
2008-02-14 23:38:23 +01:00
|
|
|
fprintf(stderr,"failed to open %s for output\n",optarg);
|
2008-02-04 13:11:40 +01:00
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2008-02-06 21:53:10 +01:00
|
|
|
if (forever && !s->loop_flag) {
|
|
|
|
fprintf(stderr,"I could play a nonlooped track forever, but it wouldn't end well.");
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
2008-02-14 23:38:23 +01:00
|
|
|
if (!play) {
|
|
|
|
if (metaonly) printf("metadata for %s\n",argv[optind]);
|
2008-03-04 08:40:41 +01:00
|
|
|
else if (adxencd) {
|
|
|
|
printf("adxencd %s",outfilename);
|
|
|
|
if (s->loop_flag) printf(" -lps%d -lpe%d",s->loop_start_sample,s->loop_end_sample);
|
|
|
|
printf("\n");
|
|
|
|
}
|
2008-02-14 23:38:23 +01:00
|
|
|
else printf("decoding %s\n",argv[optind]);
|
2008-01-31 07:15:03 +01:00
|
|
|
}
|
2008-03-11 02:27:59 +01:00
|
|
|
if (!play && !adxencd) {
|
|
|
|
char description[1024];
|
|
|
|
description[0]='\0';
|
|
|
|
describe_vgmstream(s,description,1024);
|
|
|
|
printf("%s\n",description);
|
|
|
|
}
|
2008-02-14 23:38:23 +01:00
|
|
|
if (metaonly) {
|
|
|
|
close_vgmstream(s);
|
|
|
|
return 0;
|
|
|
|
}
|
2008-01-31 07:15:03 +01:00
|
|
|
|
2008-04-15 17:49:47 +02:00
|
|
|
buf = malloc(BUFSIZE*sizeof(sample)*s->channels);
|
|
|
|
|
2008-02-04 13:11:40 +01:00
|
|
|
len = get_vgmstream_play_samples(loop_count,fade_time,s);
|
2008-03-04 08:40:41 +01:00
|
|
|
if (!play && !adxencd) printf("samples to play: %d (%.2lf seconds)\n",len,(double)len/s->sample_rate);
|
2008-02-04 13:11:40 +01:00
|
|
|
fade_samples = fade_time * s->sample_rate;
|
2008-01-31 07:15:03 +01:00
|
|
|
|
2008-02-04 11:34:18 +01:00
|
|
|
/* slap on a .wav header */
|
|
|
|
make_wav_header((uint8_t*)buf, len, s->sample_rate, s->channels);
|
|
|
|
fwrite(buf,1,0x2c,outfile);
|
|
|
|
|
2008-05-05 00:03:10 +02:00
|
|
|
/* decode forever */
|
2008-02-06 21:53:10 +01:00
|
|
|
while (forever) {
|
|
|
|
render_vgmstream(buf,BUFSIZE,s);
|
|
|
|
fwrite(buf,sizeof(sample)*s->channels,BUFSIZE,outfile);
|
|
|
|
}
|
|
|
|
|
2008-05-05 00:03:10 +02:00
|
|
|
/* decode */
|
2008-01-31 07:15:03 +01:00
|
|
|
for (i=0;i<len;i+=BUFSIZE) {
|
|
|
|
int toget=BUFSIZE;
|
|
|
|
if (i+BUFSIZE>len) toget=len-i;
|
|
|
|
render_vgmstream(buf,toget,s);
|
2008-02-04 13:11:40 +01:00
|
|
|
|
|
|
|
if (s->loop_flag && fade_samples > 0) {
|
|
|
|
int samples_into_fade = i - (len - fade_samples);
|
|
|
|
if (samples_into_fade + toget > 0) {
|
|
|
|
int j,k;
|
|
|
|
for (j=0;j<toget;j++,samples_into_fade++) {
|
|
|
|
if (samples_into_fade > 0) {
|
|
|
|
double fadedness = (double)(fade_samples-samples_into_fade)/fade_samples;
|
|
|
|
for (k=0;k<s->channels;k++) {
|
|
|
|
buf[j*s->channels+k] = buf[j*s->channels+k]*fadedness;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2008-02-04 11:48:04 +01:00
|
|
|
fwrite(buf,sizeof(sample)*s->channels,toget,outfile);
|
2008-01-31 07:15:03 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
close_vgmstream(s);
|
2008-02-15 17:26:29 +01:00
|
|
|
|
|
|
|
return 0;
|
2008-01-31 07:15:03 +01:00
|
|
|
}
|