diff --git a/src/vgmstream.c b/src/vgmstream.c index 2c85e39e..07479910 100644 --- a/src/vgmstream.c +++ b/src/vgmstream.c @@ -78,9 +78,11 @@ VGMSTREAM * init_vgmstream_internal(const char * const filename, int do_dfs) { } /* save start things so we can restart for seeking */ - /* TODO: we may need to save other things here */ + /* copy the channels */ memcpy(vgmstream->start_ch,vgmstream->ch,sizeof(VGMSTREAMCHANNEL)*vgmstream->channels); - vgmstream->start_block_offset = vgmstream->current_block_offset; + /* copy the whole VGMSTREAM */ + memcpy(vgmstream->start_vgmstream,vgmstream,sizeof(VGMSTREAM)); + return vgmstream; } } @@ -88,9 +90,25 @@ VGMSTREAM * init_vgmstream_internal(const char * const filename, int do_dfs) { return NULL; } +/* Reset a VGMSTREAM to its state at the start of playback. + * Note that this does not reset the constituent STREAMFILES. */ +void reset_vgmstream(VGMSTREAM * vgmstream) { + /* copy the vgmstream back into itself */ + memcpy(vgmstream,vgmstream->start_vgmstream,sizeof(VGMSTREAM)); + + /* copy the initial channels */ + memcpy(vgmstream->ch,vgmstream->start_ch,sizeof(VGMSTREAMCHANNEL)*vgmstream->channels); + + /* loop_ch is not zeroed here because there is a possibility of the + * init_vgmstream_* function doing something tricky and precomputing it. + * Otherwise hit_loop will be 0 and it will be copied over anyway when we + * really hit the loop start. */ +} + /* simply allocate memory for the VGMSTREAM and its channels */ VGMSTREAM * allocate_vgmstream(int channel_count, int looped) { VGMSTREAM * vgmstream; + VGMSTREAM * start_vgmstream; VGMSTREAMCHANNEL * channels; VGMSTREAMCHANNEL * start_channels; VGMSTREAMCHANNEL * loop_channels; @@ -100,9 +118,18 @@ VGMSTREAM * allocate_vgmstream(int channel_count, int looped) { vgmstream = calloc(1,sizeof(VGMSTREAM)); if (!vgmstream) return NULL; + start_vgmstream = calloc(1,sizeof(VGMSTREAM)); + if (!start_vgmstream) { + free(vgmstream); + return NULL; + } + vgmstream->start_vgmstream = start_vgmstream; + start_vgmstream->start_vgmstream = start_vgmstream; + channels = calloc(channel_count,sizeof(VGMSTREAMCHANNEL)); if (!channels) { free(vgmstream); + free(start_vgmstream); return NULL; } vgmstream->ch = channels; @@ -111,6 +138,7 @@ VGMSTREAM * allocate_vgmstream(int channel_count, int looped) { start_channels = calloc(channel_count,sizeof(VGMSTREAMCHANNEL)); if (!start_channels) { free(vgmstream); + free(start_vgmstream); free(channels); return NULL; } @@ -120,6 +148,7 @@ VGMSTREAM * allocate_vgmstream(int channel_count, int looped) { loop_channels = calloc(channel_count,sizeof(VGMSTREAMCHANNEL)); if (!loop_channels) { free(vgmstream); + free(start_vgmstream); free(channels); free(start_channels); return NULL; @@ -143,6 +172,8 @@ void close_vgmstream(VGMSTREAM * vgmstream) { if (vgmstream->loop_ch) free(vgmstream->loop_ch); if (vgmstream->start_ch) free(vgmstream->start_ch); if (vgmstream->ch) free(vgmstream->ch); + /* the start_vgmstream is considered just data */ + if (vgmstream->start_vgmstream) free(vgmstream->start_vgmstream); free(vgmstream); } @@ -746,8 +777,7 @@ void try_dual_file_stereo(VGMSTREAM * opened_stream, const char * const filename * difficult to determine when it does, and they should be zero * otherwise, anyway */ new_stream->interleave_block_size == opened_stream->interleave_block_size && - new_stream->interleave_smallblock_size == opened_stream->interleave_smallblock_size && - new_stream->start_block_offset == opened_stream->start_block_offset) { + new_stream->interleave_smallblock_size == opened_stream->interleave_smallblock_size) { /* We seem to have a usable, matching file. Merge in the second channel. */ VGMSTREAMCHANNEL * new_chans; VGMSTREAMCHANNEL * new_loop_chans = NULL; diff --git a/src/vgmstream.h b/src/vgmstream.h index fe43743d..118aae2d 100644 --- a/src/vgmstream.h +++ b/src/vgmstream.h @@ -159,7 +159,6 @@ typedef struct { size_t interleave_block_size; /* interleave for this file */ size_t interleave_smallblock_size; /* smaller interleave for last block */ /* headered blocks */ - off_t start_block_offset; /* first block in the file */ off_t current_block_offset; /* start of this block (offset of block header) */ size_t current_block_size; /* size of the block we're in now */ off_t next_block_offset; /* offset of header of the next block */ @@ -175,6 +174,8 @@ typedef struct { uint8_t xa_channel; /* Selected XA Channel */ int32_t xa_sector_length; /* XA block */ + + void * start_vgmstream; /* a copy of the VGMSTREAM as it was at the beginning of the stream */ } VGMSTREAM; /* do format detection, return pointer to a usable VGMSTREAM, or NULL on failure */ @@ -184,6 +185,9 @@ VGMSTREAM * init_vgmstream(const char * const filename); * about */ VGMSTREAM * init_vgmstream_internal(const char * const filename, int do_dfs); +/* reset a VGMSTREAM to start of stream */ +void reset_vgmstream(VGMSTREAM * vgmstream); + /* allocate a VGMSTREAM and channel stuff */ VGMSTREAM * allocate_vgmstream(int channel_count, int looped); diff --git a/test/test.c b/test/test.c index 8170c3d8..16f86f86 100644 --- a/test/test.c +++ b/test/test.c @@ -25,6 +25,7 @@ void usage(const char * name) { " -x: decode and print adxencd command line to encode as ADX\n" " -e: force end-to-end looping\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" ,name); } @@ -37,6 +38,7 @@ int main(int argc, char ** argv) { int i; FILE * outfile = NULL; char * outfilename = NULL; + char * reset_outfilename = NULL; int opt; int ignore_loop = 0; int force_loop = 0; @@ -50,7 +52,7 @@ int main(int argc, char ** argv) { double fade_seconds = 10.0; double fade_delay_seconds = 0.0; - while ((opt = getopt(argc, argv, "o:l:f:d:ipPcmxeE")) != -1) { + while ((opt = getopt(argc, argv, "o:l:f:d:ipPcmxeEr:")) != -1) { switch (opt) { case 'o': outfilename = optarg; @@ -89,6 +91,9 @@ int main(int argc, char ** argv) { case 'E': really_force_loop = 1; break; + case 'r': + reset_outfilename = optarg; + break; default: usage(argv[0]); return 1; @@ -161,7 +166,7 @@ int main(int argc, char ** argv) { if (!outfilename) outfilename = "dump.wav"; outfile = fopen(outfilename,"wb"); if (!outfile) { - fprintf(stderr,"failed to open %s for output\n",optarg); + fprintf(stderr,"failed to open %s for output\n",outfilename); return 1; } } @@ -229,7 +234,45 @@ int main(int argc, char ** argv) { } fwrite(buf,sizeof(sample)*s->channels,toget,outfile); } - + + fclose(outfile); outfile = NULL; + + if (reset_outfilename) { + outfile = fopen(reset_outfilename,"wb"); + if (!outfile) { + fprintf(stderr,"failed to open %s for output\n",reset_outfilename); + return 1; + } + /* slap on a .wav header */ + make_wav_header((uint8_t*)buf, len, s->sample_rate, s->channels); + fwrite(buf,1,0x2c,outfile); + + reset_vgmstream(s); + /* decode */ + for (i=0;ilen) toget=len-i; + render_vgmstream(buf,toget,s); + + 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 0) { + double fadedness = (double)(fade_samples-samples_into_fade)/fade_samples; + for (k=0;kchannels;k++) { + buf[j*s->channels+k] = buf[j*s->channels+k]*fadedness; + } + } + } + } + } + fwrite(buf,sizeof(sample)*s->channels,toget,outfile); + } + fclose(outfile); outfile = NULL; + } + close_vgmstream(s); return 0; diff --git a/winamp/in_vgmstream.c b/winamp/in_vgmstream.c index 97719ed8..c3441df7 100644 --- a/winamp/in_vgmstream.c +++ b/winamp/in_vgmstream.c @@ -397,32 +397,19 @@ DWORD WINAPI __stdcall decode(void *arg) { if (seek_needed_samples != -1) { /* reset if we need to seek backwards */ if (seek_needed_samples < decode_pos_samples) { - VGMSTREAM * new_temp; - VGMSTREAM * old_temp; - - new_temp = init_vgmstream(lastfn); - if (!new_temp) { - PostMessage(input_module.hMainWindow, /* message dest */ - WM_WA_MPEG_EOF, /* message id */ - 0,0); /* no parameters */ - return 0; - } - if (ignore_loop) - new_temp->loop_flag = 0; - - old_temp = vgmstream; - vgmstream = new_temp; - - close_vgmstream(old_temp); + reset_vgmstream(vgmstream); decode_pos_samples = 0; decode_pos_ms = 0; } + if (decode_pos_samples < seek_needed_samples) { samples_to_do=seek_needed_samples-decode_pos_samples; if (samples_to_do>576) samples_to_do=576; } else seek_needed_samples = -1; + + input_module.outMod->Flush((int)decode_pos_ms); } l = (samples_to_do*vgmstream->channels*2)<<(input_module.dsp_isactive()?1:0); @@ -439,7 +426,6 @@ DWORD WINAPI __stdcall decode(void *arg) { } else if (seek_needed_samples != -1) { render_vgmstream(sample_buffer,samples_to_do,vgmstream); - input_module.outMod->Flush((int)decode_pos_ms); decode_pos_samples+=samples_to_do; decode_pos_ms=decode_pos_samples*1000LL/vgmstream->sample_rate;