From 7a3822c8b03a5438a1bcfd6e38c0e6860dda3348 Mon Sep 17 00:00:00 2001 From: Yoshihisa Uchida Date: Mon, 22 Mar 2010 10:02:05 +0000 Subject: fix bug: WAV file playback does not resume (FS#11077) Not only WAV but also Sun audio, SMAF, vox and WAV64 can resume. git-svn-id: svn://svn.rockbox.org/rockbox/trunk@25289 a1c6a512-1295-4272-9138-f99709370657 --- apps/codecs/aiff.c | 28 +++++++++++++++++++++---- apps/codecs/au.c | 27 +++++++++++++++++++++--- apps/codecs/libpcm/dialogic_oki_adpcm.c | 20 +++++++++--------- apps/codecs/libpcm/dvi_adpcm.c | 8 ++++--- apps/codecs/libpcm/ieee_float.c | 8 ++++--- apps/codecs/libpcm/itut_g711.c | 8 ++++--- apps/codecs/libpcm/linear_pcm.c | 8 ++++--- apps/codecs/libpcm/ms_adpcm.c | 8 ++++--- apps/codecs/libpcm/pcm_common.h | 13 +++++++++--- apps/codecs/libpcm/qt_ima_adpcm.c | 8 ++++--- apps/codecs/libpcm/swf_adpcm.c | 15 ++++++------- apps/codecs/libpcm/yamaha_adpcm.c | 11 +++++----- apps/codecs/smaf.c | 25 +++++++++++++++++++++- apps/codecs/vox.c | 37 +++++++++++++++++++++++++-------- apps/codecs/wav.c | 16 ++++++++++---- apps/codecs/wav64.c | 16 ++++++++++---- apps/metadata/vox.c | 1 + 17 files changed, 188 insertions(+), 69 deletions(-) (limited to 'apps') diff --git a/apps/codecs/aiff.c b/apps/codecs/aiff.c index 62d79ac340..4e16788e06 100644 --- a/apps/codecs/aiff.c +++ b/apps/codecs/aiff.c @@ -100,6 +100,9 @@ next_track: codec_set_replaygain(ci->id3); + /* Need to save offset for later use (cleared indirectly by advance_buffer) */ + bytesdone = ci->id3->offset; + /* assume the AIFF header is less than 1024 bytes */ buf = ci->request_buffer(&n, 1024); if (n < 54) { @@ -279,9 +282,26 @@ next_track: firstblockposn = 1024 - n; ci->advance_buffer(firstblockposn); + /* make sure we're at the correct offset */ + if (bytesdone > (uint32_t) firstblockposn) { + /* Round down to previous block */ + struct pcm_pos *newpos = codec->get_seek_pos(bytesdone - firstblockposn, + PCM_SEEK_POS, NULL); + + if (newpos->pos > format.numbytes) + goto done; + if (ci->seek_buffer(firstblockposn + newpos->pos)) + { + bytesdone = newpos->pos; + decodedsamples = newpos->samples; + } + ci->seek_complete(); + } else { + /* already where we need to be */ + bytesdone = 0; + } + /* The main decoder loop */ - bytesdone = 0; - ci->set_elapsed(0); endofstream = 0; while (!endofstream) { @@ -290,8 +310,8 @@ next_track: break; if (ci->seek_time) { - /* 2nd args(read_buffer) is unnecessary in the format which AIFF supports. */ - struct pcm_pos *newpos = codec->get_seek_pos(ci->seek_time, NULL); + /* 3rd args(read_buffer) is unnecessary in the format which AIFF supports. */ + struct pcm_pos *newpos = codec->get_seek_pos(ci->seek_time, PCM_SEEK_TIME, NULL); if (newpos->pos > format.numbytes) break; diff --git a/apps/codecs/au.c b/apps/codecs/au.c index 19348bc299..1e6af25924 100644 --- a/apps/codecs/au.c +++ b/apps/codecs/au.c @@ -135,6 +135,9 @@ next_track: codec_set_replaygain(ci->id3); + /* Need to save offset for later use (cleared indirectly by advance_buffer) */ + bytesdone = ci->id3->offset; + ci->memset(&format, 0, sizeof(struct pcm_format)); format.is_signed = true; format.is_little_endian = false; @@ -191,7 +194,6 @@ next_track: decodedsamples = 0; codec = 0; - bytesdone = 0; /* get codec */ codec = get_au_codec(format.formattag); @@ -236,6 +238,25 @@ next_track: goto done; } + /* make sure we're at the correct offset */ + if (bytesdone > (uint32_t) firstblockposn) { + /* Round down to previous block */ + struct pcm_pos *newpos = codec->get_seek_pos(bytesdone - firstblockposn, + PCM_SEEK_POS, NULL); + + if (newpos->pos > format.numbytes) + goto done; + if (ci->seek_buffer(firstblockposn + newpos->pos)) + { + bytesdone = newpos->pos; + decodedsamples = newpos->samples; + } + ci->seek_complete(); + } else { + /* already where we need to be */ + bytesdone = 0; + } + /* The main decoder loop */ endofstream = 0; @@ -246,8 +267,8 @@ next_track: } if (ci->seek_time) { - /* 2nd args(read_buffer) is unnecessary in the format which Sun Audio supports. */ - struct pcm_pos *newpos = codec->get_seek_pos(ci->seek_time, NULL); + /* 3rd args(read_buffer) is unnecessary in the format which Sun Audio supports. */ + struct pcm_pos *newpos = codec->get_seek_pos(ci->seek_time, PCM_SEEK_TIME, NULL); if (newpos->pos > format.numbytes) break; diff --git a/apps/codecs/libpcm/dialogic_oki_adpcm.c b/apps/codecs/libpcm/dialogic_oki_adpcm.c index 62d092e677..4a6465f196 100644 --- a/apps/codecs/libpcm/dialogic_oki_adpcm.c +++ b/apps/codecs/libpcm/dialogic_oki_adpcm.c @@ -44,6 +44,7 @@ static const int index_table[] ICONST_ATTR = { }; static struct adpcm_data cur_data; +static int blocksperchunk; static struct pcm_format *fmt; @@ -71,7 +72,8 @@ static bool set_format(struct pcm_format *format) fmt->samplesperblock = 2; /* chunksize = about 1/32[sec] data */ - fmt->chunksize = ci->id3->frequency >> 6; + blocksperchunk = ci->id3->frequency >> 6; + fmt->chunksize = blocksperchunk * fmt->blockalign; max_chunk_count = (uint64_t)ci->id3->length * ci->id3->frequency / (2000LL * fmt->chunksize); @@ -146,20 +148,18 @@ static int decode_for_seek(const uint8_t *inbuf, size_t inbufsize) return CODEC_OK; } -static struct pcm_pos *get_seek_pos(long seek_time, +static struct pcm_pos *get_seek_pos(uint32_t seek_val, int seek_mode, uint8_t *(*read_buffer)(size_t *realsize)) { static struct pcm_pos newpos; - uint32_t seek_count = 0; - uint32_t new_count; + uint32_t seek_count = (seek_mode == PCM_SEEK_TIME)? + ((uint64_t)seek_val * ci->id3->frequency / 1000LL) + / (blocksperchunk * fmt->samplesperblock) : + seek_val / fmt->chunksize; + uint32_t new_count = seek(seek_count, &cur_data, read_buffer, &decode_for_seek); - if (seek_time > 0) - seek_count = (uint64_t)seek_time * ci->id3->frequency - / (2000LL * fmt->chunksize); - - new_count = seek(seek_count, &cur_data, read_buffer, &decode_for_seek); newpos.pos = new_count * fmt->chunksize; - newpos.samples = (newpos.pos / fmt->blockalign) * fmt->samplesperblock; + newpos.samples = new_count * blocksperchunk * fmt->samplesperblock; return &newpos; } diff --git a/apps/codecs/libpcm/dvi_adpcm.c b/apps/codecs/libpcm/dvi_adpcm.c index 2784b21786..2e702ca394 100644 --- a/apps/codecs/libpcm/dvi_adpcm.c +++ b/apps/codecs/libpcm/dvi_adpcm.c @@ -54,12 +54,14 @@ static bool set_format(struct pcm_format *format) return true; } -static struct pcm_pos *get_seek_pos(long seek_time, +static struct pcm_pos *get_seek_pos(uint32_t seek_val, int seek_mode, uint8_t *(*read_buffer)(size_t *realsize)) { static struct pcm_pos newpos; - uint32_t newblock = ((uint64_t)seek_time * ci->id3->frequency) - / (1000LL * fmt->samplesperblock); + uint32_t newblock = (seek_mode == PCM_SEEK_TIME) ? + ((uint64_t)seek_val * ci->id3->frequency / 1000LL) + / fmt->samplesperblock : + seek_val / fmt->blockalign; (void)read_buffer; newpos.pos = newblock * fmt->blockalign; diff --git a/apps/codecs/libpcm/ieee_float.c b/apps/codecs/libpcm/ieee_float.c index 7e3498edcb..639390bcd5 100644 --- a/apps/codecs/libpcm/ieee_float.c +++ b/apps/codecs/libpcm/ieee_float.c @@ -59,12 +59,14 @@ static bool set_format(struct pcm_format *format) return true; } -static struct pcm_pos *get_seek_pos(long seek_time, +static struct pcm_pos *get_seek_pos(uint32_t seek_val, int seek_mode, uint8_t *(*read_buffer)(size_t *realsize)) { static struct pcm_pos newpos; - uint32_t newblock = ((uint64_t)seek_time * ci->id3->frequency) - / (1000LL * fmt->samplesperblock); + uint32_t newblock = (seek_mode == PCM_SEEK_TIME) ? + ((uint64_t)seek_val * ci->id3->frequency / 1000LL) + / fmt->samplesperblock : + seek_val / fmt->blockalign; (void)read_buffer; newpos.pos = newblock * fmt->blockalign; diff --git a/apps/codecs/libpcm/itut_g711.c b/apps/codecs/libpcm/itut_g711.c index 097dd5cc25..88ff5f59e6 100644 --- a/apps/codecs/libpcm/itut_g711.c +++ b/apps/codecs/libpcm/itut_g711.c @@ -139,12 +139,14 @@ static bool set_format(struct pcm_format *format) return true; } -static struct pcm_pos *get_seek_pos(long seek_time, +static struct pcm_pos *get_seek_pos(uint32_t seek_val, int seek_mode, uint8_t *(*read_buffer)(size_t *realsize)) { static struct pcm_pos newpos; - uint32_t newblock = ((uint64_t)seek_time * ci->id3->frequency) - / (1000LL * fmt->samplesperblock); + uint32_t newblock = (seek_mode == PCM_SEEK_TIME) ? + ((uint64_t)seek_val * ci->id3->frequency / 1000LL) + / fmt->samplesperblock : + seek_val / fmt->blockalign; (void)read_buffer; newpos.pos = newblock * fmt->blockalign; diff --git a/apps/codecs/libpcm/linear_pcm.c b/apps/codecs/libpcm/linear_pcm.c index e58856efe8..5c3c140b8c 100644 --- a/apps/codecs/libpcm/linear_pcm.c +++ b/apps/codecs/libpcm/linear_pcm.c @@ -71,12 +71,14 @@ static bool set_format(struct pcm_format *format) return true; } -static struct pcm_pos *get_seek_pos(long seek_time, +static struct pcm_pos *get_seek_pos(uint32_t seek_val, int seek_mode, uint8_t *(*read_buffer)(size_t *realsize)) { static struct pcm_pos newpos; - uint32_t newblock = ((uint64_t)seek_time * ci->id3->frequency) - / (1000LL * fmt->samplesperblock); + uint32_t newblock = (seek_mode == PCM_SEEK_TIME) ? + ((uint64_t)seek_val * ci->id3->frequency / 1000LL) + / fmt->samplesperblock : + seek_val / fmt->blockalign; (void)read_buffer; newpos.pos = newblock * fmt->blockalign; diff --git a/apps/codecs/libpcm/ms_adpcm.c b/apps/codecs/libpcm/ms_adpcm.c index 79365807ef..a385d6c99f 100644 --- a/apps/codecs/libpcm/ms_adpcm.c +++ b/apps/codecs/libpcm/ms_adpcm.c @@ -60,12 +60,14 @@ static bool set_format(struct pcm_format *format) return true; } -static struct pcm_pos *get_seek_pos(long seek_time, +static struct pcm_pos *get_seek_pos(uint32_t seek_val, int seek_mode, uint8_t *(*read_buffer)(size_t *realsize)) { static struct pcm_pos newpos; - uint32_t newblock = ((uint64_t)seek_time * ci->id3->frequency) - / (1000LL * fmt->samplesperblock); + uint32_t newblock = (seek_mode == PCM_SEEK_TIME) ? + ((uint64_t)seek_val * ci->id3->frequency / 1000LL) + / fmt->samplesperblock : + seek_val / fmt->blockalign; (void)read_buffer; newpos.pos = newblock * fmt->blockalign; diff --git a/apps/codecs/libpcm/pcm_common.h b/apps/codecs/libpcm/pcm_common.h index 412ffbce0b..91c3ab7f1e 100644 --- a/apps/codecs/libpcm/pcm_common.h +++ b/apps/codecs/libpcm/pcm_common.h @@ -124,6 +124,9 @@ struct pcm_pos { uint32_t samples; }; +#define PCM_SEEK_TIME 0 +#define PCM_SEEK_POS 1 + struct pcm_codec { /* * sets the format speciffic RIFF/AIFF header information and checks the pcm_format. @@ -140,8 +143,12 @@ struct pcm_codec { /* * get seek position * - * [In] seek_time - * seek time [ms] + * [In] seek_val + * seek time [ms] or seek position + * + * [In] seek_mode + * if seek_mode sets PCM_SEEK_TIME, then seek_val means the seek time. + * if seek_mode sets PCM_SEEK_POS, then seek_val means the seek position. * * [In] read_buffer * the function which reads the data from the file (chunksize bytes read). @@ -149,7 +156,7 @@ struct pcm_codec { * return * position after the seeking. */ - struct pcm_pos *(*get_seek_pos)(long seek_time, + struct pcm_pos *(*get_seek_pos)(uint32_t seek_val, int seek_mode, uint8_t *(*read_buffer)(size_t *realsize)); /* diff --git a/apps/codecs/libpcm/qt_ima_adpcm.c b/apps/codecs/libpcm/qt_ima_adpcm.c index 003de22dd8..d7b3360eb3 100644 --- a/apps/codecs/libpcm/qt_ima_adpcm.c +++ b/apps/codecs/libpcm/qt_ima_adpcm.c @@ -57,12 +57,14 @@ static bool set_format(struct pcm_format *format) return true; } -static struct pcm_pos *get_seek_pos(long seek_time, +static struct pcm_pos *get_seek_pos(uint32_t seek_val, int seek_mode, uint8_t *(*read_buffer)(size_t *realsize)) { static struct pcm_pos newpos; - uint32_t newblock = ((uint64_t)seek_time * ci->id3->frequency) - / (1000LL * fmt->samplesperblock); + uint32_t newblock = (seek_mode == PCM_SEEK_TIME) ? + ((uint64_t)seek_val * ci->id3->frequency / 1000LL) + / fmt->samplesperblock : + seek_val / fmt->blockalign; (void)read_buffer; newpos.pos = newblock * fmt->blockalign; diff --git a/apps/codecs/libpcm/swf_adpcm.c b/apps/codecs/libpcm/swf_adpcm.c index ebc4328c59..c440fd1303 100644 --- a/apps/codecs/libpcm/swf_adpcm.c +++ b/apps/codecs/libpcm/swf_adpcm.c @@ -81,20 +81,21 @@ static bool set_format(struct pcm_format *format) return true; } -static struct pcm_pos *get_seek_pos(long seek_time, +static struct pcm_pos *get_seek_pos(uint32_t seek_val, int seek_mode, uint8_t *(*read_buffer)(size_t *realsize)) { static struct pcm_pos newpos; - uint32_t chunkbits = blockbits; - uint32_t seekbits = (((uint64_t)seek_time * ci->id3->frequency) - / (1000LL * fmt->samplesperblock)) * blockbits + 2; + uint32_t chunkbits = blockbits; + uint32_t seekblocks = (seek_mode == PCM_SEEK_TIME)? + ((uint64_t)seek_val * ci->id3->frequency) + / (1000LL * fmt->samplesperblock) : + ((seek_val << 3) - 2) / blockbits; + uint32_t seekbits = seekblocks * blockbits + 2; (void)read_buffer; newpos.pos = seekbits >> 3; - newpos.samples = (((uint64_t)seek_time * ci->id3->frequency) - / (1000LL * fmt->samplesperblock)) - * fmt->samplesperblock; + newpos.samples = seekblocks * fmt->samplesperblock; if (newpos.pos == 0) { diff --git a/apps/codecs/libpcm/yamaha_adpcm.c b/apps/codecs/libpcm/yamaha_adpcm.c index 0b997ad776..f1fb9b68ae 100644 --- a/apps/codecs/libpcm/yamaha_adpcm.c +++ b/apps/codecs/libpcm/yamaha_adpcm.c @@ -214,15 +214,14 @@ static int decode_for_seek(const uint8_t *inbuf, size_t inbufsize) return CODEC_OK; } -static struct pcm_pos *get_seek_pos(long seek_time, +static struct pcm_pos *get_seek_pos(uint32_t seek_val, int seek_mode, uint8_t *(*read_buffer)(size_t *realsize)) { static struct pcm_pos newpos; - uint32_t new_count= 0; - - if (seek_time > 0) - new_count = ((uint64_t)seek_time * ci->id3->frequency - / (1000LL * fmt->samplesperblock)) / blocksperchunk; + uint32_t new_count = (seek_mode == PCM_SEEK_TIME)? + ((uint64_t)seek_val * ci->id3->frequency / 1000LL) + / (blocksperchunk * fmt->samplesperblock) : + seek_val / fmt->chunksize; if (!has_block_header) { diff --git a/apps/codecs/smaf.c b/apps/codecs/smaf.c index 33a2a4b403..6763e95001 100644 --- a/apps/codecs/smaf.c +++ b/apps/codecs/smaf.c @@ -409,6 +409,28 @@ next_track: ci->seek_buffer(firstblockposn); ci->seek_complete(); + /* make sure we're at the correct offset */ + if (bytesdone > (uint32_t) firstblockposn) + { + /* Round down to previous block */ + struct pcm_pos *newpos = codec->get_seek_pos(bytesdone - firstblockposn, + PCM_SEEK_POS, &read_buffer); + + if (newpos->pos > format.numbytes) + goto done; + if (ci->seek_buffer(firstblockposn + newpos->pos)) + { + bytesdone = newpos->pos; + decodedsamples = newpos->samples; + } + ci->seek_complete(); + } + else + { + /* already where we need to be */ + bytesdone = 0; + } + /* The main decoder loop */ endofstream = 0; @@ -418,7 +440,8 @@ next_track: break; if (ci->seek_time) { - struct pcm_pos *newpos = codec->get_seek_pos(ci->seek_time, &read_buffer); + struct pcm_pos *newpos = codec->get_seek_pos(ci->seek_time, PCM_SEEK_TIME, + &read_buffer); if (newpos->pos > format.numbytes) break; diff --git a/apps/codecs/vox.c b/apps/codecs/vox.c index 21742e16d9..ff5d571e8d 100644 --- a/apps/codecs/vox.c +++ b/apps/codecs/vox.c @@ -52,9 +52,8 @@ enum codec_status codec_main(void) int bufcount; int endofstream; uint8_t *voxbuf; - off_t firstblockposn; /* position of the first block in file */ + off_t firstblockposn = 0; /* position of the first block in file */ const struct pcm_codec *codec; - int offset = 0; /* Generic codec initialisation */ ci->configure(DSP_SET_SAMPLE_DEPTH, PCM_OUTPUT_DEPTH-1); @@ -70,7 +69,10 @@ next_track: ci->sleep(1); codec_set_replaygain(ci->id3); - + + /* Need to save offset for later use (cleared indirectly by advance_buffer) */ + bytesdone = ci->id3->offset; + ci->memset(&format, 0, sizeof(struct pcm_format)); /* set format */ @@ -80,12 +82,9 @@ next_track: format.blockalign = 1; /* advance to first WAVE chunk */ - ci->advance_buffer(offset); - - firstblockposn = offset; - + firstblockposn = 0; decodedsamples = 0; - bytesdone = 0; + ci->advance_buffer(firstblockposn); /* * get codec @@ -124,6 +123,25 @@ next_track: ci->configure(DSP_SWITCH_FREQUENCY, ci->id3->frequency); ci->configure(DSP_SET_STEREO_MODE, STEREO_MONO); + /* make sure we're at the correct offset */ + if (bytesdone > (uint32_t) firstblockposn) { + /* Round down to previous block */ + struct pcm_pos *newpos = codec->get_seek_pos(bytesdone - firstblockposn, + PCM_SEEK_POS, &read_buffer); + + if (newpos->pos > format.numbytes) + goto done; + if (ci->seek_buffer(firstblockposn + newpos->pos)) + { + bytesdone = newpos->pos; + decodedsamples = newpos->samples; + } + ci->seek_complete(); + } else { + /* already where we need to be */ + bytesdone = 0; + } + /* The main decoder loop */ endofstream = 0; @@ -134,7 +152,8 @@ next_track: } if (ci->seek_time) { - struct pcm_pos *newpos = codec->get_seek_pos(ci->seek_time, &read_buffer); + struct pcm_pos *newpos = codec->get_seek_pos(ci->seek_time, PCM_SEEK_TIME, + &read_buffer); if (newpos->pos > format.numbytes) break; diff --git a/apps/codecs/wav.c b/apps/codecs/wav.c index 14d7136592..e286f4dc6a 100644 --- a/apps/codecs/wav.c +++ b/apps/codecs/wav.c @@ -374,10 +374,17 @@ next_track: /* make sure we're at the correct offset */ if (bytesdone > (uint32_t) firstblockposn) { /* Round down to previous block */ - uint32_t offset = bytesdone - bytesdone % format.blockalign; + struct pcm_pos *newpos = codec->get_seek_pos(bytesdone - firstblockposn, + PCM_SEEK_POS, &read_buffer); - ci->advance_buffer(offset-firstblockposn); - bytesdone = offset - firstblockposn; + if (newpos->pos > format.numbytes) + goto done; + if (ci->seek_buffer(firstblockposn + newpos->pos)) + { + bytesdone = newpos->pos; + decodedsamples = newpos->samples; + } + ci->seek_complete(); } else { /* already where we need to be */ bytesdone = 0; @@ -393,7 +400,8 @@ next_track: } if (ci->seek_time) { - struct pcm_pos *newpos = codec->get_seek_pos(ci->seek_time, &read_buffer); + struct pcm_pos *newpos = codec->get_seek_pos(ci->seek_time, PCM_SEEK_TIME, + &read_buffer); if (newpos->pos > format.numbytes) break; diff --git a/apps/codecs/wav64.c b/apps/codecs/wav64.c index 1913dafe5c..c06f78c802 100644 --- a/apps/codecs/wav64.c +++ b/apps/codecs/wav64.c @@ -380,10 +380,17 @@ next_track: /* make sure we're at the correct offset */ if (bytesdone > (uint32_t) firstblockposn) { /* Round down to previous block */ - uint32_t offset = bytesdone - bytesdone % format.blockalign; + struct pcm_pos *newpos = codec->get_seek_pos(bytesdone - firstblockposn, + PCM_SEEK_POS, &read_buffer); - ci->advance_buffer(offset-firstblockposn); - bytesdone = offset - firstblockposn; + if (newpos->pos > format.numbytes) + goto done; + if (ci->seek_buffer(firstblockposn + newpos->pos)) + { + bytesdone = newpos->pos; + decodedsamples = newpos->samples; + } + ci->seek_complete(); } else { /* already where we need to be */ bytesdone = 0; @@ -399,7 +406,8 @@ next_track: } if (ci->seek_time) { - struct pcm_pos *newpos = codec->get_seek_pos(ci->seek_time, &read_buffer); + struct pcm_pos *newpos = codec->get_seek_pos(ci->seek_time, PCM_SEEK_TIME, + &read_buffer); if (newpos->pos > format.numbytes) break; diff --git a/apps/metadata/vox.c b/apps/metadata/vox.c index 3f4e5d553c..f6bc849a88 100644 --- a/apps/metadata/vox.c +++ b/apps/metadata/vox.c @@ -40,6 +40,7 @@ bool get_vox_metadata(int fd, struct mp3entry* id3) * bitspersample: 4 */ id3->frequency = 8000; + id3->bitrate = 8000 * 4 / 1000; id3->vbr = false; /* All VOX files are CBR */ id3->filesize = filesize(fd); id3->length = id3->filesize >> 2; -- cgit