1 /***************************************************************************
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
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 ****************************************************************************/
22 #include <codecs/demac/libdemac/demac.h>
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
59 bool ape_calc_seekpos(struct ape_ctx_t
* ape_ctx
,
63 uint32_t* samplestoskip
)
67 n
= new_sample
/ ape_ctx
->blocksperframe
;
68 if (n
>= ape_ctx
->numseekpoints
)
70 /* We don't have a seekpoint for that frame */
75 *filepos
= ape_ctx
->seektable
[n
];
76 *samplestoskip
= new_sample
- (n
* ape_ctx
->blocksperframe
);
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
)
96 while ((*currentframe
< ape_ctx
->totalframes
) &&
97 (*currentframe
< ape_ctx
->numseekpoints
) &&
98 (resume_offset
> ape_ctx
->seektable
[*currentframe
]))
101 *samplesdone
+= ape_ctx
->blocksperframe
;
104 if ((*currentframe
> 0) &&
105 (ape_ctx
->seektable
[*currentframe
] > resume_offset
)) {
107 *samplesdone
-= ape_ctx
->blocksperframe
;
110 newfilepos
= ape_ctx
->seektable
[*currentframe
];
112 /* APE's bytestream is weird... */
113 *firstbyte
= 3 - (newfilepos
& 3);
116 ci
->seek_buffer(newfilepos
);
118 /* We estimate where we were in the current frame, based on the
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
;
137 uint32_t currentframe
;
139 uint32_t samplestoskip
;
142 unsigned char* inbuffer
;
143 uint32_t blockstodecode
;
146 size_t resume_offset
;
148 /* Generic codec initialisation */
149 ci
->configure(CODEC_SET_FILEBUF_WATERMARK
, 1024*512);
150 ci
->configure(CODEC_SET_FILEBUF_CHUNKSIZE
, 1024*128);
152 ci
->configure(DSP_SET_SAMPLE_DEPTH
, APE_OUTPUT_DEPTH
-1);
158 /* Remember the resume position - when the codec is opened, the
159 playback engine will reset it. */
160 resume_offset
= ci
->id3
->offset
;
163 LOGF("APE: Error initialising codec\n");
164 retval
= CODEC_ERROR
;
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
;
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
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 */
192 for(i
= 0; i
< ape_ctx
.numseekpoints
; i
++)
193 ape_ctx
.seektable
[i
] = swap32(ape_ctx
.seektable
[i
]);
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 while (!*ci
->taginfo_ready
&& !ci
->stop_codec
)
205 ci
->configure(DSP_SWITCH_FREQUENCY
, ape_ctx
.samplerate
);
206 ci
->configure(DSP_SET_STEREO_MODE
, ape_ctx
.channels
== 1 ?
207 STEREO_MONO
: STEREO_NONINTERLEAVED
);
208 codec_set_replaygain(ci
->id3
);
210 /* The main decoding loop */
213 /* The resume offset is a value in bytes - we need to
214 turn it into a frame number and samplestoskip value */
216 ape_resume(&ape_ctx
, resume_offset
,
217 ¤tframe
, &samplesdone
, &samplestoskip
, &firstbyte
);
222 firstbyte
= 3; /* Take account of the little-endian 32-bit byte ordering */
225 /* Initialise the buffer */
226 inbuffer
= ci
->request_buffer(&bytesleft
, INPUT_CHUNKSIZE
);
228 /* The main decoding loop - we decode the frames a small chunk at a time */
229 while (currentframe
< ape_ctx
.totalframes
)
232 /* Calculate how many blocks there are in this frame */
233 if (currentframe
== (ape_ctx
.totalframes
- 1))
234 nblocks
= ape_ctx
.finalframeblocks
;
236 nblocks
= ape_ctx
.blocksperframe
;
238 ape_ctx
.currentframeblocks
= nblocks
;
240 /* Initialise the frame decoder */
241 init_frame_decoder(&ape_ctx
, inbuffer
, &firstbyte
, &bytesconsumed
);
243 ci
->advance_buffer(bytesconsumed
);
244 inbuffer
= ci
->request_buffer(&bytesleft
, INPUT_CHUNKSIZE
);
246 /* Decode the frame a chunk at a time */
250 if (ci
->stop_codec
|| ci
->new_track
) {
254 /* Deal with any pending seek requests */
257 if (ape_calc_seekpos(&ape_ctx
,
258 ((ci
->seek_time
-1)/10) * (ci
->id3
->frequency
/100),
263 samplesdone
= currentframe
* ape_ctx
.blocksperframe
;
265 /* APE's bytestream is weird... */
266 firstbyte
= 3 - (newfilepos
& 3);
269 ci
->seek_buffer(newfilepos
);
270 inbuffer
= ci
->request_buffer(&bytesleft
, INPUT_CHUNKSIZE
);
273 goto frame_start
; /* Sorry... */
278 blockstodecode
= MIN(BLOCKS_PER_LOOP
, nblocks
);
280 if ((res
= decode_chunk(&ape_ctx
, inbuffer
, &firstbyte
,
283 blockstodecode
)) < 0)
285 /* Frame decoding error, abort */
286 LOGF("APE: Frame %d, error %d\n",currentframe
,res
);
287 retval
= CODEC_ERROR
;
293 if (samplestoskip
> 0) {
294 if (samplestoskip
< blockstodecode
) {
295 ci
->pcmbuf_insert(decoded0
+ samplestoskip
,
296 decoded1
+ samplestoskip
,
297 blockstodecode
- samplestoskip
);
300 samplestoskip
-= blockstodecode
;
303 ci
->pcmbuf_insert(decoded0
, decoded1
, blockstodecode
);
306 samplesdone
+= blockstodecode
;
308 if (!samplestoskip
) {
309 /* Update the elapsed-time indicator */
310 elapsedtime
= (samplesdone
*10)/(ape_ctx
.samplerate
/100);
311 ci
->set_elapsed(elapsedtime
);
314 ci
->advance_buffer(bytesconsumed
);
315 inbuffer
= ci
->request_buffer(&bytesleft
, INPUT_CHUNKSIZE
);
317 /* Decrement the block count */
318 nblocks
-= blockstodecode
;
327 LOGF("APE: Decoded %ld samples\n",samplesdone
);
329 if (ci
->request_next_track())