1 /***************************************************************************
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
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 ****************************************************************************/
23 #include <codecs/demac/libdemac/demac.h>
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
60 static bool ape_calc_seekpos(struct ape_ctx_t
* ape_ctx
,
64 uint32_t* samplestoskip
)
68 n
= new_sample
/ ape_ctx
->blocksperframe
;
69 if (n
>= ape_ctx
->numseekpoints
)
71 /* We don't have a seekpoint for that frame */
76 *filepos
= ape_ctx
->seektable
[n
];
77 *samplestoskip
= new_sample
- (n
* ape_ctx
->blocksperframe
);
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
)
97 while ((*currentframe
< ape_ctx
->totalframes
) &&
98 (*currentframe
< ape_ctx
->numseekpoints
) &&
99 (resume_offset
> ape_ctx
->seektable
[*currentframe
]))
102 *samplesdone
+= ape_ctx
->blocksperframe
;
105 if ((*currentframe
> 0) &&
106 (ape_ctx
->seektable
[*currentframe
] > resume_offset
)) {
108 *samplesdone
-= ape_ctx
->blocksperframe
;
111 newfilepos
= ape_ctx
->seektable
[*currentframe
];
113 /* APE's bytestream is weird... */
114 *firstbyte
= 3 - (newfilepos
& 3);
117 ci
->seek_buffer(newfilepos
);
119 /* We estimate where we were in the current frame, based on the
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
;
138 uint32_t currentframe
;
140 uint32_t samplestoskip
;
143 unsigned char* inbuffer
;
144 uint32_t blockstodecode
;
147 size_t resume_offset
;
149 /* Generic codec initialisation */
150 ci
->configure(DSP_SET_SAMPLE_DEPTH
, APE_OUTPUT_DEPTH
-1);
156 /* Remember the resume position - when the codec is opened, the
157 playback engine will reset it. */
158 resume_offset
= ci
->id3
->offset
;
161 LOGF("APE: Error initialising codec\n");
162 retval
= CODEC_ERROR
;
166 while (!*ci
->taginfo_ready
&& !ci
->stop_codec
)
169 inbuffer
= ci
->request_buffer(&bytesleft
, INPUT_CHUNKSIZE
);
171 /* Read the file headers to populate the ape_ctx struct */
172 if (ape_parseheaderbuf(inbuffer
,&ape_ctx
) < 0) {
173 LOGF("APE: Error reading header\n");
174 retval
= 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
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 */
193 for(i
= 0; i
< ape_ctx
.numseekpoints
; i
++)
194 ape_ctx
.seektable
[i
] = swap32(ape_ctx
.seektable
[i
]);
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 */
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 ¤tframe
, &samplesdone
, &samplestoskip
, &firstbyte
);
220 firstbyte
= 3; /* Take account of the little-endian 32-bit byte ordering */
223 /* Initialise the buffer */
224 inbuffer
= ci
->request_buffer(&bytesleft
, INPUT_CHUNKSIZE
);
226 /* The main decoding loop - we decode the frames a small chunk at a time */
227 while (currentframe
< ape_ctx
.totalframes
)
230 /* Calculate how many blocks there are in this frame */
231 if (currentframe
== (ape_ctx
.totalframes
- 1))
232 nblocks
= ape_ctx
.finalframeblocks
;
234 nblocks
= ape_ctx
.blocksperframe
;
236 ape_ctx
.currentframeblocks
= nblocks
;
238 /* Initialise the frame decoder */
239 init_frame_decoder(&ape_ctx
, inbuffer
, &firstbyte
, &bytesconsumed
);
241 ci
->advance_buffer(bytesconsumed
);
242 inbuffer
= ci
->request_buffer(&bytesleft
, INPUT_CHUNKSIZE
);
244 /* Decode the frame a chunk at a time */
248 if (ci
->stop_codec
|| ci
->new_track
) {
252 /* Deal with any pending seek requests */
255 if (ape_calc_seekpos(&ape_ctx
,
256 ((ci
->seek_time
-1)/10) * (ci
->id3
->frequency
/100),
261 samplesdone
= currentframe
* ape_ctx
.blocksperframe
;
263 /* APE's bytestream is weird... */
264 firstbyte
= 3 - (newfilepos
& 3);
267 ci
->seek_buffer(newfilepos
);
268 inbuffer
= ci
->request_buffer(&bytesleft
, INPUT_CHUNKSIZE
);
271 goto frame_start
; /* Sorry... */
276 blockstodecode
= MIN(BLOCKS_PER_LOOP
, nblocks
);
278 if ((res
= decode_chunk(&ape_ctx
, inbuffer
, &firstbyte
,
281 blockstodecode
)) < 0)
283 /* Frame decoding error, abort */
284 LOGF("APE: Frame %lu, error %d\n",currentframe
,res
);
285 retval
= CODEC_ERROR
;
291 if (samplestoskip
> 0) {
292 if (samplestoskip
< blockstodecode
) {
293 ci
->pcmbuf_insert(decoded0
+ samplestoskip
,
294 decoded1
+ samplestoskip
,
295 blockstodecode
- samplestoskip
);
298 samplestoskip
-= blockstodecode
;
301 ci
->pcmbuf_insert(decoded0
, decoded1
, blockstodecode
);
304 samplesdone
+= blockstodecode
;
306 if (!samplestoskip
) {
307 /* Update the elapsed-time indicator */
308 elapsedtime
= (samplesdone
*10)/(ape_ctx
.samplerate
/100);
309 ci
->set_elapsed(elapsedtime
);
312 ci
->advance_buffer(bytesconsumed
);
313 inbuffer
= ci
->request_buffer(&bytesleft
, INPUT_CHUNKSIZE
);
315 /* Decrement the block count */
316 nblocks
-= blockstodecode
;
325 LOGF("APE: Decoded %ld samples\n",samplesdone
);
327 if (ci
->request_next_track())