diff options
Diffstat (limited to 'apps/codecs')
-rw-r--r-- | apps/codecs/ape.c | 192 | ||||
-rw-r--r-- | apps/codecs/demac/libdemac/Makefile | 2 | ||||
-rw-r--r-- | apps/codecs/demac/libdemac/decoder.c | 2 | ||||
-rw-r--r-- | apps/codecs/demac/libdemac/parser.c | 14 | ||||
-rw-r--r-- | apps/codecs/demac/libdemac/parser.h | 7 | ||||
-rw-r--r-- | apps/codecs/demac/libdemac/predictor.c | 2 |
6 files changed, 201 insertions, 18 deletions
diff --git a/apps/codecs/ape.c b/apps/codecs/ape.c index b77abc0c74..0506c0ca49 100644 --- a/apps/codecs/ape.c +++ b/apps/codecs/ape.c @@ -27,6 +27,21 @@ CODEC_HEADER #define MAX_CHANNELS 2 #define MAX_BYTESPERSAMPLE 3 +/* Monkey's Audio files have one seekpoint per frame. The framesize + varies between 73728 and 1179648 samples. + + At the smallest framesize, 30000 frames would be 50155 seconds of + audio - almost 14 hours. This should be enough for any file a user + would want to play in Rockbox, given the 2GB FAT filesize (and 4GB + seektable entry size) limit. + + This means the seektable is 120000 bytes, but we have a lot of + spare room in the codec buffer - the APE codec itself is small. +*/ + +#define MAX_SEEKPOINTS 30000 +static uint32_t seektablebuf[MAX_SEEKPOINTS]; + #define INPUT_CHUNKSIZE (32*1024) /* 4608*4 = 18432 bytes per channel */ @@ -35,6 +50,81 @@ static int32_t decoded1[BLOCKS_PER_LOOP] IBSS_ATTR; #define MAX_SUPPORTED_SEEKTABLE_SIZE 5000 + +/* Given an ape_ctx and a sample to seek to, return the file position + to the frame containing that sample, and the number of samples to + skip in that frame. +*/ + +bool ape_calc_seekpos(struct ape_ctx_t* ape_ctx, + uint32_t new_sample, + uint32_t* newframe, + uint32_t* filepos, + uint32_t* samplestoskip) +{ + uint32_t n; + + n = new_sample / ape_ctx->blocksperframe; + if (n >= ape_ctx->numseekpoints) + { + /* We don't have a seekpoint for that frame */ + return false; + } + + *newframe = n; + *filepos = ape_ctx->seektable[n]; + *samplestoskip = new_sample - (n * ape_ctx->blocksperframe); + + return true; +} + +/* The resume offset is a value in bytes - we need to + turn it into a frame number and samplestoskip value */ + +void ape_resume(struct ape_ctx_t* ape_ctx, size_t resume_offset, + uint32_t* currentframe, uint32_t* samplesdone, + uint32_t* samplestoskip, int* firstbyte) +{ + off_t newfilepos; + int64_t framesize; + int64_t offset; + + *currentframe = 0; + *samplesdone = 0; + *samplestoskip = 0; + + while ((*currentframe < ape_ctx->totalframes) && + (*currentframe < ape_ctx->numseekpoints) && + (resume_offset > ape_ctx->seektable[*currentframe])) + { + ++*currentframe; + *samplesdone += ape_ctx->blocksperframe; + } + + if ((*currentframe > 0) && + (ape_ctx->seektable[*currentframe] > resume_offset)) { + --*currentframe; + *samplesdone -= ape_ctx->blocksperframe; + } + + newfilepos = ape_ctx->seektable[*currentframe]; + + /* APE's bytestream is weird... */ + *firstbyte = 3 - (newfilepos & 3); + newfilepos &= ~3; + + ci->seek_buffer(newfilepos); + + /* We estimate where we were in the current frame, based on the + byte offset */ + if (*currentframe < (ape_ctx->totalframes - 1)) { + framesize = ape_ctx->seektable[*currentframe+1] - ape_ctx->seektable[*currentframe]; + offset = resume_offset - ape_ctx->seektable[*currentframe]; + + *samplestoskip = (offset * ape_ctx->blocksperframe) / framesize; + } +} + /* this is the codec entry point */ enum codec_status codec_main(void) { @@ -45,12 +135,15 @@ enum codec_status codec_main(void) int retval; uint32_t currentframe; + uint32_t newfilepos; + uint32_t samplestoskip; int nblocks; int bytesconsumed; unsigned char* inbuffer; - int blockstodecode; + uint32_t blockstodecode; int res; int firstbyte; + size_t resume_offset; /* Generic codec initialisation */ ci->configure(CODEC_SET_FILEBUF_WATERMARK, 1024*512); @@ -59,6 +152,12 @@ enum codec_status codec_main(void) ci->configure(DSP_SET_SAMPLE_DEPTH, APE_OUTPUT_DEPTH-1); next_track: + + retval = CODEC_OK; + + /* Remember the resume position - when the codec is opened, the + playback engine will reset it. */ + resume_offset = ci->id3->offset; if (codec_init()) { LOGF("APE: Error initialising codec\n"); @@ -74,7 +173,31 @@ enum codec_status codec_main(void) retval = CODEC_ERROR; goto exit; } - ci->advance_buffer(ape_ctx.firstframe); + + /* Initialise the seektable for this file */ + ape_ctx.seektable = seektablebuf; + ape_ctx.numseekpoints = MIN(MAX_SEEKPOINTS,ape_ctx.numseekpoints); + + ci->advance_buffer(ape_ctx.seektablefilepos); + + /* The seektable may be bigger than the guard buffer (32KB), so we + do a read() */ + ci->read_filebuf(ape_ctx.seektable, ape_ctx.numseekpoints * sizeof(uint32_t)); + +#ifdef ROCKBOX_BIG_ENDIAN + /* Byte-swap the little-endian seekpoints */ + { + uint32_t i; + + for(i = 0; i < ape_ctx.numseekpoints; i++) + ape_ctx.seektable[i] = swap32(ape_ctx.seektable[i]); + } +#endif + + /* Now advance the file position to the first frame */ + ci->advance_buffer(ape_ctx.firstframe - + (ape_ctx.seektablefilepos + + ape_ctx.numseekpoints * sizeof(uint32_t))); while (!*ci->taginfo_ready && !ci->stop_codec) ci->sleep(1); @@ -86,16 +209,26 @@ enum codec_status codec_main(void) /* The main decoding loop */ - currentframe = 0; - samplesdone = 0; + if (resume_offset) { + /* The resume offset is a value in bytes - we need to + turn it into a frame number and samplestoskip value */ + + ape_resume(&ape_ctx, resume_offset, + ¤tframe, &samplesdone, &samplestoskip, &firstbyte); + } else { + currentframe = 0; + samplesdone = 0; + samplestoskip = 0; + firstbyte = 3; /* Take account of the little-endian 32-bit byte ordering */ + } /* Initialise the buffer */ inbuffer = ci->request_buffer(&bytesleft, INPUT_CHUNKSIZE); - firstbyte = 3; /* Take account of the little-endian 32-bit byte ordering */ /* The main decoding loop - we decode the frames a small chunk at a time */ while (currentframe < ape_ctx.totalframes) { +frame_start: /* Calculate how many blocks there are in this frame */ if (currentframe == (ape_ctx.totalframes - 1)) nblocks = ape_ctx.finalframeblocks; @@ -115,7 +248,31 @@ enum codec_status codec_main(void) { ci->yield(); if (ci->stop_codec || ci->new_track) { - break; + goto done; + } + + /* Deal with any pending seek requests */ + if (ci->seek_time) + { + if (ape_calc_seekpos(&ape_ctx, + ((ci->seek_time-1)/10) * (ci->id3->frequency/100), + ¤tframe, + &newfilepos, + &samplestoskip)) + { + samplesdone = currentframe * ape_ctx.blocksperframe; + + /* APE's bytestream is weird... */ + firstbyte = 3 - (newfilepos & 3); + newfilepos &= ~3; + + ci->seek_buffer(newfilepos); + inbuffer = ci->request_buffer(&bytesleft, INPUT_CHUNKSIZE); + + ci->seek_complete(); + goto frame_start; /* Sorry... */ + } + ci->seek_complete(); } blockstodecode = MIN(BLOCKS_PER_LOOP, nblocks); @@ -132,12 +289,27 @@ enum codec_status codec_main(void) } ci->yield(); - ci->pcmbuf_insert(decoded0, decoded1, blockstodecode); + + if (samplestoskip > 0) { + if (samplestoskip < blockstodecode) { + ci->pcmbuf_insert(decoded0 + samplestoskip, + decoded1 + samplestoskip, + blockstodecode - samplestoskip); + samplestoskip = 0; + } else { + samplestoskip -= blockstodecode; + } + } else { + ci->pcmbuf_insert(decoded0, decoded1, blockstodecode); + } - /* Update the elapsed-time indicator */ samplesdone += blockstodecode; - elapsedtime = (samplesdone*10)/(ape_ctx.samplerate/100); - ci->set_elapsed(elapsedtime); + + if (!samplestoskip) { + /* Update the elapsed-time indicator */ + elapsedtime = (samplesdone*10)/(ape_ctx.samplerate/100); + ci->set_elapsed(elapsedtime); + } ci->advance_buffer(bytesconsumed); inbuffer = ci->request_buffer(&bytesleft, INPUT_CHUNKSIZE); diff --git a/apps/codecs/demac/libdemac/Makefile b/apps/codecs/demac/libdemac/Makefile index 7fc784dd5f..6ef55d7fb9 100644 --- a/apps/codecs/demac/libdemac/Makefile +++ b/apps/codecs/demac/libdemac/Makefile @@ -4,7 +4,7 @@ # Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < # Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ # \/ \/ \/ \/ \/ -# $Id:$ +# $Id$ # INCLUDES=-I$(APPSDIR) -I.. -I. -I$(FIRMDIR)/include -I$(FIRMDIR)/export \ diff --git a/apps/codecs/demac/libdemac/decoder.c b/apps/codecs/demac/libdemac/decoder.c index 22b6e8d325..ba8c393a67 100644 --- a/apps/codecs/demac/libdemac/decoder.c +++ b/apps/codecs/demac/libdemac/decoder.c @@ -2,7 +2,7 @@ libdemac - A Monkey's Audio decoder -$Id:$ +$Id$ Copyright (C) Dave Chapman 2007 diff --git a/apps/codecs/demac/libdemac/parser.c b/apps/codecs/demac/libdemac/parser.c index 4e907308b6..7e0fd8f250 100644 --- a/apps/codecs/demac/libdemac/parser.c +++ b/apps/codecs/demac/libdemac/parser.c @@ -92,6 +92,10 @@ int ape_parseheaderbuf(unsigned char* buf, struct ape_ctx_t* ape_ctx) ape_ctx->channels = get_uint16(header + 18); ape_ctx->samplerate = get_uint32(header + 20); + ape_ctx->seektablefilepos = ape_ctx->junklength + + ape_ctx->descriptorlength + + ape_ctx->headerlength; + ape_ctx->firstframe = ape_ctx->junklength + ape_ctx->descriptorlength + ape_ctx->headerlength + ape_ctx->seektablelength + ape_ctx->wavheaderlength; @@ -133,15 +137,19 @@ int ape_parseheaderbuf(unsigned char* buf, struct ape_ctx_t* ape_ctx) else ape_ctx->blocksperframe = 9216; - ape_ctx->firstframe = ape_ctx->junklength + ape_ctx->headerlength + - ape_ctx->seektablelength + ape_ctx->wavheaderlength; + ape_ctx->seektablefilepos = ape_ctx->junklength + ape_ctx->headerlength + + ape_ctx->wavheaderlength; + + ape_ctx->firstframe = ape_ctx->junklength + ape_ctx->headerlength + + ape_ctx->wavheaderlength + ape_ctx->seektablelength; } ape_ctx->totalsamples = ape_ctx->finalframeblocks; if (ape_ctx->totalframes > 1) ape_ctx->totalsamples += ape_ctx->blocksperframe * (ape_ctx->totalframes-1); - /* TODO: Parse and store seektable */ + ape_ctx->numseekpoints = MAX(ape_ctx->maxseekpoints, + ape_ctx->seektablelength / sizeof(int32_t)); return 0; } diff --git a/apps/codecs/demac/libdemac/parser.h b/apps/codecs/demac/libdemac/parser.h index edf4222fd5..0e35425315 100644 --- a/apps/codecs/demac/libdemac/parser.h +++ b/apps/codecs/demac/libdemac/parser.h @@ -2,7 +2,7 @@ libdemac - A Monkey's Audio decoder -$Id:$ +$Id$ Copyright (C) Dave Chapman 2007 @@ -119,7 +119,10 @@ struct ape_ctx_t uint32_t samplerate; /* Seektable */ - uint32_t* seektable; + uint32_t* seektable; /* Seektable buffer */ + uint32_t maxseekpoints; /* Max seekpoints we can store (size of seektable buffer) */ + uint32_t numseekpoints; /* Number of seekpoints */ + int seektablefilepos; /* Location in .ape file of seektable */ /* Decoder state */ uint32_t CRC; diff --git a/apps/codecs/demac/libdemac/predictor.c b/apps/codecs/demac/libdemac/predictor.c index ef72fedfbd..9531786fd1 100644 --- a/apps/codecs/demac/libdemac/predictor.c +++ b/apps/codecs/demac/libdemac/predictor.c @@ -2,7 +2,7 @@ libdemac - A Monkey's Audio decoder -$Id:$ +$Id$ Copyright (C) Dave Chapman 2007 |