Fix voicing of incorrect run time (top time instead of run time). Simplify runtime...
[kugel-rb.git] / apps / codecs / mpa.c
blob1181c1e1fb2055ee4d910da4539a33e7504f472a
1 /***************************************************************************
2 * __________ __ ___.
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7 * \/ \/ \/ \/ \/
8 * $Id$
10 * Copyright (C) 2005 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/libmad/mad.h>
24 #include <inttypes.h>
26 CODEC_HEADER
28 struct mad_stream stream IBSS_ATTR;
29 struct mad_frame frame IBSS_ATTR;
30 struct mad_synth synth IBSS_ATTR;
32 /* The following function is used inside libmad - let's hope it's never
33 called.
36 void abort(void) {
39 #define INPUT_CHUNK_SIZE 8192
41 mad_fixed_t mad_frame_overlap[2][32][18] IBSS_ATTR;
42 unsigned char mad_main_data[MAD_BUFFER_MDLEN] IBSS_ATTR;
43 /* TODO: what latency does layer 1 have? */
44 int mpeg_latency[3] = { 0, 481, 529 };
45 int mpeg_framesize[3] = {384, 1152, 1152};
47 void init_mad(void)
49 ci->memset(&stream, 0, sizeof(struct mad_stream));
50 ci->memset(&frame, 0, sizeof(struct mad_frame));
51 ci->memset(&synth, 0, sizeof(struct mad_synth));
53 mad_stream_init(&stream);
54 mad_frame_init(&frame);
55 mad_synth_init(&synth);
57 /* We do this so libmad doesn't try to call codec_calloc() */
58 ci->memset(mad_frame_overlap, 0, sizeof(mad_frame_overlap));
59 frame.overlap = &mad_frame_overlap;
60 stream.main_data = &mad_main_data;
63 int get_file_pos(int newtime)
65 int pos = -1;
66 struct mp3entry *id3 = ci->id3;
68 if (id3->vbr) {
69 if (id3->has_toc) {
70 /* Use the TOC to find the new position */
71 unsigned int percent, remainder;
72 int curtoc, nexttoc, plen;
74 percent = (newtime*100) / id3->length;
75 if (percent > 99)
76 percent = 99;
78 curtoc = id3->toc[percent];
80 if (percent < 99) {
81 nexttoc = id3->toc[percent+1];
82 } else {
83 nexttoc = 256;
86 pos = (id3->filesize/256)*curtoc;
88 /* Use the remainder to get a more accurate position */
89 remainder = (newtime*100) % id3->length;
90 remainder = (remainder*100) / id3->length;
91 plen = (nexttoc - curtoc)*(id3->filesize/256);
92 pos += (plen/100)*remainder;
93 } else {
94 /* No TOC exists, estimate the new position */
95 pos = (id3->filesize / (id3->length / 1000)) *
96 (newtime / 1000);
98 } else if (id3->bitrate) {
99 pos = newtime * (id3->bitrate / 8);
100 } else {
101 return -1;
104 pos += id3->first_frame_offset;
106 /* Don't seek right to the end of the file so that we can
107 transition properly to the next song */
108 if (pos >= (int)(id3->filesize - id3->id3v1len))
109 pos = id3->filesize - id3->id3v1len - 1;
111 return pos;
114 static void set_elapsed(struct mp3entry* id3)
116 unsigned long offset = id3->offset > id3->first_frame_offset ?
117 id3->offset - id3->first_frame_offset : 0;
119 if ( id3->vbr ) {
120 if ( id3->has_toc ) {
121 /* calculate elapsed time using TOC */
122 int i;
123 unsigned int remainder, plen, relpos, nextpos;
125 /* find wich percent we're at */
126 for (i=0; i<100; i++ )
127 if ( offset < id3->toc[i] * (id3->filesize / 256) )
128 break;
130 i--;
131 if (i < 0)
132 i = 0;
134 relpos = id3->toc[i];
136 if (i < 99)
137 nextpos = id3->toc[i+1];
138 else
139 nextpos = 256;
141 remainder = offset - (relpos * (id3->filesize / 256));
143 /* set time for this percent (divide before multiply to prevent
144 overflow on long files. loss of precision is negligible on
145 short files) */
146 id3->elapsed = i * (id3->length / 100);
148 /* calculate remainder time */
149 plen = (nextpos - relpos) * (id3->filesize / 256);
150 id3->elapsed += (((remainder * 100) / plen) *
151 (id3->length / 10000));
153 else {
154 /* no TOC exists. set a rough estimate using average bitrate */
155 int tpk = id3->length /
156 ((id3->filesize - id3->first_frame_offset - id3->id3v1len) /
157 1024);
158 id3->elapsed = offset / 1024 * tpk;
161 else
163 /* constant bitrate, use exact calculation */
164 if (id3->bitrate != 0)
165 id3->elapsed = offset / (id3->bitrate / 8);
169 /* this is the codec entry point */
170 enum codec_status codec_main(void)
172 int status;
173 size_t size;
174 int file_end;
175 int samples_to_skip; /* samples to skip in total for this file (at start) */
176 char *inputbuffer;
177 int64_t samplesdone;
178 int stop_skip, start_skip;
179 int current_stereo_mode = -1;
180 unsigned long current_frequency = 0;
181 int framelength;
182 int padding = MAD_BUFFER_GUARD; /* to help mad decode the last frame */
184 if (codec_init())
185 return CODEC_ERROR;
187 /* Create a decoder instance */
189 ci->configure(DSP_SET_SAMPLE_DEPTH, MAD_F_FRACBITS);
191 next_track:
192 status = CODEC_OK;
194 /* Reinitializing seems to be necessary to avoid playback quircks when seeking. */
195 init_mad();
197 file_end = 0;
198 while (!*ci->taginfo_ready && !ci->stop_codec)
199 ci->sleep(1);
201 ci->configure(DSP_SWITCH_FREQUENCY, ci->id3->frequency);
202 current_frequency = ci->id3->frequency;
203 codec_set_replaygain(ci->id3);
205 if (ci->id3->offset) {
206 ci->seek_buffer(ci->id3->offset);
207 set_elapsed(ci->id3);
209 else
210 ci->seek_buffer(ci->id3->first_frame_offset);
212 if (ci->id3->lead_trim >= 0 && ci->id3->tail_trim >= 0) {
213 stop_skip = ci->id3->tail_trim - mpeg_latency[ci->id3->layer];
214 if (stop_skip < 0) stop_skip = 0;
215 start_skip = ci->id3->lead_trim + mpeg_latency[ci->id3->layer];
216 } else {
217 stop_skip = 0;
218 /* We want to skip this amount anyway */
219 start_skip = mpeg_latency[ci->id3->layer];
222 /* Libmad will not decode the last frame without 8 bytes of extra padding
223 in the buffer. So, we can trick libmad into not decoding the last frame
224 if we are to skip it entirely and then cut the appropriate samples from
225 final frame that we did decode. Note, if all tags (ID3, APE) are not
226 properly stripped from the end of the file, this trick will not work. */
227 if (stop_skip >= mpeg_framesize[ci->id3->layer]) {
228 padding = 0;
229 stop_skip -= mpeg_framesize[ci->id3->layer];
230 } else {
231 padding = MAD_BUFFER_GUARD;
234 samplesdone = ((int64_t)ci->id3->elapsed) * current_frequency / 1000;
236 /* Don't skip any samples unless we start at the beginning. */
237 if (samplesdone > 0)
238 samples_to_skip = 0;
239 else
240 samples_to_skip = start_skip;
242 framelength = 0;
244 /* This is the decoding loop. */
245 while (1) {
246 ci->yield();
247 if (ci->stop_codec || ci->new_track)
248 break;
250 if (ci->seek_time) {
251 int newpos;
253 samplesdone = ((int64_t)(ci->seek_time-1))*current_frequency/1000;
255 if (ci->seek_time-1 == 0) {
256 newpos = ci->id3->first_frame_offset;
257 samples_to_skip = start_skip;
258 } else {
259 newpos = get_file_pos(ci->seek_time-1);
260 samples_to_skip = 0;
263 if (!ci->seek_buffer(newpos))
264 break;
265 ci->seek_complete();
266 init_mad();
267 framelength = 0;
270 /* Lock buffers */
271 if (stream.error == 0) {
272 inputbuffer = ci->request_buffer(&size, INPUT_CHUNK_SIZE);
273 if (size == 0 || inputbuffer == NULL)
274 break;
275 mad_stream_buffer(&stream, (unsigned char *)inputbuffer,
276 size + padding);
279 if (mad_frame_decode(&frame, &stream)) {
280 if (stream.error == MAD_FLAG_INCOMPLETE
281 || stream.error == MAD_ERROR_BUFLEN) {
282 /* This makes the codec support partially corrupted files */
283 if (file_end == 30)
284 break;
286 /* Fill the buffer */
287 if (stream.next_frame)
288 ci->advance_buffer_loc((void *)stream.next_frame);
289 else
290 ci->advance_buffer(size);
291 stream.error = 0;
292 file_end++;
293 continue;
294 } else if (MAD_RECOVERABLE(stream.error)) {
295 continue;
296 } else {
297 /* Some other unrecoverable error */
298 status = CODEC_ERROR;
299 break;
301 break;
304 file_end = 0;
306 /* Do the pcmbuf insert here. Note, this is the PREVIOUS frame's pcm
307 data (not the one just decoded above). When we exit the decoding
308 loop we will need to process the final frame that was decoded. */
309 if (framelength > 0) {
310 /* In case of a mono file, the second array will be ignored. */
311 ci->pcmbuf_insert(&synth.pcm.samples[0][samples_to_skip],
312 &synth.pcm.samples[1][samples_to_skip],
313 framelength);
315 /* Only skip samples for the first frame added. */
316 samples_to_skip = 0;
319 mad_synth_frame(&synth, &frame);
321 /* Check if sample rate and stereo settings changed in this frame. */
322 if (frame.header.samplerate != current_frequency) {
323 current_frequency = frame.header.samplerate;
324 ci->configure(DSP_SWITCH_FREQUENCY, current_frequency);
326 if (MAD_NCHANNELS(&frame.header) == 2) {
327 if (current_stereo_mode != STEREO_NONINTERLEAVED) {
328 ci->configure(DSP_SET_STEREO_MODE, STEREO_NONINTERLEAVED);
329 current_stereo_mode = STEREO_NONINTERLEAVED;
331 } else {
332 if (current_stereo_mode != STEREO_MONO) {
333 ci->configure(DSP_SET_STEREO_MODE, STEREO_MONO);
334 current_stereo_mode = STEREO_MONO;
338 if (stream.next_frame)
339 ci->advance_buffer_loc((void *)stream.next_frame);
340 else
341 ci->advance_buffer(size);
343 framelength = synth.pcm.length - samples_to_skip;
344 if (framelength < 0) {
345 framelength = 0;
346 samples_to_skip -= synth.pcm.length;
349 samplesdone += framelength;
350 ci->set_elapsed(samplesdone / (current_frequency / 1000));
353 /* Finish the remaining decoded frame.
354 Cut the required samples from the end. */
355 if (framelength > stop_skip)
356 ci->pcmbuf_insert(synth.pcm.samples[0], synth.pcm.samples[1],
357 framelength - stop_skip);
359 stream.error = 0;
361 if (ci->request_next_track())
362 goto next_track;
364 return status;