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 ****************************************************************************/
24 #include "libfaad/common.h"
25 #include "libfaad/structs.h"
26 #include "libfaad/decoder.h"
27 #include "libfaad/output.h"
31 /* Global buffers to be used in the mdct synthesis. This way the arrays can
32 * be moved to IRAM for some targets */
33 #define GB_BUF_SIZE 1024
34 static ALIGN real_t gb_time_buffer
[2][GB_BUF_SIZE
] IBSS_ATTR_FAAD_LARGE_IRAM
;
35 static ALIGN real_t gb_fb_intermed
[2][GB_BUF_SIZE
] IBSS_ATTR_FAAD_LARGE_IRAM
;
38 static void init_rm(RMContext
*rmctx
)
40 memcpy(rmctx
, (void*)(( (intptr_t)ci
->id3
->id3v2buf
+ 3 ) &~ 3), sizeof(RMContext
));
43 static RMContext rmctx
;
45 /* this is the codec entry point */
46 enum codec_status
codec_main(void)
48 static NeAACDecFrameInfo frame_info
;
49 NeAACDecHandle decoder
;
54 unsigned char* buffer
;
55 int err
, consumed
, pkt_offset
, skipped
= 0;
56 uint32_t s
= 0; /* sample rate */
57 unsigned char c
= 0; /* channels */
61 /* Generic codec initialisation */
62 ci
->configure(DSP_SET_STEREO_MODE
, STEREO_NONINTERLEAVED
);
63 ci
->configure(DSP_SET_SAMPLE_DEPTH
, 29);
69 DEBUGF("FAAD: Codec init error\n");
73 if (codec_wait_taginfo() != 0)
76 resume_offset
= ci
->id3
->offset
;
78 ci
->memset(&rmctx
,0,sizeof(RMContext
));
79 ci
->memset(&pkt
,0,sizeof(RMPacket
));
81 ci
->configure(DSP_SWITCH_FREQUENCY
, ci
->id3
->frequency
);
82 codec_set_replaygain(ci
->id3
);
84 /* initialise the sound converter */
85 decoder
= NeAACDecOpen();
88 DEBUGF("FAAD: Decode open error\n");
92 NeAACDecConfigurationPtr conf
= NeAACDecGetCurrentConfiguration(decoder
);
93 conf
->outputFormat
= FAAD_FMT_16BIT
; /* irrelevant, we don't convert */
94 NeAACDecSetConfiguration(decoder
, conf
);
96 decoder
->config
.defObjectType
= rmctx
.codec_extradata
[0];
97 decoder
->config
.defSampleRate
= rmctx
.sample_rate
;
98 err
= NeAACDecInit(decoder
, NULL
, 0, &s
, &c
);
101 DEBUGF("FAAD: DecInit: %d, %d\n", err
, decoder
->object_type
);
106 /* Set pointer to be able to use IRAM an to avoid alloc in decoder. Must
107 * be called after NeAACDecOpen(). */
108 /* A buffer of framelength or 2*frameLenght size must be allocated for
109 * time_out. If frameLength is too big or SBR/forceUpSampling is active,
110 * we do not use the IRAM buffer and keep faad's internal allocation (see
112 needed_bufsize
= decoder
->frameLength
;
114 if ((decoder
->sbr_present_flag
== 1) || (decoder
->forceUpSampling
== 1))
119 if (needed_bufsize
<= GB_BUF_SIZE
)
121 decoder
->time_out
[0] = &gb_time_buffer
[0][0];
122 decoder
->time_out
[1] = &gb_time_buffer
[1][0];
124 /* A buffer of with frameLength elements must be allocated for fb_intermed.
125 * If frameLength is too big, we do not use the IRAM buffer and keep faad's
126 * internal allocation (see specrec.c). */
127 needed_bufsize
= decoder
->frameLength
;
128 if (needed_bufsize
<= GB_BUF_SIZE
)
130 decoder
->fb_intermed
[0] = &gb_fb_intermed
[0][0];
131 decoder
->fb_intermed
[1] = &gb_fb_intermed
[1][0];
134 /* check for a mid-track resume and force a seek time accordingly */
135 if(resume_offset
> rmctx
.data_offset
+ DATA_HEADER_SIZE
) {
136 resume_offset
-= rmctx
.data_offset
+ DATA_HEADER_SIZE
;
137 /* put number of subpackets to skip in resume_offset */
138 resume_offset
/= (rmctx
.block_align
+ PACKET_HEADER_SIZE
);
139 ci
->seek_time
= (int)resume_offset
* ((rmctx
.block_align
* 8 * 1000)/rmctx
.bit_rate
);
142 ci
->id3
->frequency
= s
;
144 ci
->advance_buffer(rmctx
.data_offset
+ DATA_HEADER_SIZE
);
146 /* The main decoding loop */
150 if (ci
->stop_codec
|| ci
->new_track
) {
156 /* Do not allow seeking beyond the file's length */
157 if ((unsigned) ci
->seek_time
> ci
->id3
->length
) {
162 ci
->seek_buffer(rmctx
.data_offset
+ DATA_HEADER_SIZE
);
164 /* Seek to the start of the track */
165 if (ci
->seek_time
== 1) {
173 buffer
= ci
->request_buffer(&n
,rmctx
.audio_framesize
+ 1000);
174 pkt_offset
= skipped
- pkt
.length
;
175 consumed
= rm_get_packet(&buffer
, &rmctx
, &pkt
);
176 if(consumed
< 0 && playback_on
!= 0) {
177 if(playback_on
== -1) {
178 /* Error only if packet-parsing failed and playback hadn't started */
179 DEBUGF("rm_get_packet failed\n");
185 skipped
+= pkt
.length
;
186 if(pkt
.timestamp
> (unsigned)ci
->seek_time
) break;
187 ci
->advance_buffer(pkt
.length
);
189 ci
->seek_buffer(pkt_offset
+ rmctx
.data_offset
+ DATA_HEADER_SIZE
);
190 buffer
= ci
->request_buffer(&n
,rmctx
.audio_framesize
+ 1000);
194 /* Request the required number of bytes from the input buffer */
195 buffer
=ci
->request_buffer(&n
,rmctx
.audio_framesize
+ 1000);
196 consumed
= rm_get_packet(&buffer
, &rmctx
, &pkt
);
198 if(consumed
< 0 && playback_on
!= 0) {
199 if(playback_on
== -1) {
200 /* Error only if packet-parsing failed and playback hadn't started */
201 DEBUGF("rm_get_packet failed\n");
209 if (pkt
.timestamp
>= ci
->id3
->length
)
211 /* Decode one block - returned samples will be host-endian */
212 for(i
= 0; i
< rmctx
.sub_packet_cnt
; i
++) {
213 ret
= NeAACDecDecode(decoder
, &frame_info
, buffer
, rmctx
.sub_packet_lengths
[i
]);
214 buffer
+= rmctx
.sub_packet_lengths
[i
];
215 if (frame_info
.error
> 0) {
216 DEBUGF("FAAD: decode error '%s'\n", NeAACDecGetErrorMessage(frame_info
.error
));
220 ci
->pcmbuf_insert(decoder
->time_out
[0],
221 decoder
->time_out
[1],
222 decoder
->frameLength
);
223 ci
->set_elapsed(pkt
.timestamp
);
226 ci
->advance_buffer(pkt
.length
);
230 if (ci
->request_next_track())