mirror of
https://github.com/vgmstream/vgmstream.git
synced 2025-01-30 03:47:30 +01:00
test.exe: add "-F" option to loop + play stream's end instead of fading
This commit is contained in:
parent
2c1dafa1a0
commit
9488ba32c7
@ -869,12 +869,31 @@ void close_vgmstream(VGMSTREAM * vgmstream) {
|
|||||||
free(vgmstream);
|
free(vgmstream);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* calculate samples based on player's config */
|
||||||
int32_t get_vgmstream_play_samples(double looptimes, double fadeseconds, double fadedelayseconds, VGMSTREAM * vgmstream) {
|
int32_t get_vgmstream_play_samples(double looptimes, double fadeseconds, double fadedelayseconds, VGMSTREAM * vgmstream) {
|
||||||
if (vgmstream->loop_flag) {
|
if (vgmstream->loop_flag) {
|
||||||
return vgmstream->loop_start_sample+(vgmstream->loop_end_sample-vgmstream->loop_start_sample)*looptimes+(fadedelayseconds+fadeseconds)*vgmstream->sample_rate;
|
if (fadeseconds < 0) { /* a bit hack-y to avoid signature change */
|
||||||
} else return vgmstream->num_samples;
|
/* Continue playing the file normally after looping, instead of fading.
|
||||||
|
* Most files cut abruply after the loop, but some do have proper endings.
|
||||||
|
* With looptimes = 1 this option should give the same output vs loop disabled */
|
||||||
|
int loop_count = (int)looptimes; /* no half loops allowed */
|
||||||
|
vgmstream->loop_target = loop_count;
|
||||||
|
return vgmstream->loop_start_sample
|
||||||
|
+ (vgmstream->loop_end_sample - vgmstream->loop_start_sample) * loop_count
|
||||||
|
+ (vgmstream->num_samples - vgmstream->loop_end_sample);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
return vgmstream->loop_start_sample
|
||||||
|
+ (vgmstream->loop_end_sample - vgmstream->loop_start_sample) * looptimes
|
||||||
|
+ (fadedelayseconds + fadeseconds) * vgmstream->sample_rate;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
return vgmstream->num_samples;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* decode data into sample buffer */
|
||||||
void render_vgmstream(sample * buffer, int32_t sample_count, VGMSTREAM * vgmstream) {
|
void render_vgmstream(sample * buffer, int32_t sample_count, VGMSTREAM * vgmstream) {
|
||||||
switch (vgmstream->layout_type) {
|
switch (vgmstream->layout_type) {
|
||||||
case layout_interleave:
|
case layout_interleave:
|
||||||
@ -1788,13 +1807,21 @@ int vgmstream_samples_to_do(int samples_this_block, int samples_per_frame, VGMST
|
|||||||
return samples_to_do;
|
return samples_to_do;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* return 1 if we just looped */
|
/* loop if end sample is reached, and return 1 if we did loop */
|
||||||
int vgmstream_do_loop(VGMSTREAM * vgmstream) {
|
int vgmstream_do_loop(VGMSTREAM * vgmstream) {
|
||||||
/*if (vgmstream->loop_flag) return 0;*/
|
/*if (!vgmstream->loop_flag) return 0;*/
|
||||||
|
|
||||||
/* is this the loop end? */
|
/* is this the loop end? = new loop, continue from loop_start_sample */
|
||||||
if (vgmstream->current_sample==vgmstream->loop_end_sample) {
|
if (vgmstream->current_sample==vgmstream->loop_end_sample) {
|
||||||
|
|
||||||
|
/* disable looping if target count reached and continue normally
|
||||||
|
* (only needed with the "play stream end after looping N times" option enabled) */
|
||||||
|
vgmstream->loop_count++;
|
||||||
|
if (vgmstream->loop_target && vgmstream->loop_target == vgmstream->loop_count) {
|
||||||
|
vgmstream->loop_flag = 0; /* could be improved but works ok */
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
/* against everything I hold sacred, preserve adpcm
|
/* against everything I hold sacred, preserve adpcm
|
||||||
* history through loop for certain types */
|
* history through loop for certain types */
|
||||||
if (vgmstream->meta_type == meta_DSP_STD ||
|
if (vgmstream->meta_type == meta_DSP_STD ||
|
||||||
|
@ -728,8 +728,6 @@ typedef struct {
|
|||||||
off_t next_block_offset; /* offset of header of the next block */
|
off_t next_block_offset; /* offset of header of the next block */
|
||||||
int block_count; /* count of "semi" block in total block */
|
int block_count; /* count of "semi" block in total block */
|
||||||
|
|
||||||
int hit_loop; /* have we seen the loop yet? */
|
|
||||||
|
|
||||||
/* loop layout (saved values) */
|
/* loop layout (saved values) */
|
||||||
int32_t loop_sample; /* saved from current_sample, should be loop_start_sample... */
|
int32_t loop_sample; /* saved from current_sample, should be loop_start_sample... */
|
||||||
int32_t loop_samples_into_block;/* saved from samples_into_block */
|
int32_t loop_samples_into_block;/* saved from samples_into_block */
|
||||||
@ -737,6 +735,12 @@ typedef struct {
|
|||||||
size_t loop_block_size; /* saved from current_block_size */
|
size_t loop_block_size; /* saved from current_block_size */
|
||||||
off_t loop_next_block_offset; /* saved from next_block_offset */
|
off_t loop_next_block_offset; /* saved from next_block_offset */
|
||||||
|
|
||||||
|
/* loop internals */
|
||||||
|
int hit_loop; /* have we seen the loop yet? */
|
||||||
|
/* counters for "loop + play end of the stream instead of fading" (not used/needed otherwise) */
|
||||||
|
int loop_count; /* number of complete loops (1=looped once) */
|
||||||
|
int loop_target; /* max loops before continuing with the stream end */
|
||||||
|
|
||||||
/* decoder specific */
|
/* decoder specific */
|
||||||
int codec_endian; /* little/big endian marker; name is left vague but usually means big endian */
|
int codec_endian; /* little/big endian marker; name is left vague but usually means big endian */
|
||||||
|
|
||||||
|
34
test/test.c
34
test/test.c
@ -36,7 +36,7 @@ void usage(const char * name) {
|
|||||||
"Options:\n"
|
"Options:\n"
|
||||||
" -o outfile.wav: name of output .wav file, default is dump.wav\n"
|
" -o outfile.wav: name of output .wav file, default is dump.wav\n"
|
||||||
" -l loop count: loop count, default 2.0\n"
|
" -l loop count: loop count, default 2.0\n"
|
||||||
" -f fade time: fade time (seconds), default 10.0\n"
|
" -f fade time: fade time (seconds) after N loops, default 10.0\n"
|
||||||
" -d fade delay: fade delay (seconds, default 0.0\n"
|
" -d fade delay: fade delay (seconds, default 0.0\n"
|
||||||
" -i: ignore looping information and play the whole stream once\n"
|
" -i: ignore looping information and play the whole stream once\n"
|
||||||
" -p: output to stdout (for piping into another program)\n"
|
" -p: output to stdout (for piping into another program)\n"
|
||||||
@ -46,11 +46,12 @@ void usage(const char * name) {
|
|||||||
" -x: decode and print adxencd command line to encode as ADX\n"
|
" -x: decode and print adxencd command line to encode as ADX\n"
|
||||||
" -g: decode and print oggenc command line to encode as OGG\n"
|
" -g: decode and print oggenc command line to encode as OGG\n"
|
||||||
" -b: decode and print batch variable commands\n"
|
" -b: decode and print batch variable commands\n"
|
||||||
" -L: append a smpl chunk and create a looping wav\n"
|
" -L: append a smpl chunk and create a looping wav\n"
|
||||||
" -e: force end-to-end looping\n"
|
" -e: force end-to-end looping\n"
|
||||||
" -E: force end-to-end looping even if file has real loop points\n"
|
" -E: force end-to-end looping even if file has real loop points\n"
|
||||||
" -r outfile2.wav: output a second time after resetting\n"
|
" -r outfile2.wav: output a second time after resetting\n"
|
||||||
" -2 N: only output the Nth (first is 0) set of stereo channels\n"
|
" -2 N: only output the Nth (first is 0) set of stereo channels\n"
|
||||||
|
" -F: don't fade after N loops and play the rest of the stream\n"
|
||||||
,name);
|
,name);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -73,15 +74,16 @@ int main(int argc, char ** argv) {
|
|||||||
int metaonly = 0;
|
int metaonly = 0;
|
||||||
int adxencd = 0;
|
int adxencd = 0;
|
||||||
int oggenc = 0;
|
int oggenc = 0;
|
||||||
int lwav = 0;
|
int lwav = 0;
|
||||||
int batchvar = 0;
|
int batchvar = 0;
|
||||||
int only_stereo = -1;
|
int only_stereo = -1;
|
||||||
double loop_count = 2.0;
|
double loop_count = 2.0;
|
||||||
double fade_seconds = 10.0;
|
double fade_seconds = 10.0;
|
||||||
double fade_delay_seconds = 0.0;
|
double fade_delay_seconds = 0.0;
|
||||||
int32_t bytecount;
|
int fade_ignore = 0;
|
||||||
|
int32_t bytecount;
|
||||||
|
|
||||||
while ((opt = getopt(argc, argv, "o:l:f:d:ipPcmxeLEr:gb2:")) != -1) {
|
while ((opt = getopt(argc, argv, "o:l:f:d:ipPcmxeLEFr:gb2:")) != -1) {
|
||||||
switch (opt) {
|
switch (opt) {
|
||||||
case 'o':
|
case 'o':
|
||||||
outfilename = optarg;
|
outfilename = optarg;
|
||||||
@ -127,14 +129,17 @@ int main(int argc, char ** argv) {
|
|||||||
really_force_loop = 1;
|
really_force_loop = 1;
|
||||||
break;
|
break;
|
||||||
case 'L':
|
case 'L':
|
||||||
lwav = 1;
|
lwav = 1;
|
||||||
break;
|
break;
|
||||||
case 'r':
|
case 'r':
|
||||||
reset_outfilename = optarg;
|
reset_outfilename = optarg;
|
||||||
break;
|
break;
|
||||||
case '2':
|
case '2':
|
||||||
only_stereo = atoi(optarg);
|
only_stereo = atoi(optarg);
|
||||||
break;
|
break;
|
||||||
|
case 'F':
|
||||||
|
fade_ignore = 1;
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
usage(argv[0]);
|
usage(argv[0]);
|
||||||
return 1;
|
return 1;
|
||||||
@ -263,6 +268,11 @@ int main(int argc, char ** argv) {
|
|||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* signal ignore fade for get_vgmstream_play_samples */
|
||||||
|
if (loop_count && fade_ignore) {
|
||||||
|
fade_seconds = -1.0;
|
||||||
|
}
|
||||||
|
|
||||||
len = get_vgmstream_play_samples(loop_count,fade_seconds,fade_delay_seconds,s);
|
len = get_vgmstream_play_samples(loop_count,fade_seconds,fade_delay_seconds,s);
|
||||||
if (!play && !adxencd && !oggenc && !batchvar) printf("samples to play: %d (%.4lf seconds)\n",len,(double)len/s->sample_rate);
|
if (!play && !adxencd && !oggenc && !batchvar) printf("samples to play: %d (%.4lf seconds)\n",len,(double)len/s->sample_rate);
|
||||||
fade_samples = fade_seconds * s->sample_rate;
|
fade_samples = fade_seconds * s->sample_rate;
|
||||||
@ -273,10 +283,10 @@ int main(int argc, char ** argv) {
|
|||||||
} else {
|
} else {
|
||||||
make_wav_header((uint8_t*)buf, len, s->sample_rate, s->channels);
|
make_wav_header((uint8_t*)buf, len, s->sample_rate, s->channels);
|
||||||
}
|
}
|
||||||
if (lwav && s->loop_flag) { // Adding space for smpl chunk at end
|
if (lwav && s->loop_flag) { // Adding space for smpl chunk at end
|
||||||
bytecount = get_32bitLE((uint8_t*)buf + 4);
|
bytecount = get_32bitLE((uint8_t*)buf + 4);
|
||||||
put_32bitLE((uint8_t*)buf + 4, bytecount + 0x44);
|
put_32bitLE((uint8_t*)buf + 4, bytecount + 0x44);
|
||||||
}
|
}
|
||||||
fwrite(buf,1,0x2c,outfile);
|
fwrite(buf,1,0x2c,outfile);
|
||||||
|
|
||||||
/* decode forever */
|
/* decode forever */
|
||||||
@ -325,9 +335,9 @@ int main(int argc, char ** argv) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (lwav && s->loop_flag) { // Writing smpl chuck
|
if (lwav && s->loop_flag) { // Writing smpl chuck
|
||||||
make_smpl_chunk((uint8_t*)buf, s->loop_start_sample, s->loop_end_sample);
|
make_smpl_chunk((uint8_t*)buf, s->loop_start_sample, s->loop_end_sample);
|
||||||
fwrite(buf,1,0x44,outfile);
|
fwrite(buf,1,0x44,outfile);
|
||||||
}
|
}
|
||||||
fclose(outfile); outfile = NULL;
|
fclose(outfile); outfile = NULL;
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user