1 /***************************************************************************
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
10 * Copyright (C) 2009 Mohamed Tarek
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/librm/rm.h>
24 #include <inttypes.h> /* Needed by a52.h */
25 #include <codecs/liba52/config-a52.h>
26 #include <codecs/liba52/a52.h>
30 #define BUFFER_SIZE 4096
32 #define A52_SAMPLESPERFRAME (6*256)
34 static a52_state_t
*state
;
35 unsigned long samplesdone
;
36 unsigned long frequency
;
40 static void init_rm(RMContext
*rmctx
)
42 memcpy(rmctx
, (void*)(( (intptr_t)ci
->id3
->id3v2buf
+ 3 ) &~ 3), sizeof(RMContext
));
45 /* used outside liba52 */
46 static uint8_t buf
[3840] IBSS_ATTR
;
48 static inline void output_audio(sample_t
*samples
)
51 ci
->pcmbuf_insert(&samples
[0], &samples
[256], 256);
54 static void a52_decode_data(uint8_t *start
, uint8_t *end
)
56 static uint8_t *bufptr
= buf
;
57 static uint8_t *bufpos
= buf
+ 7;
59 * sample_rate and flags are static because this routine could
60 * exit between the a52_syncinfo() and the ao_setup(), and we want
61 * to have the same values when we get back !
63 static int sample_rate
;
72 if (len
> bufpos
- bufptr
)
73 len
= bufpos
- bufptr
;
74 memcpy(bufptr
, start
, len
);
77 if (bufptr
== bufpos
) {
78 if (bufpos
== buf
+ 7) {
81 length
= a52_syncinfo(buf
, &flags
, &sample_rate
, &bit_rate
);
84 for (bufptr
= buf
; bufptr
< buf
+ 6; bufptr
++)
85 bufptr
[0] = bufptr
[1];
88 bufpos
= buf
+ length
;
90 /* Unity gain is 1 << 26, and we want to end up on 28 bits
91 of precision instead of the default 30.
93 level_t level
= 1 << 24;
97 /* This is the configuration for the downmixing: */
98 flags
= A52_STEREO
| A52_ADJUST_LEVEL
;
100 if (a52_frame(state
, buf
, &flags
, &level
, bias
))
102 a52_dynrng(state
, NULL
, NULL
);
103 frequency
= sample_rate
;
105 /* An A52 frame consists of 6 blocks of 256 samples
106 So we decode and output them one block at a time */
107 for (i
= 0; i
< 6; i
++) {
108 if (a52_block(state
))
110 output_audio(a52_samples(state
));
113 ci
->set_elapsed(samplesdone
/(frequency
/1000));
118 //logf("Error decoding A52 stream\n");
127 /* this is the codec entry point */
128 enum codec_status
codec_main(void)
132 int retval
, consumed
, packet_offset
;
134 /* Generic codec initialisation */
135 ci
->configure(DSP_SET_STEREO_MODE
, STEREO_NONINTERLEAVED
);
136 ci
->configure(DSP_SET_SAMPLE_DEPTH
, 28);
140 retval
= CODEC_ERROR
;
144 while (!ci
->taginfo_ready
)
147 ci
->configure(DSP_SWITCH_FREQUENCY
, ci
->id3
->frequency
);
148 codec_set_replaygain(ci
->id3
);
152 ci
->memset(&rmctx
,0,sizeof(RMContext
));
153 ci
->memset(&pkt
,0,sizeof(RMPacket
));
156 /* Seek to the first packet */
157 ci
->advance_buffer(rmctx
.data_offset
+ DATA_HEADER_SIZE
);
159 /* The main decoding loop */
160 while(pkt
.timestamp
< rmctx
.duration
) {
162 if (ci
->stop_codec
|| ci
->new_track
)
166 packet_offset
= ci
->seek_time
/ (((rmctx
.block_align
+ PACKET_HEADER_SIZE
)*8*1000)/rmctx
.bit_rate
);
167 ci
->seek_buffer(rmctx
.data_offset
+ DATA_HEADER_SIZE
+ packet_offset
*(rmctx
.block_align
+ PACKET_HEADER_SIZE
));
168 samplesdone
= A52_SAMPLESPERFRAME
* packet_offset
;
172 filebuf
= ci
->request_buffer(&n
, rmctx
.block_align
+ PACKET_HEADER_SIZE
);
173 consumed
= rm_get_packet(&filebuf
, &rmctx
, &pkt
);
175 DEBUGF("rm_get_packet failed\n");
178 a52_decode_data(filebuf
, filebuf
+ rmctx
.block_align
);
179 ci
->advance_buffer(pkt
.length
);
184 if (ci
->request_next_track())