summaryrefslogtreecommitdiff
path: root/lib/rbcodec/codecs/mpa.c
diff options
context:
space:
mode:
Diffstat (limited to 'lib/rbcodec/codecs/mpa.c')
-rw-r--r--lib/rbcodec/codecs/mpa.c521
1 files changed, 521 insertions, 0 deletions
diff --git a/lib/rbcodec/codecs/mpa.c b/lib/rbcodec/codecs/mpa.c
new file mode 100644
index 0000000000..f9bf7e600f
--- /dev/null
+++ b/lib/rbcodec/codecs/mpa.c
@@ -0,0 +1,521 @@
1/***************************************************************************
2 * __________ __ ___.
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7 * \/ \/ \/ \/ \/
8 * $Id$
9 *
10 * Copyright (C) 2005 Dave Chapman
11 *
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.
16 *
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"
23#include <codecs/libmad/mad.h>
24#include <inttypes.h>
25
26CODEC_HEADER
27
28#if NUM_CORES > 1 && !defined(MPEGPLAYER)
29#define MPA_SYNTH_ON_COP
30#endif
31
32static struct mad_stream stream IBSS_ATTR;
33static struct mad_frame frame IBSS_ATTR;
34static struct mad_synth synth IBSS_ATTR;
35
36#ifdef MPA_SYNTH_ON_COP
37static volatile short die IBSS_ATTR = 0; /*thread should die*/
38
39#if (CONFIG_CPU == PP5024) || (CONFIG_CPU == PP5022)
40static mad_fixed_t sbsample_prev[2][36][32] IBSS_ATTR;
41#else
42static mad_fixed_t sbsample_prev[2][36][32] SHAREDBSS_ATTR;
43#endif
44
45static struct semaphore synth_done_sem IBSS_ATTR;
46static struct semaphore synth_pending_sem IBSS_ATTR;
47#endif
48
49#define INPUT_CHUNK_SIZE 8192
50
51static mad_fixed_t mad_frame_overlap[2][32][18] IBSS_ATTR;
52static mad_fixed_t sbsample[2][36][32] IBSS_ATTR;
53
54static unsigned char mad_main_data[MAD_BUFFER_MDLEN] IBSS_ATTR;
55/* TODO: what latency does layer 1 have? */
56static int mpeg_latency[3] = { 0, 481, 529 };
57static int mpeg_framesize[3] = {384, 1152, 1152};
58
59static void init_mad(void)
60{
61 ci->memset(&stream, 0, sizeof(struct mad_stream));
62 ci->memset(&frame , 0, sizeof(struct mad_frame));
63 ci->memset(&synth , 0, sizeof(struct mad_synth));
64
65#ifdef MPA_SYNTH_ON_COP
66 frame.sbsample_prev = &sbsample_prev;
67 frame.sbsample = &sbsample;
68#else
69 frame.sbsample_prev = &sbsample;
70 frame.sbsample = &sbsample;
71#endif
72
73 /* We do this so libmad doesn't try to call codec_calloc(). This needs to
74 * be called before mad_stream_init(), mad_frame_inti() and
75 * mad_synth_init(). */
76 frame.overlap = &mad_frame_overlap;
77 stream.main_data = &mad_main_data;
78
79 /* Call mad initialization. Those will zero the arrays frame.overlap,
80 * frame.sbsample and frame.sbsample_prev. Therefore there is no need to
81 * zero them here. */
82 mad_stream_init(&stream);
83 mad_frame_init(&frame);
84 mad_synth_init(&synth);
85}
86
87static int get_file_pos(int newtime)
88{
89 int pos = -1;
90 struct mp3entry *id3 = ci->id3;
91
92 if (id3->vbr) {
93 /* Convert newtime and id3->length to seconds to
94 * avoid overflow */
95 unsigned int newtime_s = newtime/1000;
96 unsigned int length_s = id3->length/1000;
97
98 if (id3->has_toc) {
99 /* Use the TOC to find the new position */
100 unsigned int percent, remainder;
101 int curtoc, nexttoc, plen;
102
103 percent = (newtime_s*100) / length_s;
104 if (percent > 99)
105 percent = 99;
106
107 curtoc = id3->toc[percent];
108
109 if (percent < 99) {
110 nexttoc = id3->toc[percent+1];
111 } else {
112 nexttoc = 256;
113 }
114
115 pos = (id3->filesize/256)*curtoc;
116
117 /* Use the remainder to get a more accurate position */
118 remainder = (newtime_s*100) % length_s;
119 remainder = (remainder*100) / length_s;
120 plen = (nexttoc - curtoc)*(id3->filesize/256);
121 pos += (plen/100)*remainder;
122 } else {
123 /* No TOC exists, estimate the new position */
124 pos = (id3->filesize / length_s) * newtime_s;
125 }
126 } else if (id3->bitrate) {
127 pos = newtime * (id3->bitrate / 8);
128 } else {
129 return -1;
130 }
131
132 /* Don't seek right to the end of the file so that we can
133 transition properly to the next song */
134 if (pos >= (int)(id3->filesize - id3->id3v1len))
135 pos = id3->filesize - id3->id3v1len - 1;
136
137 /* id3->filesize excludes id3->first_frame_offset, so add it now */
138 pos += id3->first_frame_offset;
139
140 return pos;
141}
142
143static void set_elapsed(struct mp3entry* id3)
144{
145 unsigned long offset = id3->offset > id3->first_frame_offset ?
146 id3->offset - id3->first_frame_offset : 0;
147 unsigned long elapsed = id3->elapsed;
148
149 if ( id3->vbr ) {
150 if ( id3->has_toc ) {
151 /* calculate elapsed time using TOC */
152 int i;
153 unsigned int remainder, plen, relpos, nextpos;
154
155 /* find wich percent we're at */
156 for (i=0; i<100; i++ )
157 if ( offset < id3->toc[i] * (id3->filesize / 256) )
158 break;
159
160 i--;
161 if (i < 0)
162 i = 0;
163
164 relpos = id3->toc[i];
165
166 if (i < 99)
167 nextpos = id3->toc[i+1];
168 else
169 nextpos = 256;
170
171 remainder = offset - (relpos * (id3->filesize / 256));
172
173 /* set time for this percent (divide before multiply to prevent
174 overflow on long files. loss of precision is negligible on
175 short files) */
176 elapsed = i * (id3->length / 100);
177
178 /* calculate remainder time */
179 plen = (nextpos - relpos) * (id3->filesize / 256);
180 elapsed += (((remainder * 100) / plen) * (id3->length / 10000));
181 }
182 else {
183 /* no TOC exists. set a rough estimate using average bitrate */
184 int tpk = id3->length /
185 ((id3->filesize - id3->first_frame_offset - id3->id3v1len) /
186 1024);
187 elapsed = offset / 1024 * tpk;
188 }
189 }
190 else
191 {
192 /* constant bitrate, use exact calculation */
193 if (id3->bitrate != 0)
194 elapsed = offset / (id3->bitrate / 8);
195 }
196
197 ci->set_elapsed(elapsed);
198}
199
200#ifdef MPA_SYNTH_ON_COP
201
202/*
203 * Run the synthesis filter on the COProcessor
204 */
205
206static int mad_synth_thread_stack[DEFAULT_STACK_SIZE/sizeof(int)] IBSS_ATTR;
207
208static const unsigned char * const mad_synth_thread_name = "mp3dec";
209static unsigned int mad_synth_thread_id = 0;
210
211
212static void mad_synth_thread(void)
213{
214 while(1) {
215 ci->semaphore_release(&synth_done_sem);
216 ci->semaphore_wait(&synth_pending_sem, TIMEOUT_BLOCK);
217
218 if(die)
219 break;
220
221 mad_synth_frame(&synth, &frame);
222 }
223}
224
225/* wait for the synth thread to go idle which indicates a PCM frame has been
226 * synthesized */
227static inline void mad_synth_thread_wait_pcm(void)
228{
229 ci->semaphore_wait(&synth_done_sem, TIMEOUT_BLOCK);
230}
231
232/* increment the done semaphore - used after a wait for idle to preserve the
233 * semaphore count */
234static inline void mad_synth_thread_unwait_pcm(void)
235{
236 ci->semaphore_release(&synth_done_sem);
237}
238
239/* after synth thread has gone idle - switch decoded frames and commence
240 * synthesis on it */
241static void mad_synth_thread_ready(void)
242{
243 mad_fixed_t (*temp)[2][36][32];
244
245 /*circular buffer that holds 2 frames' samples*/
246 temp=frame.sbsample;
247 frame.sbsample = frame.sbsample_prev;
248 frame.sbsample_prev=temp;
249
250 ci->semaphore_release(&synth_pending_sem);
251}
252
253static bool mad_synth_thread_create(void)
254{
255 ci->semaphore_init(&synth_done_sem, 1, 0);
256 ci->semaphore_init(&synth_pending_sem, 1, 0);
257
258 mad_synth_thread_id = ci->create_thread(mad_synth_thread,
259 mad_synth_thread_stack,
260 sizeof(mad_synth_thread_stack), 0,
261 mad_synth_thread_name
262 IF_PRIO(, PRIORITY_PLAYBACK)
263 IF_COP(, COP));
264
265 if (mad_synth_thread_id == 0)
266 return false;
267
268 return true;
269}
270
271static void mad_synth_thread_quit(void)
272{
273 /* mop up COP thread */
274 die = 1;
275 ci->semaphore_release(&synth_pending_sem);
276 ci->thread_wait(mad_synth_thread_id);
277 ci->commit_discard_dcache();
278}
279#else
280static inline void mad_synth_thread_ready(void)
281{
282 mad_synth_frame(&synth, &frame);
283}
284
285static inline bool mad_synth_thread_create(void)
286{
287 return true;
288}
289
290static inline void mad_synth_thread_quit(void)
291{
292}
293
294static inline void mad_synth_thread_wait_pcm(void)
295{
296}
297
298static inline void mad_synth_thread_unwait_pcm(void)
299{
300}
301#endif /* MPA_SYNTH_ON_COP */
302
303/* this is the codec entry point */
304enum codec_status codec_main(enum codec_entry_call_reason reason)
305{
306 if (reason == CODEC_LOAD) {
307 /* Create a decoder instance */
308 if (codec_init())
309 return CODEC_ERROR;
310
311 ci->configure(DSP_SET_SAMPLE_DEPTH, MAD_F_FRACBITS);
312
313 /* does nothing on 1 processor systems except return true */
314 if(!mad_synth_thread_create())
315 return CODEC_ERROR;
316 }
317 else if (reason == CODEC_UNLOAD) {
318 /* mop up COP thread - MT only */
319 mad_synth_thread_quit();
320 }
321
322 return CODEC_OK;
323}
324
325/* this is called for each file to process */
326enum codec_status codec_run(void)
327{
328 size_t size;
329 int file_end;
330 int samples_to_skip; /* samples to skip in total for this file (at start) */
331 char *inputbuffer;
332 int64_t samplesdone;
333 int stop_skip, start_skip;
334 int current_stereo_mode = -1;
335 unsigned long current_frequency = 0;
336 int framelength;
337 int padding = MAD_BUFFER_GUARD; /* to help mad decode the last frame */
338 intptr_t param;
339
340 /* Reinitializing seems to be necessary to avoid playback quircks when seeking. */
341 init_mad();
342
343 file_end = 0;
344
345 ci->configure(DSP_SWITCH_FREQUENCY, ci->id3->frequency);
346 current_frequency = ci->id3->frequency;
347 codec_set_replaygain(ci->id3);
348
349 if (ci->id3->offset) {
350 ci->seek_buffer(ci->id3->offset);
351 set_elapsed(ci->id3);
352 }
353 else
354 ci->seek_buffer(ci->id3->first_frame_offset);
355
356 if (ci->id3->lead_trim >= 0 && ci->id3->tail_trim >= 0) {
357 stop_skip = ci->id3->tail_trim - mpeg_latency[ci->id3->layer];
358 if (stop_skip < 0) stop_skip = 0;
359 start_skip = ci->id3->lead_trim + mpeg_latency[ci->id3->layer];
360 } else {
361 stop_skip = 0;
362 /* We want to skip this amount anyway */
363 start_skip = mpeg_latency[ci->id3->layer];
364 }
365
366 /* Libmad will not decode the last frame without 8 bytes of extra padding
367 in the buffer. So, we can trick libmad into not decoding the last frame
368 if we are to skip it entirely and then cut the appropriate samples from
369 final frame that we did decode. Note, if all tags (ID3, APE) are not
370 properly stripped from the end of the file, this trick will not work. */
371 if (stop_skip >= mpeg_framesize[ci->id3->layer]) {
372 padding = 0;
373 stop_skip -= mpeg_framesize[ci->id3->layer];
374 } else {
375 padding = MAD_BUFFER_GUARD;
376 }
377
378 samplesdone = ((int64_t)ci->id3->elapsed) * current_frequency / 1000;
379
380 /* Don't skip any samples unless we start at the beginning. */
381 if (samplesdone > 0)
382 samples_to_skip = 0;
383 else
384 samples_to_skip = start_skip;
385
386 framelength = 0;
387
388 /* This is the decoding loop. */
389 while (1) {
390 enum codec_command_action action = ci->get_command(&param);
391
392 if (action == CODEC_ACTION_HALT)
393 break;
394
395 if (action == CODEC_ACTION_SEEK_TIME) {
396 int newpos;
397
398 /*make sure the synth thread is idle before seeking - MT only*/
399 mad_synth_thread_wait_pcm();
400 mad_synth_thread_unwait_pcm();
401
402 samplesdone = ((int64_t)param)*current_frequency/1000;
403
404 if (param == 0) {
405 newpos = ci->id3->first_frame_offset;
406 samples_to_skip = start_skip;
407 } else {
408 newpos = get_file_pos(param);
409 samples_to_skip = 0;
410 }
411
412 if (!ci->seek_buffer(newpos))
413 {
414 ci->seek_complete();
415 break;
416 }
417
418 ci->set_elapsed((samplesdone * 1000) / current_frequency);
419 ci->seek_complete();
420 init_mad();
421 framelength = 0;
422 }
423
424 /* Lock buffers */
425 if (stream.error == 0) {
426 inputbuffer = ci->request_buffer(&size, INPUT_CHUNK_SIZE);
427 if (size == 0 || inputbuffer == NULL)
428 break;
429 mad_stream_buffer(&stream, (unsigned char *)inputbuffer,
430 size + padding);
431 }
432
433 if (mad_frame_decode(&frame, &stream)) {
434 if (stream.error == MAD_ERROR_BUFLEN) {
435 /* This makes the codec support partially corrupted files */
436 if (file_end == 30)
437 break;
438
439 /* Fill the buffer */
440 if (stream.next_frame)
441 ci->advance_buffer(stream.next_frame - stream.buffer);
442 else
443 ci->advance_buffer(size);
444 stream.error = 0; /* Must get new inputbuffer next time */
445 file_end++;
446 continue;
447 } else if (MAD_RECOVERABLE(stream.error)) {
448 /* Probably syncing after a seek */
449 continue;
450 } else {
451 /* Some other unrecoverable error */
452 return CODEC_ERROR;
453 }
454 }
455
456 /* Do the pcmbuf insert here. Note, this is the PREVIOUS frame's pcm
457 data (not the one just decoded above). When we exit the decoding
458 loop we will need to process the final frame that was decoded. */
459 mad_synth_thread_wait_pcm();
460
461 if (framelength > 0) {
462
463 /* In case of a mono file, the second array will be ignored. */
464 ci->pcmbuf_insert(&synth.pcm.samples[0][samples_to_skip],
465 &synth.pcm.samples[1][samples_to_skip],
466 framelength);
467
468 /* Only skip samples for the first frame added. */
469 samples_to_skip = 0;
470 }
471
472 /* Initiate PCM synthesis on the COP (MT) or perform it here (ST) */
473 mad_synth_thread_ready();
474
475 /* Check if sample rate and stereo settings changed in this frame. */
476 if (frame.header.samplerate != current_frequency) {
477 current_frequency = frame.header.samplerate;
478 ci->configure(DSP_SWITCH_FREQUENCY, current_frequency);
479 }
480 if (MAD_NCHANNELS(&frame.header) == 2) {
481 if (current_stereo_mode != STEREO_NONINTERLEAVED) {
482 ci->configure(DSP_SET_STEREO_MODE, STEREO_NONINTERLEAVED);
483 current_stereo_mode = STEREO_NONINTERLEAVED;
484 }
485 } else {
486 if (current_stereo_mode != STEREO_MONO) {
487 ci->configure(DSP_SET_STEREO_MODE, STEREO_MONO);
488 current_stereo_mode = STEREO_MONO;
489 }
490 }
491
492 if (stream.next_frame)
493 ci->advance_buffer(stream.next_frame - stream.buffer);
494 else
495 ci->advance_buffer(size);
496 stream.error = 0; /* Must get new inputbuffer next time */
497 file_end = 0;
498
499 framelength = synth.pcm.length - samples_to_skip;
500 if (framelength < 0) {
501 framelength = 0;
502 samples_to_skip -= synth.pcm.length;
503 }
504
505 samplesdone += framelength;
506 ci->set_elapsed((samplesdone * 1000) / current_frequency);
507 }
508
509 /* wait for synth idle - MT only*/
510 mad_synth_thread_wait_pcm();
511 mad_synth_thread_unwait_pcm();
512
513 /* Finish the remaining decoded frame.
514 Cut the required samples from the end. */
515 if (framelength > stop_skip){
516 ci->pcmbuf_insert(synth.pcm.samples[0], synth.pcm.samples[1],
517 framelength - stop_skip);
518 }
519
520 return CODEC_OK;
521}