FS#11968 by Peter Lecky - Slovak language update
[maemo-rb.git] / apps / codecs / ape.c
blob11d973ab268b5fff2760e94649bcbd03b548158c
1 /***************************************************************************
2 * __________ __ ___.
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7 * \/ \/ \/ \/ \/
8 * $Id$
10 * Copyright (C) 2007 Dave Chapman
12 * This program is free software; you can redistribute it and/or
13 * modify it under the terms of the GNU General Public License
14 * as published by the Free Software Foundation; either version 2
15 * of the License, or (at your option) any later version.
17 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
18 * KIND, either express or implied.
20 ****************************************************************************/
22 #include "codeclib.h"
23 #include <codecs/demac/libdemac/demac.h>
25 CODEC_HEADER
27 #define BLOCKS_PER_LOOP 1024
28 #define MAX_CHANNELS 2
29 #define MAX_BYTESPERSAMPLE 3
31 /* Monkey's Audio files have one seekpoint per frame. The framesize
32 varies between 73728 and 1179648 samples.
34 At the smallest framesize, 30000 frames would be 50155 seconds of
35 audio - almost 14 hours. This should be enough for any file a user
36 would want to play in Rockbox, given the 2GB FAT filesize (and 4GB
37 seektable entry size) limit.
39 This means the seektable is 120000 bytes, but we have a lot of
40 spare room in the codec buffer - the APE codec itself is small.
43 #define MAX_SEEKPOINTS 30000
44 static uint32_t seektablebuf[MAX_SEEKPOINTS];
46 #define INPUT_CHUNKSIZE (32*1024)
48 /* 1024*4 = 4096 bytes per channel */
49 static int32_t decoded0[BLOCKS_PER_LOOP] IBSS_ATTR;
50 static int32_t decoded1[BLOCKS_PER_LOOP] IBSS_ATTR;
52 #define MAX_SUPPORTED_SEEKTABLE_SIZE 5000
55 /* Given an ape_ctx and a sample to seek to, return the file position
56 to the frame containing that sample, and the number of samples to
57 skip in that frame.
60 static bool ape_calc_seekpos(struct ape_ctx_t* ape_ctx,
61 uint32_t new_sample,
62 uint32_t* newframe,
63 uint32_t* filepos,
64 uint32_t* samplestoskip)
66 uint32_t n;
68 n = new_sample / ape_ctx->blocksperframe;
69 if (n >= ape_ctx->numseekpoints)
71 /* We don't have a seekpoint for that frame */
72 return false;
75 *newframe = n;
76 *filepos = ape_ctx->seektable[n];
77 *samplestoskip = new_sample - (n * ape_ctx->blocksperframe);
79 return true;
82 /* The resume offset is a value in bytes - we need to
83 turn it into a frame number and samplestoskip value */
85 static void ape_resume(struct ape_ctx_t* ape_ctx, size_t resume_offset,
86 uint32_t* currentframe, uint32_t* samplesdone,
87 uint32_t* samplestoskip, int* firstbyte)
89 off_t newfilepos;
90 int64_t framesize;
91 int64_t offset;
93 *currentframe = 0;
94 *samplesdone = 0;
95 *samplestoskip = 0;
97 while ((*currentframe < ape_ctx->totalframes) &&
98 (*currentframe < ape_ctx->numseekpoints) &&
99 (resume_offset > ape_ctx->seektable[*currentframe]))
101 ++*currentframe;
102 *samplesdone += ape_ctx->blocksperframe;
105 if ((*currentframe > 0) &&
106 (ape_ctx->seektable[*currentframe] > resume_offset)) {
107 --*currentframe;
108 *samplesdone -= ape_ctx->blocksperframe;
111 newfilepos = ape_ctx->seektable[*currentframe];
113 /* APE's bytestream is weird... */
114 *firstbyte = 3 - (newfilepos & 3);
115 newfilepos &= ~3;
117 ci->seek_buffer(newfilepos);
119 /* We estimate where we were in the current frame, based on the
120 byte offset */
121 if (*currentframe < (ape_ctx->totalframes - 1)) {
122 framesize = ape_ctx->seektable[*currentframe+1] - ape_ctx->seektable[*currentframe];
123 offset = resume_offset - ape_ctx->seektable[*currentframe];
125 *samplestoskip = (offset * ape_ctx->blocksperframe) / framesize;
129 /* this is the codec entry point */
130 enum codec_status codec_main(void)
132 struct ape_ctx_t ape_ctx;
133 uint32_t samplesdone;
134 uint32_t elapsedtime;
135 size_t bytesleft;
136 int retval;
138 uint32_t currentframe;
139 uint32_t newfilepos;
140 uint32_t samplestoskip;
141 int nblocks;
142 int bytesconsumed;
143 unsigned char* inbuffer;
144 uint32_t blockstodecode;
145 int res;
146 int firstbyte;
147 size_t resume_offset;
149 /* Generic codec initialisation */
150 ci->configure(DSP_SET_SAMPLE_DEPTH, APE_OUTPUT_DEPTH-1);
152 next_track:
153 retval = CODEC_OK;
155 if (codec_init()) {
156 LOGF("APE: Error initialising codec\n");
157 retval = CODEC_ERROR;
158 goto exit;
161 if (codec_wait_taginfo() != 0)
162 goto done;
164 /* Remember the resume position - when the codec is opened, the
165 playback engine will reset it. */
166 resume_offset = ci->id3->offset;
168 inbuffer = ci->request_buffer(&bytesleft, INPUT_CHUNKSIZE);
170 /* Read the file headers to populate the ape_ctx struct */
171 if (ape_parseheaderbuf(inbuffer,&ape_ctx) < 0) {
172 LOGF("APE: Error reading header\n");
173 retval = CODEC_ERROR;
174 goto exit;
177 /* Initialise the seektable for this file */
178 ape_ctx.seektable = seektablebuf;
179 ape_ctx.numseekpoints = MIN(MAX_SEEKPOINTS,ape_ctx.numseekpoints);
181 ci->advance_buffer(ape_ctx.seektablefilepos);
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));
187 #ifdef ROCKBOX_BIG_ENDIAN
188 /* Byte-swap the little-endian seekpoints */
190 uint32_t i;
192 for(i = 0; i < ape_ctx.numseekpoints; i++)
193 ape_ctx.seektable[i] = swap32(ape_ctx.seektable[i]);
195 #endif
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)));
202 ci->configure(DSP_SWITCH_FREQUENCY, ape_ctx.samplerate);
203 ci->configure(DSP_SET_STEREO_MODE, ape_ctx.channels == 1 ?
204 STEREO_MONO : STEREO_NONINTERLEAVED);
205 codec_set_replaygain(ci->id3);
207 /* The main decoding loop */
209 if (resume_offset) {
210 /* The resume offset is a value in bytes - we need to
211 turn it into a frame number and samplestoskip value */
213 ape_resume(&ape_ctx, resume_offset,
214 &currentframe, &samplesdone, &samplestoskip, &firstbyte);
215 } else {
216 currentframe = 0;
217 samplesdone = 0;
218 samplestoskip = 0;
219 firstbyte = 3; /* Take account of the little-endian 32-bit byte ordering */
222 /* Initialise the buffer */
223 inbuffer = ci->request_buffer(&bytesleft, INPUT_CHUNKSIZE);
225 /* The main decoding loop - we decode the frames a small chunk at a time */
226 while (currentframe < ape_ctx.totalframes)
228 frame_start:
229 /* Calculate how many blocks there are in this frame */
230 if (currentframe == (ape_ctx.totalframes - 1))
231 nblocks = ape_ctx.finalframeblocks;
232 else
233 nblocks = ape_ctx.blocksperframe;
235 ape_ctx.currentframeblocks = nblocks;
237 /* Initialise the frame decoder */
238 init_frame_decoder(&ape_ctx, inbuffer, &firstbyte, &bytesconsumed);
240 ci->advance_buffer(bytesconsumed);
241 inbuffer = ci->request_buffer(&bytesleft, INPUT_CHUNKSIZE);
243 /* Decode the frame a chunk at a time */
244 while (nblocks > 0)
246 ci->yield();
247 if (ci->stop_codec || ci->new_track) {
248 goto done;
251 /* Deal with any pending seek requests */
252 if (ci->seek_time)
254 if (ape_calc_seekpos(&ape_ctx,
255 ((ci->seek_time-1)/10) * (ci->id3->frequency/100),
256 &currentframe,
257 &newfilepos,
258 &samplestoskip))
260 samplesdone = currentframe * ape_ctx.blocksperframe;
262 /* APE's bytestream is weird... */
263 firstbyte = 3 - (newfilepos & 3);
264 newfilepos &= ~3;
266 ci->seek_buffer(newfilepos);
267 inbuffer = ci->request_buffer(&bytesleft, INPUT_CHUNKSIZE);
269 ci->seek_complete();
270 goto frame_start; /* Sorry... */
272 ci->seek_complete();
275 blockstodecode = MIN(BLOCKS_PER_LOOP, nblocks);
277 if ((res = decode_chunk(&ape_ctx, inbuffer, &firstbyte,
278 &bytesconsumed,
279 decoded0, decoded1,
280 blockstodecode)) < 0)
282 /* Frame decoding error, abort */
283 LOGF("APE: Frame %lu, error %d\n",(unsigned long)currentframe,res);
284 retval = CODEC_ERROR;
285 goto done;
288 ci->yield();
290 if (samplestoskip > 0) {
291 if (samplestoskip < blockstodecode) {
292 ci->pcmbuf_insert(decoded0 + samplestoskip,
293 decoded1 + samplestoskip,
294 blockstodecode - samplestoskip);
295 samplestoskip = 0;
296 } else {
297 samplestoskip -= blockstodecode;
299 } else {
300 ci->pcmbuf_insert(decoded0, decoded1, blockstodecode);
303 samplesdone += blockstodecode;
305 if (!samplestoskip) {
306 /* Update the elapsed-time indicator */
307 elapsedtime = (samplesdone*10)/(ape_ctx.samplerate/100);
308 ci->set_elapsed(elapsedtime);
311 ci->advance_buffer(bytesconsumed);
312 inbuffer = ci->request_buffer(&bytesleft, INPUT_CHUNKSIZE);
314 /* Decrement the block count */
315 nblocks -= blockstodecode;
318 currentframe++;
321 done:
322 LOGF("APE: Decoded %lu samples\n",(unsigned long)samplesdone);
324 if (ci->request_next_track())
325 goto next_track;
327 exit:
328 return retval;