blob: 8f95a01ec790a2fd6ac7e2c55d1746ef152e4e88 [file] [log] [blame]
Dave Chapman52027422007-06-05 16:58:29 +00001/***************************************************************************
2 * __________ __ ___.
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7 * \/ \/ \/ \/ \/
8 * $Id$
9 *
10 * Copyright (C) 2007 Dave Chapman
11 *
Daniel Stenberg2acc0ac2008-06-28 18:10:04 +000012 * 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.
Dave Chapman52027422007-06-05 16:58:29 +000016 *
17 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
18 * KIND, either express or implied.
19 *
20 ****************************************************************************/
21
22#include "codeclib.h"
Dave Chapman52027422007-06-05 16:58:29 +000023#include <codecs/demac/libdemac/demac.h>
24
25CODEC_HEADER
26
Jens Arnold66fe9a42008-10-03 16:34:25 +000027#define BLOCKS_PER_LOOP 1024
Dave Chapman52027422007-06-05 16:58:29 +000028#define MAX_CHANNELS 2
29#define MAX_BYTESPERSAMPLE 3
30
Dave Chapman7b1d90a2007-06-08 22:35:26 +000031/* Monkey's Audio files have one seekpoint per frame. The framesize
32 varies between 73728 and 1179648 samples.
33
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.
38
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.
41*/
42
43#define MAX_SEEKPOINTS 30000
44static uint32_t seektablebuf[MAX_SEEKPOINTS];
45
Dave Chapman52027422007-06-05 16:58:29 +000046#define INPUT_CHUNKSIZE (32*1024)
47
Jens Arnoldb1531332008-11-30 11:53:52 +000048/* 1024*4 = 4096 bytes per channel */
Dave Chapman52027422007-06-05 16:58:29 +000049static int32_t decoded0[BLOCKS_PER_LOOP] IBSS_ATTR;
50static int32_t decoded1[BLOCKS_PER_LOOP] IBSS_ATTR;
51
52#define MAX_SUPPORTED_SEEKTABLE_SIZE 5000
53
Dave Chapman7b1d90a2007-06-08 22:35:26 +000054
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.
58*/
59
Bertrik Sikken8e22f7f2008-12-29 19:49:48 +000060static 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)
Dave Chapman7b1d90a2007-06-08 22:35:26 +000065{
66 uint32_t n;
67
68 n = new_sample / ape_ctx->blocksperframe;
69 if (n >= ape_ctx->numseekpoints)
70 {
71 /* We don't have a seekpoint for that frame */
72 return false;
73 }
74
75 *newframe = n;
76 *filepos = ape_ctx->seektable[n];
77 *samplestoskip = new_sample - (n * ape_ctx->blocksperframe);
78
79 return true;
80}
81
82/* The resume offset is a value in bytes - we need to
83 turn it into a frame number and samplestoskip value */
84
Bertrik Sikken8e22f7f2008-12-29 19:49:48 +000085static 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)
Dave Chapman7b1d90a2007-06-08 22:35:26 +000088{
89 off_t newfilepos;
90 int64_t framesize;
91 int64_t offset;
92
93 *currentframe = 0;
94 *samplesdone = 0;
95 *samplestoskip = 0;
96
97 while ((*currentframe < ape_ctx->totalframes) &&
98 (*currentframe < ape_ctx->numseekpoints) &&
99 (resume_offset > ape_ctx->seektable[*currentframe]))
100 {
101 ++*currentframe;
102 *samplesdone += ape_ctx->blocksperframe;
103 }
104
105 if ((*currentframe > 0) &&
106 (ape_ctx->seektable[*currentframe] > resume_offset)) {
107 --*currentframe;
108 *samplesdone -= ape_ctx->blocksperframe;
109 }
110
111 newfilepos = ape_ctx->seektable[*currentframe];
112
113 /* APE's bytestream is weird... */
114 *firstbyte = 3 - (newfilepos & 3);
115 newfilepos &= ~3;
116
117 ci->seek_buffer(newfilepos);
118
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];
124
125 *samplestoskip = (offset * ape_ctx->blocksperframe) / framesize;
126 }
127}
128
Dave Chapman52027422007-06-05 16:58:29 +0000129/* this is the codec entry point */
Michael Sevakisc537d592011-04-27 03:08:23 +0000130enum codec_status codec_main(enum codec_entry_call_reason reason)
131{
132 if (reason == CODEC_LOAD) {
133 /* Generic codec initialisation */
134 ci->configure(DSP_SET_SAMPLE_DEPTH, APE_OUTPUT_DEPTH-1);
135 }
136
137 return CODEC_OK;
138}
139
140/* this is called for each file to process */
141enum codec_status codec_run(void)
Dave Chapman52027422007-06-05 16:58:29 +0000142{
143 struct ape_ctx_t ape_ctx;
144 uint32_t samplesdone;
145 uint32_t elapsedtime;
146 size_t bytesleft;
Dave Chapman52027422007-06-05 16:58:29 +0000147
148 uint32_t currentframe;
Dave Chapman7b1d90a2007-06-08 22:35:26 +0000149 uint32_t newfilepos;
150 uint32_t samplestoskip;
Dave Chapman52027422007-06-05 16:58:29 +0000151 int nblocks;
152 int bytesconsumed;
153 unsigned char* inbuffer;
Dave Chapman7b1d90a2007-06-08 22:35:26 +0000154 uint32_t blockstodecode;
Dave Chapman52027422007-06-05 16:58:29 +0000155 int res;
156 int firstbyte;
Dave Chapman7b1d90a2007-06-08 22:35:26 +0000157 size_t resume_offset;
Michael Sevakisc537d592011-04-27 03:08:23 +0000158 intptr_t param;
Dave Chapman7b1d90a2007-06-08 22:35:26 +0000159
Dave Chapman52027422007-06-05 16:58:29 +0000160 if (codec_init()) {
161 LOGF("APE: Error initialising codec\n");
Michael Sevakisc537d592011-04-27 03:08:23 +0000162 return CODEC_ERROR;
Dave Chapman52027422007-06-05 16:58:29 +0000163 }
164
Michael Sevakis85e40252011-02-20 15:27:10 +0000165 /* Remember the resume position - when the codec is opened, the
166 playback engine will reset it. */
167 resume_offset = ci->id3->offset;
Magnus Holmgren87842ca2008-02-24 19:12:15 +0000168
Michael Sevakisc537d592011-04-27 03:08:23 +0000169 ci->seek_buffer(0);
Dave Chapman52027422007-06-05 16:58:29 +0000170 inbuffer = ci->request_buffer(&bytesleft, INPUT_CHUNKSIZE);
171
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");
Michael Sevakisc537d592011-04-27 03:08:23 +0000175 return CODEC_ERROR;
Dave Chapman52027422007-06-05 16:58:29 +0000176 }
Dave Chapman7b1d90a2007-06-08 22:35:26 +0000177
178 /* Initialise the seektable for this file */
179 ape_ctx.seektable = seektablebuf;
180 ape_ctx.numseekpoints = MIN(MAX_SEEKPOINTS,ape_ctx.numseekpoints);
181
182 ci->advance_buffer(ape_ctx.seektablefilepos);
183
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));
187
188#ifdef ROCKBOX_BIG_ENDIAN
189 /* Byte-swap the little-endian seekpoints */
190 {
191 uint32_t i;
192
193 for(i = 0; i < ape_ctx.numseekpoints; i++)
194 ape_ctx.seektable[i] = swap32(ape_ctx.seektable[i]);
195 }
196#endif
197
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)));
Dave Chapman52027422007-06-05 16:58:29 +0000202
Dave Chapman52027422007-06-05 16:58:29 +0000203 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);
207
208 /* The main decoding loop */
209
Dave Chapman7b1d90a2007-06-08 22:35:26 +0000210 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 */
213
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 */
221 }
Dave Chapman52027422007-06-05 16:58:29 +0000222
223 /* Initialise the buffer */
224 inbuffer = ci->request_buffer(&bytesleft, INPUT_CHUNKSIZE);
Dave Chapman52027422007-06-05 16:58:29 +0000225
226 /* The main decoding loop - we decode the frames a small chunk at a time */
227 while (currentframe < ape_ctx.totalframes)
228 {
Dave Chapman7b1d90a2007-06-08 22:35:26 +0000229frame_start:
Dave Chapman52027422007-06-05 16:58:29 +0000230 /* Calculate how many blocks there are in this frame */
231 if (currentframe == (ape_ctx.totalframes - 1))
232 nblocks = ape_ctx.finalframeblocks;
233 else
234 nblocks = ape_ctx.blocksperframe;
235
236 ape_ctx.currentframeblocks = nblocks;
237
238 /* Initialise the frame decoder */
239 init_frame_decoder(&ape_ctx, inbuffer, &firstbyte, &bytesconsumed);
240
241 ci->advance_buffer(bytesconsumed);
242 inbuffer = ci->request_buffer(&bytesleft, INPUT_CHUNKSIZE);
243
244 /* Decode the frame a chunk at a time */
245 while (nblocks > 0)
246 {
Michael Sevakisc537d592011-04-27 03:08:23 +0000247 enum codec_command_action action = ci->get_command(&param);
248
249 if (action == CODEC_ACTION_HALT)
Dave Chapman7b1d90a2007-06-08 22:35:26 +0000250 goto done;
Dave Chapman7b1d90a2007-06-08 22:35:26 +0000251
252 /* Deal with any pending seek requests */
Michael Sevakisc537d592011-04-27 03:08:23 +0000253 if (action == CODEC_ACTION_SEEK_TIME)
Dave Chapman7b1d90a2007-06-08 22:35:26 +0000254 {
255 if (ape_calc_seekpos(&ape_ctx,
Michael Sevakisc537d592011-04-27 03:08:23 +0000256 (param/10) * (ci->id3->frequency/100),
Dave Chapman7b1d90a2007-06-08 22:35:26 +0000257 &currentframe,
258 &newfilepos,
259 &samplestoskip))
260 {
261 samplesdone = currentframe * ape_ctx.blocksperframe;
262
263 /* APE's bytestream is weird... */
264 firstbyte = 3 - (newfilepos & 3);
265 newfilepos &= ~3;
266
267 ci->seek_buffer(newfilepos);
268 inbuffer = ci->request_buffer(&bytesleft, INPUT_CHUNKSIZE);
269
Michael Sevakisc537d592011-04-27 03:08:23 +0000270 elapsedtime = (samplesdone*10)/(ape_ctx.samplerate/100);
271 ci->set_elapsed(elapsedtime);
Dave Chapman7b1d90a2007-06-08 22:35:26 +0000272 ci->seek_complete();
273 goto frame_start; /* Sorry... */
274 }
Michael Sevakisc537d592011-04-27 03:08:23 +0000275
Dave Chapman7b1d90a2007-06-08 22:35:26 +0000276 ci->seek_complete();
Dave Chapman52027422007-06-05 16:58:29 +0000277 }
278
279 blockstodecode = MIN(BLOCKS_PER_LOOP, nblocks);
280
281 if ((res = decode_chunk(&ape_ctx, inbuffer, &firstbyte,
282 &bytesconsumed,
283 decoded0, decoded1,
284 blockstodecode)) < 0)
285 {
286 /* Frame decoding error, abort */
Jeffrey Goode6083f3d2010-05-15 01:57:32 +0000287 LOGF("APE: Frame %lu, error %d\n",(unsigned long)currentframe,res);
Michael Sevakisc537d592011-04-27 03:08:23 +0000288 return CODEC_ERROR;
Dave Chapman52027422007-06-05 16:58:29 +0000289 }
290
291 ci->yield();
Dave Chapman7b1d90a2007-06-08 22:35:26 +0000292
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 }
Dave Chapman52027422007-06-05 16:58:29 +0000305
Dave Chapman52027422007-06-05 16:58:29 +0000306 samplesdone += blockstodecode;
Dave Chapman7b1d90a2007-06-08 22:35:26 +0000307
308 if (!samplestoskip) {
309 /* Update the elapsed-time indicator */
310 elapsedtime = (samplesdone*10)/(ape_ctx.samplerate/100);
311 ci->set_elapsed(elapsedtime);
312 }
Dave Chapman52027422007-06-05 16:58:29 +0000313
314 ci->advance_buffer(bytesconsumed);
315 inbuffer = ci->request_buffer(&bytesleft, INPUT_CHUNKSIZE);
316
317 /* Decrement the block count */
318 nblocks -= blockstodecode;
319 }
320
321 currentframe++;
322 }
323
Dave Chapman52027422007-06-05 16:58:29 +0000324done:
Jeffrey Goode6083f3d2010-05-15 01:57:32 +0000325 LOGF("APE: Decoded %lu samples\n",(unsigned long)samplesdone);
Michael Sevakisc537d592011-04-27 03:08:23 +0000326 return CODEC_OK;
Dave Chapman52027422007-06-05 16:58:29 +0000327}