gitscraper: support Python3.
[maemo-rb.git] / apps / codecs / ape.c
blobed6ea216857cdf6d9d716654ca7872bbdce42236
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(enum codec_entry_call_reason reason)
132 if (reason == CODEC_LOAD) {
133 /* Generic codec initialisation */
134 ci->configure(DSP_SET_SAMPLE_DEPTH, APE_OUTPUT_DEPTH-1);
137 return CODEC_OK;
140 /* this is called for each file to process */
141 enum codec_status codec_run(void)
143 struct ape_ctx_t ape_ctx;
144 uint32_t samplesdone;
145 uint32_t elapsedtime;
146 size_t bytesleft;
148 uint32_t currentframe;
149 uint32_t newfilepos;
150 uint32_t samplestoskip;
151 int nblocks;
152 int bytesconsumed;
153 unsigned char* inbuffer;
154 uint32_t blockstodecode;
155 int res;
156 int firstbyte;
157 size_t resume_offset;
158 intptr_t param;
160 if (codec_init()) {
161 LOGF("APE: Error initialising codec\n");
162 return CODEC_ERROR;
165 /* Remember the resume position - when the codec is opened, the
166 playback engine will reset it. */
167 resume_offset = ci->id3->offset;
169 ci->seek_buffer(0);
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 return CODEC_ERROR;
178 /* Initialise the seektable for this file */
179 ape_ctx.seektable = seektablebuf;
180 ape_ctx.numseekpoints = MIN(MAX_SEEKPOINTS,ape_ctx.numseekpoints);
182 ci->advance_buffer(ape_ctx.seektablefilepos);
184 /* The seektable may be bigger than the guard buffer (32KB), so we
185 do a read() */
186 ci->read_filebuf(ape_ctx.seektable, ape_ctx.numseekpoints * sizeof(uint32_t));
188 #ifdef ROCKBOX_BIG_ENDIAN
189 /* Byte-swap the little-endian seekpoints */
191 uint32_t i;
193 for(i = 0; i < ape_ctx.numseekpoints; i++)
194 ape_ctx.seektable[i] = swap32(ape_ctx.seektable[i]);
196 #endif
198 /* Now advance the file position to the first frame */
199 ci->advance_buffer(ape_ctx.firstframe -
200 (ape_ctx.seektablefilepos +
201 ape_ctx.numseekpoints * sizeof(uint32_t)));
203 ci->configure(DSP_SWITCH_FREQUENCY, ape_ctx.samplerate);
204 ci->configure(DSP_SET_STEREO_MODE, ape_ctx.channels == 1 ?
205 STEREO_MONO : STEREO_NONINTERLEAVED);
206 codec_set_replaygain(ci->id3);
208 /* The main decoding loop */
210 if (resume_offset) {
211 /* The resume offset is a value in bytes - we need to
212 turn it into a frame number and samplestoskip value */
214 ape_resume(&ape_ctx, resume_offset,
215 &currentframe, &samplesdone, &samplestoskip, &firstbyte);
216 } else {
217 currentframe = 0;
218 samplesdone = 0;
219 samplestoskip = 0;
220 firstbyte = 3; /* Take account of the little-endian 32-bit byte ordering */
223 elapsedtime = (samplesdone*10)/(ape_ctx.samplerate/100);
224 ci->set_elapsed(elapsedtime);
226 /* Initialise the buffer */
227 inbuffer = ci->request_buffer(&bytesleft, INPUT_CHUNKSIZE);
229 /* The main decoding loop - we decode the frames a small chunk at a time */
230 while (currentframe < ape_ctx.totalframes)
232 frame_start:
233 /* Calculate how many blocks there are in this frame */
234 if (currentframe == (ape_ctx.totalframes - 1))
235 nblocks = ape_ctx.finalframeblocks;
236 else
237 nblocks = ape_ctx.blocksperframe;
239 ape_ctx.currentframeblocks = nblocks;
241 /* Initialise the frame decoder */
242 init_frame_decoder(&ape_ctx, inbuffer, &firstbyte, &bytesconsumed);
244 ci->advance_buffer(bytesconsumed);
245 inbuffer = ci->request_buffer(&bytesleft, INPUT_CHUNKSIZE);
247 /* Decode the frame a chunk at a time */
248 while (nblocks > 0)
250 enum codec_command_action action = ci->get_command(&param);
252 if (action == CODEC_ACTION_HALT)
253 goto done;
255 /* Deal with any pending seek requests */
256 if (action == CODEC_ACTION_SEEK_TIME)
258 if (ape_calc_seekpos(&ape_ctx,
259 (param/10) * (ci->id3->frequency/100),
260 &currentframe,
261 &newfilepos,
262 &samplestoskip))
264 samplesdone = currentframe * ape_ctx.blocksperframe;
266 /* APE's bytestream is weird... */
267 firstbyte = 3 - (newfilepos & 3);
268 newfilepos &= ~3;
270 ci->seek_buffer(newfilepos);
271 inbuffer = ci->request_buffer(&bytesleft, INPUT_CHUNKSIZE);
273 elapsedtime = (samplesdone*10)/(ape_ctx.samplerate/100);
274 ci->set_elapsed(elapsedtime);
275 ci->seek_complete();
276 goto frame_start; /* Sorry... */
279 ci->seek_complete();
282 blockstodecode = MIN(BLOCKS_PER_LOOP, nblocks);
284 if ((res = decode_chunk(&ape_ctx, inbuffer, &firstbyte,
285 &bytesconsumed,
286 decoded0, decoded1,
287 blockstodecode)) < 0)
289 /* Frame decoding error, abort */
290 LOGF("APE: Frame %lu, error %d\n",(unsigned long)currentframe,res);
291 return CODEC_ERROR;
294 ci->yield();
296 if (samplestoskip > 0) {
297 if (samplestoskip < blockstodecode) {
298 ci->pcmbuf_insert(decoded0 + samplestoskip,
299 decoded1 + samplestoskip,
300 blockstodecode - samplestoskip);
301 samplestoskip = 0;
302 } else {
303 samplestoskip -= blockstodecode;
305 } else {
306 ci->pcmbuf_insert(decoded0, decoded1, blockstodecode);
309 samplesdone += blockstodecode;
311 if (!samplestoskip) {
312 /* Update the elapsed-time indicator */
313 elapsedtime = (samplesdone*10)/(ape_ctx.samplerate/100);
314 ci->set_elapsed(elapsedtime);
317 ci->advance_buffer(bytesconsumed);
318 inbuffer = ci->request_buffer(&bytesleft, INPUT_CHUNKSIZE);
320 /* Decrement the block count */
321 nblocks -= blockstodecode;
324 currentframe++;
327 done:
328 LOGF("APE: Decoded %lu samples\n",(unsigned long)samplesdone);
329 return CODEC_OK;