Enable replaygain for the new FLAC decoder
[Rockbox.git] / apps / codecs / flac.c
blobfff301b65a9cff0b88a4fb08ee1dee72ece705a7
1 /***************************************************************************
2 * __________ __ ___.
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7 * \/ \/ \/ \/ \/
8 * $Id$
10 * Copyright (C) 2005 Dave Chapman
12 * All files in this archive are subject to the GNU General Public License.
13 * See the file COPYING in the source tree root for full license agreement.
15 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
16 * KIND, either express or implied.
18 ****************************************************************************/
20 #include "codeclib.h"
21 #include <codecs/libffmpegFLAC/decoder.h>
23 #ifndef SIMULATOR
24 extern char iramcopy[];
25 extern char iramstart[];
26 extern char iramend[];
27 #endif
29 struct codec_api* rb;
30 struct codec_api* ci;
32 /* The output buffers containing the decoded samples (channels 0 and 1) */
33 int32_t decoded0[MAX_BLOCKSIZE] IBSS_ATTR;
34 int32_t decoded1[MAX_BLOCKSIZE] IBSS_ATTR;
36 #define MAX_SUPPORTED_SEEKTABLE_SIZE 5000
38 /* Notes about seeking:
40 The full seek table consists of:
41 uint64_t sample (only 36 bits are used)
42 uint64_t offset
43 uint32_t blocksize
45 We don't store the blocksize (of the target frame) and we also
46 limit the sample and offset values to 32-bits - Rockbox doesn't support
47 files bigger than 2GB on FAT32 filesystems.
49 The reference FLAC encoder produces a seek table with points every
50 10 seconds, but this can be overridden by the user when encoding a file.
52 With the default settings, a typical 4 minute track will contain
53 24 seek points.
55 Taking the extreme case of a Rockbox supported file to be a 2GB (compressed)
56 16-bit/44.1KHz mono stream with a likely uncompressed size of 4GB:
57 Total duration is: 48694 seconds (about 810 minutes - 13.5 hours)
58 Total number of seek points: 4869
60 Therefore we limit the number of seek points to 5000. This is a
61 very extreme case, and requires 5000*8=40000 bytes of storage.
63 If we come across a FLAC file with more than this number of seekpoints, we
64 just use the first 5000.
68 struct FLACseekpoints {
69 uint32_t sample;
70 uint32_t offset;
73 struct FLACseekpoints seekpoints[MAX_SUPPORTED_SEEKTABLE_SIZE];
74 int nseekpoints;
76 static bool flac_init(FLACContext* fc, int first_frame_offset)
78 unsigned char buf[255];
79 bool found_streaminfo=false;
80 uint32_t seekpoint_hi,seekpoint_lo;
81 uint32_t offset_hi,offset_lo;
82 int endofmetadata=0;
83 int blocklength;
84 int n;
85 uint32_t* p;
87 ci->memset(fc,0,sizeof(FLACContext));
88 nseekpoints=0;
90 /* Skip any foreign tags at start of file */
91 ci->seek_buffer(first_frame_offset);
93 fc->metadatalength = first_frame_offset;
95 if (ci->read_filebuf(buf, 4) < 4)
97 return false;
100 if (ci->memcmp(buf,"fLaC",4) != 0)
102 return false;
104 fc->metadatalength += 4;
106 while (!endofmetadata) {
107 if (ci->read_filebuf(buf, 4) < 4)
109 return false;
112 endofmetadata=(buf[0]&0x80);
113 blocklength = (buf[1] << 16) | (buf[2] << 8) | buf[3];
114 fc->metadatalength+=blocklength+4;
116 if ((buf[0] & 0x7f) == 0) /* 0 is the STREAMINFO block */
118 /* FIXME: Don't trust the value of blocklength */
119 if (ci->read_filebuf(buf, blocklength) < 0)
121 return false;
124 fc->filesize = ci->filesize;
125 fc->min_blocksize = (buf[0] << 8) | buf[1];
126 fc->max_blocksize = (buf[2] << 8) | buf[3];
127 fc->min_framesize = (buf[4] << 16) | (buf[5] << 8) | buf[6];
128 fc->max_framesize = (buf[7] << 16) | (buf[8] << 8) | buf[9];
129 fc->samplerate = (buf[10] << 12) | (buf[11] << 4)
130 | ((buf[12] & 0xf0) >> 4);
131 fc->channels = ((buf[12]&0x0e)>>1) + 1;
132 fc->bps = (((buf[12]&0x01) << 4) | ((buf[13]&0xf0)>>4) ) + 1;
134 /* totalsamples is a 36-bit field, but we assume <= 32 bits are
135 used */
136 fc->totalsamples = (buf[14] << 24) | (buf[15] << 16)
137 | (buf[16] << 8) | buf[17];
139 /* Calculate track length (in ms) and estimate the bitrate
140 (in kbit/s) */
141 fc->length = (fc->totalsamples / fc->samplerate) * 1000;
143 found_streaminfo=true;
144 } else if ((buf[0] & 0x7f) == 3) { /* 3 is the SEEKTABLE block */
145 while ((nseekpoints < MAX_SUPPORTED_SEEKTABLE_SIZE) &&
146 (blocklength >= 18)) {
147 n=ci->read_filebuf(buf,18);
148 if (n < 18) return false;
149 blocklength-=n;
151 p=(uint32_t*)buf;
152 seekpoint_hi=betoh32(*(p++));
153 seekpoint_lo=betoh32(*(p++));
154 offset_hi=betoh32(*(p++));
155 offset_lo=betoh32(*(p++));
157 if ((seekpoint_hi == 0) && (seekpoint_lo != 0xffffffff) &&
158 (offset_hi == 0)) {
159 seekpoints[nseekpoints].sample=seekpoint_lo;
160 seekpoints[nseekpoints].offset=offset_lo;
161 nseekpoints++;
164 /* Skip any unread seekpoints */
165 if (blocklength > 0)
166 ci->advance_buffer(blocklength);
167 } else {
168 /* Skip to next metadata block */
169 ci->advance_buffer(blocklength);
173 if (found_streaminfo) {
174 fc->bitrate = ((fc->filesize-fc->metadatalength) * 8) / fc->length;
175 return true;
176 } else {
177 return false;
181 /* A very simple seek implementation - seek to the seekpoint before
182 the target sample.
184 This needs to be improved to seek with greater accuracy
186 bool flac_seek(FLACContext* fc, uint32_t newsample) {
187 uint32_t offset;
188 int i;
190 if (nseekpoints==0) {
191 offset=0;
192 } else {
193 i=nseekpoints-1;
194 while ((i > 0) && (seekpoints[i].sample > newsample)) {
195 i--;
198 if ((i==0) && (seekpoints[i].sample > newsample)) {
199 offset=0;
200 } else {
201 offset=seekpoints[i].offset;
205 offset+=fc->metadatalength;
207 if (ci->seek_buffer(offset)) {
208 return true;
209 } else {
210 return false;
214 /* this is the codec entry point */
215 enum codec_status codec_start(struct codec_api* api)
217 int8_t *buf;
218 FLACContext fc;
219 uint32_t samplesdone;
220 uint32_t elapsedtime;
221 long bytesleft;
222 int consumed;
223 int res;
224 int frame;
226 /* Generic codec initialisation */
227 TEST_CODEC_API(api);
229 rb = api;
230 ci = (struct codec_api*)api;
232 #ifndef SIMULATOR
233 ci->memcpy(iramstart, iramcopy, iramend-iramstart);
234 #endif
236 ci->configure(CODEC_SET_FILEBUF_LIMIT, (int *)(1024*1024*10));
237 ci->configure(CODEC_SET_FILEBUF_WATERMARK, (int *)(1024*512));
238 ci->configure(CODEC_SET_FILEBUF_CHUNKSIZE, (int *)(1024*128));
240 ci->configure(CODEC_DSP_ENABLE, (bool *)true);
241 ci->configure(DSP_DITHER, (bool *)false);
242 ci->configure(DSP_SET_STEREO_MODE, (long *)STEREO_NONINTERLEAVED);
243 ci->configure(DSP_SET_SAMPLE_DEPTH, (int *)(FLAC_OUTPUT_DEPTH-1));
245 next_track:
247 if (codec_init(api)) {
248 LOGF("FLAC: Error initialising codec\n");
249 return CODEC_ERROR;
252 if (!flac_init(&fc,ci->id3->first_frame_offset)) {
253 LOGF("FLAC: Error initialising codec\n");
254 return CODEC_ERROR;
257 while (!*ci->taginfo_ready)
258 ci->yield();
260 ci->configure(DSP_SET_FREQUENCY, (long *)(ci->id3->frequency));
261 codec_set_replaygain(ci->id3);
263 /* The main decoding loop */
264 samplesdone=0;
265 frame=0;
266 buf = ci->request_buffer(&bytesleft, MAX_FRAMESIZE);
267 while (bytesleft) {
268 ci->yield();
269 if (ci->stop_codec || ci->reload_codec) {
270 break;
273 /* Deal with any pending seek requests */
274 if (ci->seek_time) {
275 if (flac_seek(&fc,(ci->seek_time/20) * (ci->id3->frequency/50))) {
276 /* Refill the input buffer */
277 buf = ci->request_buffer(&bytesleft, MAX_FRAMESIZE);
279 ci->seek_complete();
282 if((res=flac_decode_frame(&fc,decoded0,decoded1,buf,
283 bytesleft,ci->yield)) < 0) {
284 LOGF("FLAC: Frame %d, error %d\n",frame,res);
285 return CODEC_ERROR;
287 consumed=fc.gb.index/8;
288 frame++;
290 ci->yield();
291 while(!ci->pcmbuf_insert_split((char*)decoded0,(char*)decoded1,
292 fc.blocksize*4)) {
293 ci->yield();
296 /* Update the elapsed-time indicator */
297 samplesdone=fc.samplenumber+fc.blocksize;
298 elapsedtime=(samplesdone*10)/(ci->id3->frequency/100);
299 ci->set_elapsed(elapsedtime);
301 ci->advance_buffer(consumed);
303 buf = ci->request_buffer(&bytesleft, MAX_FRAMESIZE);
305 LOGF("FLAC: Decoded %d samples\n",samplesdone);
307 if (ci->request_next_track())
308 goto next_track;
310 return CODEC_OK;