diff options
Diffstat (limited to 'apps')
-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 | ||||
-rw-r--r-- | apps/playback.c | 1 |
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 | ||
43 | static 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 | |||
59 | bool 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 | |||
84 | void 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 */ |
39 | enum codec_status codec_main(void) | 129 | enum 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 | ¤tframe, &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 | { |
231 | frame_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 | ¤tframe, | ||
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 | ||
10 | INCLUDES=-I$(APPSDIR) -I.. -I. -I$(FIRMDIR)/include -I$(FIRMDIR)/export \ | 10 | 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 @@ | |||
2 | 2 | ||
3 | libdemac - A Monkey's Audio decoder | 3 | libdemac - A Monkey's Audio decoder |
4 | 4 | ||
5 | $Id:$ | 5 | $Id$ |
6 | 6 | ||
7 | Copyright (C) Dave Chapman 2007 | 7 | Copyright (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 | ||
3 | libdemac - A Monkey's Audio decoder | 3 | libdemac - A Monkey's Audio decoder |
4 | 4 | ||
5 | $Id:$ | 5 | $Id$ |
6 | 6 | ||
7 | Copyright (C) Dave Chapman 2007 | 7 | Copyright (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 | ||
3 | libdemac - A Monkey's Audio decoder | 3 | libdemac - A Monkey's Audio decoder |
4 | 4 | ||
5 | $Id:$ | 5 | $Id$ |
6 | 6 | ||
7 | Copyright (C) Dave Chapman 2007 | 7 | Copyright (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 | } |