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 static unsigned long samplesdone
;
36 static unsigned long frequency
;
37 static RMContext rmctx
;
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 /* The following two functions, a52_decode_data and output_audio are taken from apps/codecs/a52.c */
49 static inline void output_audio(sample_t
*samples
)
52 ci
->pcmbuf_insert(&samples
[0], &samples
[256], 256);
55 static void a52_decode_data(uint8_t *start
, uint8_t *end
)
57 static uint8_t *bufptr
= buf
;
58 static uint8_t *bufpos
= buf
+ 7;
60 * sample_rate and flags are static because this routine could
61 * exit between the a52_syncinfo() and the ao_setup(), and we want
62 * to have the same values when we get back !
64 static int sample_rate
;
73 if (len
> bufpos
- bufptr
)
74 len
= bufpos
- bufptr
;
75 memcpy(bufptr
, start
, len
);
78 if (bufptr
== bufpos
) {
79 if (bufpos
== buf
+ 7) {
82 length
= a52_syncinfo(buf
, &flags
, &sample_rate
, &bit_rate
);
85 for (bufptr
= buf
; bufptr
< buf
+ 6; bufptr
++)
86 bufptr
[0] = bufptr
[1];
89 bufpos
= buf
+ length
;
91 /* Unity gain is 1 << 26, and we want to end up on 28 bits
92 of precision instead of the default 30.
94 level_t level
= 1 << 24;
98 /* This is the configuration for the downmixing: */
99 flags
= A52_STEREO
| A52_ADJUST_LEVEL
;
101 if (a52_frame(state
, buf
, &flags
, &level
, bias
))
103 a52_dynrng(state
, NULL
, NULL
);
104 frequency
= sample_rate
;
106 /* An A52 frame consists of 6 blocks of 256 samples
107 So we decode and output them one block at a time */
108 for (i
= 0; i
< 6; i
++) {
109 if (a52_block(state
))
111 output_audio(a52_samples(state
));
114 ci
->set_elapsed(samplesdone
/(frequency
/1000));
119 //logf("Error decoding A52 stream\n");
128 /* this is the codec entry point */
129 enum codec_status
codec_main(void)
133 int retval
, consumed
, packet_offset
;
134 int playback_on
= -1;
135 size_t resume_offset
= ci
->id3
->offset
;
137 /* Generic codec initialisation */
138 ci
->configure(DSP_SET_STEREO_MODE
, STEREO_NONINTERLEAVED
);
139 ci
->configure(DSP_SET_SAMPLE_DEPTH
, 28);
143 retval
= CODEC_ERROR
;
147 while (!ci
->taginfo_ready
)
150 ci
->configure(DSP_SWITCH_FREQUENCY
, ci
->id3
->frequency
);
151 codec_set_replaygain(ci
->id3
);
155 ci
->memset(&rmctx
,0,sizeof(RMContext
));
156 ci
->memset(&pkt
,0,sizeof(RMPacket
));
159 /* check for a mid-track resume and force a seek time accordingly */
160 if(resume_offset
> rmctx
.data_offset
+ DATA_HEADER_SIZE
) {
161 resume_offset
-= rmctx
.data_offset
+ DATA_HEADER_SIZE
;
162 /* put number of subpackets to skip in resume_offset */
163 resume_offset
/= (rmctx
.block_align
+ PACKET_HEADER_SIZE
);
164 ci
->seek_time
= (int)resume_offset
* ((rmctx
.block_align
* 8 * 1000)/rmctx
.bit_rate
);
167 /* Seek to the first packet */
168 ci
->advance_buffer(rmctx
.data_offset
+ DATA_HEADER_SIZE
);
170 /* The main decoding loop */
171 while((unsigned)rmctx
.audio_pkt_cnt
< rmctx
.nb_packets
) {
173 if (ci
->stop_codec
|| ci
->new_track
)
177 packet_offset
= ci
->seek_time
/ ((rmctx
.block_align
*8*1000)/rmctx
.bit_rate
);
178 ci
->seek_buffer(rmctx
.data_offset
+ DATA_HEADER_SIZE
+ packet_offset
*(rmctx
.block_align
+ PACKET_HEADER_SIZE
));
179 rmctx
.audio_pkt_cnt
= packet_offset
;
180 samplesdone
= (rmctx
.sample_rate
/1000 * ci
->seek_time
);
184 filebuf
= ci
->request_buffer(&n
, rmctx
.block_align
+ PACKET_HEADER_SIZE
);
185 consumed
= rm_get_packet(&filebuf
, &rmctx
, &pkt
);
187 if(consumed
< 0 && playback_on
!= 0) {
188 if(playback_on
== -1) {
189 /* Error only if packet-parsing failed and playback hadn't started */
190 DEBUGF("rm_get_packet failed\n");
200 a52_decode_data(filebuf
, filebuf
+ rmctx
.block_align
);
201 ci
->advance_buffer(pkt
.length
);
206 if (ci
->request_next_track())