autodetection: convert path to native separators before displaying it.
[Rockbox.git] / apps / codecs / ape.c
blob76c1d1af8dbadcb89aff06dcdd22c9ba1357fd93
1 /***************************************************************************
2 * __________ __ ___.
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7 * \/ \/ \/ \/ \/
8 * $Id$
10 * Copyright (C) 2007 Dave Chapman
12 * All files in this archive are subject to the GNU General Public License.
13 * See the file COPYING in the source tree root for full license agreement.
15 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
16 * KIND, either express or implied.
18 ****************************************************************************/
20 #include "codeclib.h"
21 #define ROCKBOX
22 #include <codecs/demac/libdemac/demac.h>
24 CODEC_HEADER
26 #define BLOCKS_PER_LOOP 4608
27 #define MAX_CHANNELS 2
28 #define MAX_BYTESPERSAMPLE 3
30 /* Monkey's Audio files have one seekpoint per frame. The framesize
31 varies between 73728 and 1179648 samples.
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.
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.
42 #define MAX_SEEKPOINTS 30000
43 static uint32_t seektablebuf[MAX_SEEKPOINTS];
45 #define INPUT_CHUNKSIZE (32*1024)
47 /* 4608*4 = 18432 bytes per channel */
48 static int32_t decoded0[BLOCKS_PER_LOOP] IBSS_ATTR;
49 static int32_t decoded1[BLOCKS_PER_LOOP] IBSS_ATTR;
51 #define MAX_SUPPORTED_SEEKTABLE_SIZE 5000
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.
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)
65 uint32_t n;
67 n = new_sample / ape_ctx->blocksperframe;
68 if (n >= ape_ctx->numseekpoints)
70 /* We don't have a seekpoint for that frame */
71 return false;
74 *newframe = n;
75 *filepos = ape_ctx->seektable[n];
76 *samplestoskip = new_sample - (n * ape_ctx->blocksperframe);
78 return true;
81 /* The resume offset is a value in bytes - we need to
82 turn it into a frame number and samplestoskip value */
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)
88 off_t newfilepos;
89 int64_t framesize;
90 int64_t offset;
92 *currentframe = 0;
93 *samplesdone = 0;
94 *samplestoskip = 0;
96 while ((*currentframe < ape_ctx->totalframes) &&
97 (*currentframe < ape_ctx->numseekpoints) &&
98 (resume_offset > ape_ctx->seektable[*currentframe]))
100 ++*currentframe;
101 *samplesdone += ape_ctx->blocksperframe;
104 if ((*currentframe > 0) &&
105 (ape_ctx->seektable[*currentframe] > resume_offset)) {
106 --*currentframe;
107 *samplesdone -= ape_ctx->blocksperframe;
110 newfilepos = ape_ctx->seektable[*currentframe];
112 /* APE's bytestream is weird... */
113 *firstbyte = 3 - (newfilepos & 3);
114 newfilepos &= ~3;
116 ci->seek_buffer(newfilepos);
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];
124 *samplestoskip = (offset * ape_ctx->blocksperframe) / framesize;
128 /* this is the codec entry point */
129 enum codec_status codec_main(void)
131 struct ape_ctx_t ape_ctx;
132 uint32_t samplesdone;
133 uint32_t elapsedtime;
134 size_t bytesleft;
135 int retval;
137 uint32_t currentframe;
138 uint32_t newfilepos;
139 uint32_t samplestoskip;
140 int nblocks;
141 int bytesconsumed;
142 unsigned char* inbuffer;
143 uint32_t blockstodecode;
144 int res;
145 int firstbyte;
146 size_t resume_offset;
148 /* Generic codec initialisation */
149 ci->configure(CODEC_SET_FILEBUF_WATERMARK, 1024*512);
151 ci->configure(DSP_SET_SAMPLE_DEPTH, APE_OUTPUT_DEPTH-1);
153 next_track:
155 retval = CODEC_OK;
157 /* Remember the resume position - when the codec is opened, the
158 playback engine will reset it. */
159 resume_offset = ci->id3->offset;
161 if (codec_init()) {
162 LOGF("APE: Error initialising codec\n");
163 retval = CODEC_ERROR;
164 goto exit;
167 while (!*ci->taginfo_ready && !ci->stop_codec)
168 ci->sleep(1);
170 inbuffer = ci->request_buffer(&bytesleft, INPUT_CHUNKSIZE);
172 /* Read the file headers to populate the ape_ctx struct */
173 if (ape_parseheaderbuf(inbuffer,&ape_ctx) < 0) {
174 LOGF("APE: Error reading header\n");
175 retval = CODEC_ERROR;
176 goto exit;
179 /* Initialise the seektable for this file */
180 ape_ctx.seektable = seektablebuf;
181 ape_ctx.numseekpoints = MIN(MAX_SEEKPOINTS,ape_ctx.numseekpoints);
183 ci->advance_buffer(ape_ctx.seektablefilepos);
185 /* The seektable may be bigger than the guard buffer (32KB), so we
186 do a read() */
187 ci->read_filebuf(ape_ctx.seektable, ape_ctx.numseekpoints * sizeof(uint32_t));
189 #ifdef ROCKBOX_BIG_ENDIAN
190 /* Byte-swap the little-endian seekpoints */
192 uint32_t i;
194 for(i = 0; i < ape_ctx.numseekpoints; i++)
195 ape_ctx.seektable[i] = swap32(ape_ctx.seektable[i]);
197 #endif
199 /* Now advance the file position to the first frame */
200 ci->advance_buffer(ape_ctx.firstframe -
201 (ape_ctx.seektablefilepos +
202 ape_ctx.numseekpoints * sizeof(uint32_t)));
204 ci->configure(DSP_SWITCH_FREQUENCY, ape_ctx.samplerate);
205 ci->configure(DSP_SET_STEREO_MODE, ape_ctx.channels == 1 ?
206 STEREO_MONO : STEREO_NONINTERLEAVED);
207 codec_set_replaygain(ci->id3);
209 /* The main decoding loop */
211 if (resume_offset) {
212 /* The resume offset is a value in bytes - we need to
213 turn it into a frame number and samplestoskip value */
215 ape_resume(&ape_ctx, resume_offset,
216 &currentframe, &samplesdone, &samplestoskip, &firstbyte);
217 } else {
218 currentframe = 0;
219 samplesdone = 0;
220 samplestoskip = 0;
221 firstbyte = 3; /* Take account of the little-endian 32-bit byte ordering */
224 /* Initialise the buffer */
225 inbuffer = ci->request_buffer(&bytesleft, INPUT_CHUNKSIZE);
227 /* The main decoding loop - we decode the frames a small chunk at a time */
228 while (currentframe < ape_ctx.totalframes)
230 frame_start:
231 /* Calculate how many blocks there are in this frame */
232 if (currentframe == (ape_ctx.totalframes - 1))
233 nblocks = ape_ctx.finalframeblocks;
234 else
235 nblocks = ape_ctx.blocksperframe;
237 ape_ctx.currentframeblocks = nblocks;
239 /* Initialise the frame decoder */
240 init_frame_decoder(&ape_ctx, inbuffer, &firstbyte, &bytesconsumed);
242 ci->advance_buffer(bytesconsumed);
243 inbuffer = ci->request_buffer(&bytesleft, INPUT_CHUNKSIZE);
245 /* Decode the frame a chunk at a time */
246 while (nblocks > 0)
248 ci->yield();
249 if (ci->stop_codec || ci->new_track) {
250 goto done;
253 /* Deal with any pending seek requests */
254 if (ci->seek_time)
256 if (ape_calc_seekpos(&ape_ctx,
257 ((ci->seek_time-1)/10) * (ci->id3->frequency/100),
258 &currentframe,
259 &newfilepos,
260 &samplestoskip))
262 samplesdone = currentframe * ape_ctx.blocksperframe;
264 /* APE's bytestream is weird... */
265 firstbyte = 3 - (newfilepos & 3);
266 newfilepos &= ~3;
268 ci->seek_buffer(newfilepos);
269 inbuffer = ci->request_buffer(&bytesleft, INPUT_CHUNKSIZE);
271 ci->seek_complete();
272 goto frame_start; /* Sorry... */
274 ci->seek_complete();
277 blockstodecode = MIN(BLOCKS_PER_LOOP, nblocks);
279 if ((res = decode_chunk(&ape_ctx, inbuffer, &firstbyte,
280 &bytesconsumed,
281 decoded0, decoded1,
282 blockstodecode)) < 0)
284 /* Frame decoding error, abort */
285 LOGF("APE: Frame %d, error %d\n",currentframe,res);
286 retval = CODEC_ERROR;
287 goto done;
290 ci->yield();
292 if (samplestoskip > 0) {
293 if (samplestoskip < blockstodecode) {
294 ci->pcmbuf_insert(decoded0 + samplestoskip,
295 decoded1 + samplestoskip,
296 blockstodecode - samplestoskip);
297 samplestoskip = 0;
298 } else {
299 samplestoskip -= blockstodecode;
301 } else {
302 ci->pcmbuf_insert(decoded0, decoded1, blockstodecode);
305 samplesdone += blockstodecode;
307 if (!samplestoskip) {
308 /* Update the elapsed-time indicator */
309 elapsedtime = (samplesdone*10)/(ape_ctx.samplerate/100);
310 ci->set_elapsed(elapsedtime);
313 ci->advance_buffer(bytesconsumed);
314 inbuffer = ci->request_buffer(&bytesleft, INPUT_CHUNKSIZE);
316 /* Decrement the block count */
317 nblocks -= blockstodecode;
320 currentframe++;
323 retval = CODEC_OK;
325 done:
326 LOGF("APE: Decoded %ld samples\n",samplesdone);
328 if (ci->request_next_track())
329 goto next_track;
331 exit:
332 return retval;