summaryrefslogtreecommitdiff
path: root/apps
diff options
context:
space:
mode:
Diffstat (limited to 'apps')
-rw-r--r--apps/codecs/ape.c192
-rw-r--r--apps/codecs/demac/libdemac/Makefile2
-rw-r--r--apps/codecs/demac/libdemac/decoder.c2
-rw-r--r--apps/codecs/demac/libdemac/parser.c14
-rw-r--r--apps/codecs/demac/libdemac/parser.h7
-rw-r--r--apps/codecs/demac/libdemac/predictor.c2
-rw-r--r--apps/playback.c1
7 files changed, 202 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
27#define MAX_CHANNELS 2 27#define MAX_CHANNELS 2
28#define MAX_BYTESPERSAMPLE 3 28#define MAX_BYTESPERSAMPLE 3
29 29
30/* Monkey's Audio files have one seekpoint per frame. The framesize
31 varies between 73728 and 1179648 samples.
32
33 At the smallest framesize, 30000 frames would be 50155 seconds of
34 audio - almost 14 hours. This should be enough for any file a user
35 would want to play in Rockbox, given the 2GB FAT filesize (and 4GB
36 seektable entry size) limit.
37
38 This means the seektable is 120000 bytes, but we have a lot of
39 spare room in the codec buffer - the APE codec itself is small.
40*/
41
42#define MAX_SEEKPOINTS 30000
43static uint32_t seektablebuf[MAX_SEEKPOINTS];
44
30#define INPUT_CHUNKSIZE (32*1024) 45#define INPUT_CHUNKSIZE (32*1024)
31 46
32/* 4608*4 = 18432 bytes per channel */ 47/* 4608*4 = 18432 bytes per channel */
@@ -35,6 +50,81 @@ static int32_t decoded1[BLOCKS_PER_LOOP] IBSS_ATTR;
35 50
36#define MAX_SUPPORTED_SEEKTABLE_SIZE 5000 51#define MAX_SUPPORTED_SEEKTABLE_SIZE 5000
37 52
53
54/* Given an ape_ctx and a sample to seek to, return the file position
55 to the frame containing that sample, and the number of samples to
56 skip in that frame.
57*/
58
59bool ape_calc_seekpos(struct ape_ctx_t* ape_ctx,
60 uint32_t new_sample,
61 uint32_t* newframe,
62 uint32_t* filepos,
63 uint32_t* samplestoskip)
64{
65 uint32_t n;
66
67 n = new_sample / ape_ctx->blocksperframe;
68 if (n >= ape_ctx->numseekpoints)
69 {
70 /* We don't have a seekpoint for that frame */
71 return false;
72 }
73
74 *newframe = n;
75 *filepos = ape_ctx->seektable[n];
76 *samplestoskip = new_sample - (n * ape_ctx->blocksperframe);
77
78 return true;
79}
80
81/* The resume offset is a value in bytes - we need to
82 turn it into a frame number and samplestoskip value */
83
84void ape_resume(struct ape_ctx_t* ape_ctx, size_t resume_offset,
85 uint32_t* currentframe, uint32_t* samplesdone,
86 uint32_t* samplestoskip, int* firstbyte)
87{
88 off_t newfilepos;
89 int64_t framesize;
90 int64_t offset;
91
92 *currentframe = 0;
93 *samplesdone = 0;
94 *samplestoskip = 0;
95
96 while ((*currentframe < ape_ctx->totalframes) &&
97 (*currentframe < ape_ctx->numseekpoints) &&
98 (resume_offset > ape_ctx->seektable[*currentframe]))
99 {
100 ++*currentframe;
101 *samplesdone += ape_ctx->blocksperframe;
102 }
103
104 if ((*currentframe > 0) &&
105 (ape_ctx->seektable[*currentframe] > resume_offset)) {
106 --*currentframe;
107 *samplesdone -= ape_ctx->blocksperframe;
108 }
109
110 newfilepos = ape_ctx->seektable[*currentframe];
111
112 /* APE's bytestream is weird... */
113 *firstbyte = 3 - (newfilepos & 3);
114 newfilepos &= ~3;
115
116 ci->seek_buffer(newfilepos);
117
118 /* We estimate where we were in the current frame, based on the
119 byte offset */
120 if (*currentframe < (ape_ctx->totalframes - 1)) {
121 framesize = ape_ctx->seektable[*currentframe+1] - ape_ctx->seektable[*currentframe];
122 offset = resume_offset - ape_ctx->seektable[*currentframe];
123
124 *samplestoskip = (offset * ape_ctx->blocksperframe) / framesize;
125 }
126}
127
38/* this is the codec entry point */ 128/* this is the codec entry point */
39enum codec_status codec_main(void) 129enum codec_status codec_main(void)
40{ 130{
@@ -45,12 +135,15 @@ enum codec_status codec_main(void)
45 int retval; 135 int retval;
46 136
47 uint32_t currentframe; 137 uint32_t currentframe;
138 uint32_t newfilepos;
139 uint32_t samplestoskip;
48 int nblocks; 140 int nblocks;
49 int bytesconsumed; 141 int bytesconsumed;
50 unsigned char* inbuffer; 142 unsigned char* inbuffer;
51 int blockstodecode; 143 uint32_t blockstodecode;
52 int res; 144 int res;
53 int firstbyte; 145 int firstbyte;
146 size_t resume_offset;
54 147
55 /* Generic codec initialisation */ 148 /* Generic codec initialisation */
56 ci->configure(CODEC_SET_FILEBUF_WATERMARK, 1024*512); 149 ci->configure(CODEC_SET_FILEBUF_WATERMARK, 1024*512);
@@ -59,6 +152,12 @@ enum codec_status codec_main(void)
59 ci->configure(DSP_SET_SAMPLE_DEPTH, APE_OUTPUT_DEPTH-1); 152 ci->configure(DSP_SET_SAMPLE_DEPTH, APE_OUTPUT_DEPTH-1);
60 153
61 next_track: 154 next_track:
155
156 retval = CODEC_OK;
157
158 /* Remember the resume position - when the codec is opened, the
159 playback engine will reset it. */
160 resume_offset = ci->id3->offset;
62 161
63 if (codec_init()) { 162 if (codec_init()) {
64 LOGF("APE: Error initialising codec\n"); 163 LOGF("APE: Error initialising codec\n");
@@ -74,7 +173,31 @@ enum codec_status codec_main(void)
74 retval = CODEC_ERROR; 173 retval = CODEC_ERROR;
75 goto exit; 174 goto exit;
76 } 175 }
77 ci->advance_buffer(ape_ctx.firstframe); 176
177 /* Initialise the seektable for this file */
178 ape_ctx.seektable = seektablebuf;
179 ape_ctx.numseekpoints = MIN(MAX_SEEKPOINTS,ape_ctx.numseekpoints);
180
181 ci->advance_buffer(ape_ctx.seektablefilepos);
182
183 /* The seektable may be bigger than the guard buffer (32KB), so we
184 do a read() */
185 ci->read_filebuf(ape_ctx.seektable, ape_ctx.numseekpoints * sizeof(uint32_t));
186
187#ifdef ROCKBOX_BIG_ENDIAN
188 /* Byte-swap the little-endian seekpoints */
189 {
190 uint32_t i;
191
192 for(i = 0; i < ape_ctx.numseekpoints; i++)
193 ape_ctx.seektable[i] = swap32(ape_ctx.seektable[i]);
194 }
195#endif
196
197 /* Now advance the file position to the first frame */
198 ci->advance_buffer(ape_ctx.firstframe -
199 (ape_ctx.seektablefilepos +
200 ape_ctx.numseekpoints * sizeof(uint32_t)));
78 201
79 while (!*ci->taginfo_ready && !ci->stop_codec) 202 while (!*ci->taginfo_ready && !ci->stop_codec)
80 ci->sleep(1); 203 ci->sleep(1);
@@ -86,16 +209,26 @@ enum codec_status codec_main(void)
86 209
87 /* The main decoding loop */ 210 /* The main decoding loop */
88 211
89 currentframe = 0; 212 if (resume_offset) {
90 samplesdone = 0; 213 /* The resume offset is a value in bytes - we need to
214 turn it into a frame number and samplestoskip value */
215
216 ape_resume(&ape_ctx, resume_offset,
217 &currentframe, &samplesdone, &samplestoskip, &firstbyte);
218 } else {
219 currentframe = 0;
220 samplesdone = 0;
221 samplestoskip = 0;
222 firstbyte = 3; /* Take account of the little-endian 32-bit byte ordering */
223 }
91 224
92 /* Initialise the buffer */ 225 /* Initialise the buffer */
93 inbuffer = ci->request_buffer(&bytesleft, INPUT_CHUNKSIZE); 226 inbuffer = ci->request_buffer(&bytesleft, INPUT_CHUNKSIZE);
94 firstbyte = 3; /* Take account of the little-endian 32-bit byte ordering */
95 227
96 /* The main decoding loop - we decode the frames a small chunk at a time */ 228 /* The main decoding loop - we decode the frames a small chunk at a time */
97 while (currentframe < ape_ctx.totalframes) 229 while (currentframe < ape_ctx.totalframes)
98 { 230 {
231frame_start:
99 /* Calculate how many blocks there are in this frame */ 232 /* Calculate how many blocks there are in this frame */
100 if (currentframe == (ape_ctx.totalframes - 1)) 233 if (currentframe == (ape_ctx.totalframes - 1))
101 nblocks = ape_ctx.finalframeblocks; 234 nblocks = ape_ctx.finalframeblocks;
@@ -115,7 +248,31 @@ enum codec_status codec_main(void)
115 { 248 {
116 ci->yield(); 249 ci->yield();
117 if (ci->stop_codec || ci->new_track) { 250 if (ci->stop_codec || ci->new_track) {
118 break; 251 goto done;
252 }
253
254 /* Deal with any pending seek requests */
255 if (ci->seek_time)
256 {
257 if (ape_calc_seekpos(&ape_ctx,
258 ((ci->seek_time-1)/10) * (ci->id3->frequency/100),
259 &currentframe,
260 &newfilepos,
261 &samplestoskip))
262 {
263 samplesdone = currentframe * ape_ctx.blocksperframe;
264
265 /* APE's bytestream is weird... */
266 firstbyte = 3 - (newfilepos & 3);
267 newfilepos &= ~3;
268
269 ci->seek_buffer(newfilepos);
270 inbuffer = ci->request_buffer(&bytesleft, INPUT_CHUNKSIZE);
271
272 ci->seek_complete();
273 goto frame_start; /* Sorry... */
274 }
275 ci->seek_complete();
119 } 276 }
120 277
121 blockstodecode = MIN(BLOCKS_PER_LOOP, nblocks); 278 blockstodecode = MIN(BLOCKS_PER_LOOP, nblocks);
@@ -132,12 +289,27 @@ enum codec_status codec_main(void)
132 } 289 }
133 290
134 ci->yield(); 291 ci->yield();
135 ci->pcmbuf_insert(decoded0, decoded1, blockstodecode); 292
293 if (samplestoskip > 0) {
294 if (samplestoskip < blockstodecode) {
295 ci->pcmbuf_insert(decoded0 + samplestoskip,
296 decoded1 + samplestoskip,
297 blockstodecode - samplestoskip);
298 samplestoskip = 0;
299 } else {
300 samplestoskip -= blockstodecode;
301 }
302 } else {
303 ci->pcmbuf_insert(decoded0, decoded1, blockstodecode);
304 }
136 305
137 /* Update the elapsed-time indicator */
138 samplesdone += blockstodecode; 306 samplesdone += blockstodecode;
139 elapsedtime = (samplesdone*10)/(ape_ctx.samplerate/100); 307
140 ci->set_elapsed(elapsedtime); 308 if (!samplestoskip) {
309 /* Update the elapsed-time indicator */
310 elapsedtime = (samplesdone*10)/(ape_ctx.samplerate/100);
311 ci->set_elapsed(elapsedtime);
312 }
141 313
142 ci->advance_buffer(bytesconsumed); 314 ci->advance_buffer(bytesconsumed);
143 inbuffer = ci->request_buffer(&bytesleft, INPUT_CHUNKSIZE); 315 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 @@
4# Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < 4# Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
5# Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ 5# Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
6# \/ \/ \/ \/ \/ 6# \/ \/ \/ \/ \/
7# $Id:$ 7# $Id$
8# 8#
9 9
10INCLUDES=-I$(APPSDIR) -I.. -I. -I$(FIRMDIR)/include -I$(FIRMDIR)/export \ 10INCLUDES=-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 @@
2 2
3libdemac - A Monkey's Audio decoder 3libdemac - A Monkey's Audio decoder
4 4
5$Id:$ 5$Id$
6 6
7Copyright (C) Dave Chapman 2007 7Copyright (C) Dave Chapman 2007
8 8
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)
92 ape_ctx->channels = get_uint16(header + 18); 92 ape_ctx->channels = get_uint16(header + 18);
93 ape_ctx->samplerate = get_uint32(header + 20); 93 ape_ctx->samplerate = get_uint32(header + 20);
94 94
95 ape_ctx->seektablefilepos = ape_ctx->junklength +
96 ape_ctx->descriptorlength +
97 ape_ctx->headerlength;
98
95 ape_ctx->firstframe = ape_ctx->junklength + ape_ctx->descriptorlength + 99 ape_ctx->firstframe = ape_ctx->junklength + ape_ctx->descriptorlength +
96 ape_ctx->headerlength + ape_ctx->seektablelength + 100 ape_ctx->headerlength + ape_ctx->seektablelength +
97 ape_ctx->wavheaderlength; 101 ape_ctx->wavheaderlength;
@@ -133,15 +137,19 @@ int ape_parseheaderbuf(unsigned char* buf, struct ape_ctx_t* ape_ctx)
133 else 137 else
134 ape_ctx->blocksperframe = 9216; 138 ape_ctx->blocksperframe = 9216;
135 139
136 ape_ctx->firstframe = ape_ctx->junklength + ape_ctx->headerlength + 140 ape_ctx->seektablefilepos = ape_ctx->junklength + ape_ctx->headerlength +
137 ape_ctx->seektablelength + ape_ctx->wavheaderlength; 141 ape_ctx->wavheaderlength;
142
143 ape_ctx->firstframe = ape_ctx->junklength + ape_ctx->headerlength +
144 ape_ctx->wavheaderlength + ape_ctx->seektablelength;
138 } 145 }
139 146
140 ape_ctx->totalsamples = ape_ctx->finalframeblocks; 147 ape_ctx->totalsamples = ape_ctx->finalframeblocks;
141 if (ape_ctx->totalframes > 1) 148 if (ape_ctx->totalframes > 1)
142 ape_ctx->totalsamples += ape_ctx->blocksperframe * (ape_ctx->totalframes-1); 149 ape_ctx->totalsamples += ape_ctx->blocksperframe * (ape_ctx->totalframes-1);
143 150
144 /* TODO: Parse and store seektable */ 151 ape_ctx->numseekpoints = MAX(ape_ctx->maxseekpoints,
152 ape_ctx->seektablelength / sizeof(int32_t));
145 153
146 return 0; 154 return 0;
147} 155}
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 @@
2 2
3libdemac - A Monkey's Audio decoder 3libdemac - A Monkey's Audio decoder
4 4
5$Id:$ 5$Id$
6 6
7Copyright (C) Dave Chapman 2007 7Copyright (C) Dave Chapman 2007
8 8
@@ -119,7 +119,10 @@ struct ape_ctx_t
119 uint32_t samplerate; 119 uint32_t samplerate;
120 120
121 /* Seektable */ 121 /* Seektable */
122 uint32_t* seektable; 122 uint32_t* seektable; /* Seektable buffer */
123 uint32_t maxseekpoints; /* Max seekpoints we can store (size of seektable buffer) */
124 uint32_t numseekpoints; /* Number of seekpoints */
125 int seektablefilepos; /* Location in .ape file of seektable */
123 126
124 /* Decoder state */ 127 /* Decoder state */
125 uint32_t CRC; 128 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 @@
2 2
3libdemac - A Monkey's Audio decoder 3libdemac - A Monkey's Audio decoder
4 4
5$Id:$ 5$Id$
6 6
7Copyright (C) Dave Chapman 2007 7Copyright (C) Dave Chapman 2007
8 8
diff --git a/apps/playback.c b/apps/playback.c
index 25dec7a9ff..b48bcc8c26 100644
--- a/apps/playback.c
+++ b/apps/playback.c
@@ -2837,6 +2837,7 @@ static bool audio_load_track(int offset, bool start_play, bool rebuffer)
2837 case AFMT_A52: 2837 case AFMT_A52:
2838 case AFMT_AAC: 2838 case AFMT_AAC:
2839 case AFMT_MPC: 2839 case AFMT_MPC:
2840 case AFMT_APE:
2840 tracks[track_widx].id3.offset = offset; 2841 tracks[track_widx].id3.offset = offset;
2841 break; 2842 break;
2842 } 2843 }