summaryrefslogtreecommitdiff
path: root/lib/rbcodec/codecs/ape.c
diff options
context:
space:
mode:
authorMichael Sevakis <jethead71@rockbox.org>2013-07-14 07:59:39 -0400
committerMichael Sevakis <jethead71@rockbox.org>2014-03-10 04:12:30 +0100
commit31b712286721dd606940c7b557d03e3f714b9604 (patch)
tree8c4a4cc32e9000ea721ebb23aa3c0129ca97bf53 /lib/rbcodec/codecs/ape.c
parentdda54b85daa83b7803b4fb189ab45859f96ff3f9 (diff)
downloadrockbox-31b712286721dd606940c7b557d03e3f714b9604.tar.gz
rockbox-31b712286721dd606940c7b557d03e3f714b9604.zip
Implement time-based resume and playback start.
This complements offset-based resume and playback start funcionality. The implementation is global on both HWCODEC and SWCODEC. Basically, if either the specified elapsed or offset are non-zero, it indicates a mid-track resume. To resume by time only, set elapsed to nonzero and offset to zero. To resume by offset only, set offset to nonzero and elapsed to zero. Which one the codec uses and which has priority is up to the codec; however, using an elapsed time covers more cases: * Codecs not able to use an offset such as VGM or other atomic formats * Starting playback at a nonzero elapsed time from a source that contains no offset, such as a cuesheet The change re-versions pretty much everything from tagcache to nvram. Change-Id: Ic7aebb24e99a03ae99585c5e236eba960d163f38 Reviewed-on: http://gerrit.rockbox.org/516 Reviewed-by: Michael Sevakis <jethead71@rockbox.org> Tested: Michael Sevakis <jethead71@rockbox.org>
Diffstat (limited to 'lib/rbcodec/codecs/ape.c')
-rw-r--r--lib/rbcodec/codecs/ape.c70
1 files changed, 45 insertions, 25 deletions
diff --git a/lib/rbcodec/codecs/ape.c b/lib/rbcodec/codecs/ape.c
index 577e7b65e2..a6c5254d45 100644
--- a/lib/rbcodec/codecs/ape.c
+++ b/lib/rbcodec/codecs/ape.c
@@ -155,6 +155,7 @@ enum codec_status codec_run(void)
155 int res; 155 int res;
156 int firstbyte; 156 int firstbyte;
157 size_t resume_offset; 157 size_t resume_offset;
158 enum codec_command_action action;
158 intptr_t param; 159 intptr_t param;
159 160
160 if (codec_init()) { 161 if (codec_init()) {
@@ -162,8 +163,12 @@ enum codec_status codec_run(void)
162 return CODEC_ERROR; 163 return CODEC_ERROR;
163 } 164 }
164 165
166 action = CODEC_ACTION_NULL;
167 param = 0;
168
165 /* Remember the resume position - when the codec is opened, the 169 /* Remember the resume position - when the codec is opened, the
166 playback engine will reset it. */ 170 playback engine will reset it. */
171 elapsedtime = ci->id3->elapsed;
167 resume_offset = ci->id3->offset; 172 resume_offset = ci->id3->offset;
168 173
169 ci->seek_buffer(0); 174 ci->seek_buffer(0);
@@ -213,14 +218,21 @@ enum codec_status codec_run(void)
213 218
214 ape_resume(&ape_ctx, resume_offset, 219 ape_resume(&ape_ctx, resume_offset,
215 &currentframe, &samplesdone, &samplestoskip, &firstbyte); 220 &currentframe, &samplesdone, &samplestoskip, &firstbyte);
216 } else { 221 elapsedtime = (samplesdone*10)/(ape_ctx.samplerate/100);
222 }
223 else {
217 currentframe = 0; 224 currentframe = 0;
218 samplesdone = 0; 225 samplesdone = 0;
219 samplestoskip = 0; 226 samplestoskip = 0;
220 firstbyte = 3; /* Take account of the little-endian 32-bit byte ordering */ 227 firstbyte = 3; /* Take account of the little-endian 32-bit byte ordering */
228
229 if (elapsedtime) {
230 /* Resume by simulated seeking */
231 param = elapsedtime;
232 action = CODEC_ACTION_SEEK_TIME;
233 }
221 } 234 }
222 235
223 elapsedtime = (samplesdone*10)/(ape_ctx.samplerate/100);
224 ci->set_elapsed(elapsedtime); 236 ci->set_elapsed(elapsedtime);
225 237
226 /* Initialise the buffer */ 238 /* Initialise the buffer */
@@ -247,36 +259,44 @@ frame_start:
247 /* Decode the frame a chunk at a time */ 259 /* Decode the frame a chunk at a time */
248 while (nblocks > 0) 260 while (nblocks > 0)
249 { 261 {
250 enum codec_command_action action = ci->get_command(&param); 262 if (action == CODEC_ACTION_NULL)
263 action = ci->get_command(&param);
251 264
252 if (action == CODEC_ACTION_HALT) 265 if (action != CODEC_ACTION_NULL) {
253 goto done; 266 if (action == CODEC_ACTION_HALT)
267 goto done;
254 268
255 /* Deal with any pending seek requests */ 269 /* Deal with any pending seek requests */
256 if (action == CODEC_ACTION_SEEK_TIME) 270 if (action == CODEC_ACTION_SEEK_TIME)
257 {
258 if (ape_calc_seekpos(&ape_ctx,
259 (param/10) * (ci->id3->frequency/100),
260 &currentframe,
261 &newfilepos,
262 &samplestoskip))
263 { 271 {
264 samplesdone = currentframe * ape_ctx.blocksperframe; 272 if (ape_calc_seekpos(&ape_ctx,
265 273 (param/10) * (ci->id3->frequency/100),
266 /* APE's bytestream is weird... */ 274 &currentframe,
267 firstbyte = 3 - (newfilepos & 3); 275 &newfilepos,
268 newfilepos &= ~3; 276 &samplestoskip))
269 277 {
270 ci->seek_buffer(newfilepos); 278 samplesdone = currentframe * ape_ctx.blocksperframe;
271 inbuffer = ci->request_buffer(&bytesleft, INPUT_CHUNKSIZE); 279
280 /* APE's bytestream is weird... */
281 firstbyte = 3 - (newfilepos & 3);
282 newfilepos &= ~3;
283
284 ci->seek_buffer(newfilepos);
285 inbuffer = ci->request_buffer(&bytesleft,
286 INPUT_CHUNKSIZE);
287
288 elapsedtime = (samplesdone*10)/
289 (ape_ctx.samplerate/100);
290 ci->set_elapsed(elapsedtime);
291 ci->seek_complete();
292 action = CODEC_ACTION_NULL;
293 goto frame_start; /* Sorry... */
294 }
272 295
273 elapsedtime = (samplesdone*10)/(ape_ctx.samplerate/100);
274 ci->set_elapsed(elapsedtime);
275 ci->seek_complete(); 296 ci->seek_complete();
276 goto frame_start; /* Sorry... */
277 } 297 }
278 298
279 ci->seek_complete(); 299 action = CODEC_ACTION_NULL;
280 } 300 }
281 301
282 blockstodecode = MIN(BLOCKS_PER_LOOP, nblocks); 302 blockstodecode = MIN(BLOCKS_PER_LOOP, nblocks);