blob: 259686ed3f6fd44796f00cddffc3f9527ab3c245 [file] [log] [blame]
Dave Chapman6c082a82005-06-07 18:53:01 +00001/***************************************************************************
2 * __________ __ ___.
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7 * \/ \/ \/ \/ \/
8 * $Id$
9 *
10 * Copyright (C) 2002 Björn Stenberg
11 *
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.
14 *
15 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
16 * KIND, either express or implied.
17 *
18 ****************************************************************************/
19
Daniel Stenberg1dd672f2005-06-22 19:41:30 +000020#include "codec.h"
Dave Chapman6c082a82005-06-07 18:53:01 +000021
22#include <codecs/libFLAC/include/FLAC/seekable_stream_decoder.h>
23#include "playback.h"
24#include "lib/codeclib.h"
Miika Pekkarinend8cb7032005-06-26 19:41:29 +000025#include "dsp.h"
Dave Chapman6c082a82005-06-07 18:53:01 +000026
27#define FLAC_MAX_SUPPORTED_BLOCKSIZE 4608
28#define FLAC_MAX_SUPPORTED_CHANNELS 2
29
Daniel Stenberg1dd672f2005-06-22 19:41:30 +000030static struct codec_api* rb;
Dave Chapman7c54b3a2005-06-09 09:47:04 +000031static uint32_t samplesdone;
Dave Chapman6c082a82005-06-07 18:53:01 +000032
33/* Called when the FLAC decoder needs some FLAC data to decode */
34FLAC__SeekableStreamDecoderReadStatus flac_read_handler(const FLAC__SeekableStreamDecoder *dec,
35 FLAC__byte buffer[], unsigned *bytes, void *data)
36{ struct codec_api* ci = (struct codec_api*)data;
37 (void)dec;
38
39 *bytes=(unsigned)(ci->read_filebuf(buffer,*bytes));
40
Dave Chapmanb15e5462005-06-07 20:09:53 +000041 if (*bytes==0) {
Dave Chapman6c082a82005-06-07 18:53:01 +000042 return FLAC__STREAM_DECODER_READ_STATUS_END_OF_STREAM;
Dave Chapmanb15e5462005-06-07 20:09:53 +000043 } else {
44 return FLAC__STREAM_DECODER_READ_STATUS_CONTINUE;
Dave Chapman6c082a82005-06-07 18:53:01 +000045 }
Dave Chapman6c082a82005-06-07 18:53:01 +000046}
47
48static unsigned char pcmbuf[FLAC_MAX_SUPPORTED_BLOCKSIZE*FLAC_MAX_SUPPORTED_CHANNELS*2] IDATA_ATTR;
49
50/* Called when the FLAC decoder has some decoded PCM data to write */
51FLAC__StreamDecoderWriteStatus flac_write_handler(const FLAC__SeekableStreamDecoder *dec,
52 const FLAC__Frame *frame,
53 const FLAC__int32 * const buf[],
54 void *data)
55{
56 struct codec_api* ci = (struct codec_api*)data;
57 (void)dec;
58 unsigned int c_samp, c_chan, d_samp;
59 uint32_t data_size = frame->header.blocksize * frame->header.channels * 2; /* Assume 16-bit words */
60 uint32_t samples = frame->header.blocksize;
Miika Pekkarinend30f1102005-06-10 17:33:16 +000061 int yieldcounter = 0;
Dave Chapman6c082a82005-06-07 18:53:01 +000062
63
64 if (samples*frame->header.channels > (FLAC_MAX_SUPPORTED_BLOCKSIZE*FLAC_MAX_SUPPORTED_CHANNELS)) {
65 // ERROR!!!
66 DEBUGF("ERROR: samples*frame->header.channels=%d\n",samples*frame->header.channels);
67 return(FLAC__STREAM_DECODER_WRITE_STATUS_CONTINUE);
68 }
69
70 (void)dec;
71 for(c_samp = d_samp = 0; c_samp < samples; c_samp++) {
72 for(c_chan = 0; c_chan < frame->header.channels; c_chan++, d_samp++) {
73 pcmbuf[d_samp*2] = (buf[c_chan][c_samp]&0xff00)>>8;
74 pcmbuf[(d_samp*2)+1] = buf[c_chan][c_samp]&0xff;
Miika Pekkarinend30f1102005-06-10 17:33:16 +000075 if (yieldcounter++ == 100) {
76 rb->yield();
77 yieldcounter = 0;
78 }
Dave Chapman6c082a82005-06-07 18:53:01 +000079 }
80 }
81
Dave Chapman7c54b3a2005-06-09 09:47:04 +000082 samplesdone+=samples;
83 ci->set_elapsed(samplesdone/(ci->id3->frequency/1000));
Miika Pekkarinen9e200e32005-06-09 20:01:09 +000084
85 rb->yield();
Miika Pekkarinen20b38972005-07-13 12:48:22 +000086 while (!ci->pcmbuf_insert(pcmbuf, data_size))
Dave Chapman6c082a82005-06-07 18:53:01 +000087 rb->yield();
88
89 return FLAC__STREAM_DECODER_WRITE_STATUS_CONTINUE;
90}
91
92void flac_metadata_handler(const FLAC__SeekableStreamDecoder *dec,
93 const FLAC__StreamMetadata *meta, void *data)
94{
95 /* Ignore metadata for now... */
96 (void)dec;
97 (void)meta;
98 (void)data;
99}
100
101
102void flac_error_handler(const FLAC__SeekableStreamDecoder *dec,
103 FLAC__StreamDecoderErrorStatus status, void *data)
104{
105 (void)dec;
106 (void)status;
107 (void)data;
108}
109
110FLAC__SeekableStreamDecoderSeekStatus flac_seek_handler (const FLAC__SeekableStreamDecoder *decoder,
111 FLAC__uint64 absolute_byte_offset,
112 void *client_data)
113{
114 (void)decoder;
115 struct codec_api* ci = (struct codec_api*)client_data;
116
117 if (ci->seek_buffer(absolute_byte_offset)) {
118 return(FLAC__SEEKABLE_STREAM_DECODER_SEEK_STATUS_OK);
119 } else {
120 return(FLAC__SEEKABLE_STREAM_DECODER_SEEK_STATUS_ERROR);
121 }
122}
123
124FLAC__SeekableStreamDecoderTellStatus flac_tell_handler (const FLAC__SeekableStreamDecoder *decoder,
125 FLAC__uint64 *absolute_byte_offset, void *client_data)
126{
127 struct codec_api* ci = (struct codec_api*)client_data;
128
129 (void)decoder;
130 *absolute_byte_offset=ci->curpos;
131 return(FLAC__SEEKABLE_STREAM_DECODER_TELL_STATUS_OK);
132}
133
134FLAC__SeekableStreamDecoderLengthStatus flac_length_handler (const FLAC__SeekableStreamDecoder *decoder,
135 FLAC__uint64 *stream_length, void *client_data)
136{
137 struct codec_api* ci = (struct codec_api*)client_data;
138
139 (void)decoder;
140 *stream_length=ci->filesize;
141 return(FLAC__SEEKABLE_STREAM_DECODER_LENGTH_STATUS_OK);
142}
143
144FLAC__bool flac_eof_handler (const FLAC__SeekableStreamDecoder *decoder,
145 void *client_data)
146{
147 struct codec_api* ci = (struct codec_api*)client_data;
148
149 (void)decoder;
150 if (ci->curpos >= ci->filesize) {
151 return(true);
152 } else {
153 return(false);
154 }
155}
156
157#ifndef SIMULATOR
158extern char iramcopy[];
159extern char iramstart[];
160extern char iramend[];
161#endif
162
Daniel Stenberg1dd672f2005-06-22 19:41:30 +0000163/* this is the codec entry point */
Daniel Stenberg31efab42005-06-22 19:55:09 +0000164enum codec_status codec_start(struct codec_api* api)
Dave Chapman6c082a82005-06-07 18:53:01 +0000165{
Daniel Stenberg1dd672f2005-06-22 19:41:30 +0000166 struct codec_api* ci = api;
167 FLAC__SeekableStreamDecoder* flacDecoder;
Dave Chapman6c082a82005-06-07 18:53:01 +0000168
Daniel Stenberg1dd672f2005-06-22 19:41:30 +0000169 /* Generic codec initialisation */
170 TEST_CODEC_API(api);
Dave Chapman6c082a82005-06-07 18:53:01 +0000171
172 /* if you are using a global api pointer, don't forget to copy it!
173 otherwise you will get lovely "I04: IllInstr" errors... :-) */
174 rb = api;
175
176#ifndef SIMULATOR
177 rb->memcpy(iramstart, iramcopy, iramend-iramstart);
178#endif
179
Miika Pekkarinen68b9acd2005-06-10 15:02:10 +0000180 ci->configure(CODEC_SET_FILEBUF_LIMIT, (int *)(1024*1024*10));
181 ci->configure(CODEC_SET_FILEBUF_WATERMARK, (int *)(1024*512));
Dave Chapman789791e2005-06-13 17:48:30 +0000182 ci->configure(CODEC_SET_FILEBUF_CHUNKSIZE, (int *)(1024*128));
Dave Chapman6c082a82005-06-07 18:53:01 +0000183
Miika Pekkarinend8cb7032005-06-26 19:41:29 +0000184 ci->configure(DSP_DITHER, (bool *)false);
185 ci->configure(DSP_SET_STEREO_MODE, (int *)STEREO_INTERLEAVED);
186 ci->configure(DSP_SET_SAMPLE_DEPTH, (int *)(16));
187
Dave Chapmanb15e5462005-06-07 20:09:53 +0000188 next_track:
189
Daniel Stenberg1dd672f2005-06-22 19:41:30 +0000190 if (codec_init(api)) {
191 return CODEC_ERROR;
Dave Chapman6c082a82005-06-07 18:53:01 +0000192 }
193
Miika Pekkarinend8cb7032005-06-26 19:41:29 +0000194 while (!rb->taginfo_ready)
195 rb->yield();
196
197 if (rb->id3->frequency != NATIVE_FREQUENCY) {
198 rb->configure(DSP_SET_FREQUENCY, (long *)(rb->id3->frequency));
199 rb->configure(CODEC_DSP_ENABLE, (bool *)true);
200 } else {
201 rb->configure(CODEC_DSP_ENABLE, (bool *)false);
202 }
203
Dave Chapman6c082a82005-06-07 18:53:01 +0000204 /* Create a decoder instance */
205
Dave Chapman6c082a82005-06-07 18:53:01 +0000206 flacDecoder=FLAC__seekable_stream_decoder_new();
207
208 /* Set up the decoder and the callback functions - this must be done before init */
209
210 /* The following are required for stream_decoder and higher */
211 FLAC__seekable_stream_decoder_set_client_data(flacDecoder,ci);
212 FLAC__seekable_stream_decoder_set_write_callback(flacDecoder, flac_write_handler);
213 FLAC__seekable_stream_decoder_set_read_callback(flacDecoder, flac_read_handler);
214 FLAC__seekable_stream_decoder_set_metadata_callback(flacDecoder, flac_metadata_handler);
215 FLAC__seekable_stream_decoder_set_error_callback(flacDecoder, flac_error_handler);
216 FLAC__seekable_stream_decoder_set_metadata_respond(flacDecoder, FLAC__METADATA_TYPE_STREAMINFO);
217
218 /* The following are only for the seekable_stream_decoder */
219 FLAC__seekable_stream_decoder_set_seek_callback(flacDecoder, flac_seek_handler);
220 FLAC__seekable_stream_decoder_set_tell_callback(flacDecoder, flac_tell_handler);
221 FLAC__seekable_stream_decoder_set_length_callback(flacDecoder, flac_length_handler);
222 FLAC__seekable_stream_decoder_set_eof_callback(flacDecoder, flac_eof_handler);
223
224
225 /* QUESTION: What do we do when the init fails? */
226 if (FLAC__seekable_stream_decoder_init(flacDecoder)) {
Daniel Stenberg1dd672f2005-06-22 19:41:30 +0000227 return CODEC_ERROR;
Dave Chapman6c082a82005-06-07 18:53:01 +0000228 }
229
230 /* The first thing to do is to parse the metadata */
231 FLAC__seekable_stream_decoder_process_until_end_of_metadata(flacDecoder);
232
Dave Chapman7c54b3a2005-06-09 09:47:04 +0000233 samplesdone=0;
234 ci->set_elapsed(0);
Dave Chapman6c082a82005-06-07 18:53:01 +0000235 /* The main decoder loop */
Dave Chapman02e22ea2005-06-07 19:38:13 +0000236 while (FLAC__seekable_stream_decoder_get_state(flacDecoder)!=FLAC__SEEKABLE_STREAM_DECODER_END_OF_STREAM) {
Dave Chapman6c082a82005-06-07 18:53:01 +0000237 rb->yield();
238 if (ci->stop_codec || ci->reload_codec) {
239 break;
240 }
Dave Chapmandefdf4b2005-06-18 20:57:01 +0000241
242 if (ci->seek_time) {
243 int sample_loc;
244
245 sample_loc = ci->seek_time/1000 * ci->id3->frequency;
246 if (FLAC__seekable_stream_decoder_seek_absolute(flacDecoder,sample_loc)) {
247 samplesdone=sample_loc;
248 ci->set_elapsed(samplesdone/(ci->id3->frequency/1000));
249 }
250 ci->seek_time = 0;
251 }
252
Dave Chapman6c082a82005-06-07 18:53:01 +0000253 FLAC__seekable_stream_decoder_process_single(flacDecoder);
254 }
255
Dave Chapmanb15e5462005-06-07 20:09:53 +0000256 /* Flush the libFLAC buffers */
257 FLAC__seekable_stream_decoder_finish(flacDecoder);
258
Dave Chapman6c082a82005-06-07 18:53:01 +0000259 if (ci->request_next_track())
260 goto next_track;
261
Daniel Stenberg1dd672f2005-06-22 19:41:30 +0000262 return CODEC_OK;
Dave Chapman6c082a82005-06-07 18:53:01 +0000263}