summaryrefslogtreecommitdiff
path: root/apps/codecs
diff options
context:
space:
mode:
Diffstat (limited to 'apps/codecs')
-rw-r--r--apps/codecs/Makefile1
-rw-r--r--apps/codecs/SOURCES1
-rw-r--r--apps/codecs/aiff.c314
3 files changed, 316 insertions, 0 deletions
diff --git a/apps/codecs/Makefile b/apps/codecs/Makefile
index d0cd97db9b..915e922278 100644
--- a/apps/codecs/Makefile
+++ b/apps/codecs/Makefile
@@ -63,6 +63,7 @@ $(OBJDIR)/wavpack.elf: $(OBJDIR)/wavpack.o $(CODECDEPS) $(BUILDDIR)/libwavpack.a
63$(OBJDIR)/alac.elf: $(OBJDIR)/alac.o $(CODECDEPS) $(BUILDDIR)/libalac.a $(BUILDDIR)/libm4a.a 63$(OBJDIR)/alac.elf: $(OBJDIR)/alac.o $(CODECDEPS) $(BUILDDIR)/libalac.a $(BUILDDIR)/libm4a.a
64$(OBJDIR)/aac.elf: $(OBJDIR)/aac.o $(CODECDEPS) $(BUILDDIR)/libfaad.a $(BUILDDIR)/libm4a.a 64$(OBJDIR)/aac.elf: $(OBJDIR)/aac.o $(CODECDEPS) $(BUILDDIR)/libfaad.a $(BUILDDIR)/libm4a.a
65$(OBJDIR)/shorten.elf: $(OBJDIR)/shorten.o $(CODECDEPS) $(BUILDDIR)/libffmpegFLAC.a 65$(OBJDIR)/shorten.elf: $(OBJDIR)/shorten.o $(CODECDEPS) $(BUILDDIR)/libffmpegFLAC.a
66$(OBJDIR)/aiff.elf: $(OBJDIR)/aiff.o $(CODECDEPS)
66 67
67$(OBJDIR)/%.elf: $(OBJDIR)/%.o $(CODECDEPS) 68$(OBJDIR)/%.elf: $(OBJDIR)/%.o $(CODECDEPS)
68 $(ELFIT) 69 $(ELFIT)
diff --git a/apps/codecs/SOURCES b/apps/codecs/SOURCES
index 911ee3b705..05172d6da9 100644
--- a/apps/codecs/SOURCES
+++ b/apps/codecs/SOURCES
@@ -11,4 +11,5 @@ alac.c
11aac.c 11aac.c
12#endif 12#endif
13shorten.c 13shorten.c
14aiff.c
14#endif 15#endif
diff --git a/apps/codecs/aiff.c b/apps/codecs/aiff.c
new file mode 100644
index 0000000000..091e621bb7
--- /dev/null
+++ b/apps/codecs/aiff.c
@@ -0,0 +1,314 @@
1/***************************************************************************
2 * __________ __ ___.
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7 * \/ \/ \/ \/ \/
8 * $Id$
9 *
10 * Copyright (c) 2005 Jvo Studer
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
20#include "codeclib.h"
21#include "inttypes.h"
22
23CODEC_HEADER
24
25struct codec_api* rb;
26
27/* This codec supports AIFF files with the following formats:
28 * - PCM, 8 and 16 bits, mono or stereo
29 */
30
31enum
32{
33 AIFF_FORMAT_PCM = 0x0001, /* AIFF PCM Format (big endian) */
34 IEEE_FORMAT_FLOAT = 0x0003, /* IEEE Float */
35 AIFF_FORMAT_ALAW = 0x0004, /* AIFC ALaw compressed */
36 AIFF_FORMAT_ULAW = 0x0005 /* AIFC uLaw compressed */
37};
38
39/* Maximum number of bytes to process in one iteration */
40/* for 44.1kHz stereo 16bits, this represents 0.023s ~= 1/50s */
41#define AIF_CHUNK_SIZE (1024*2)
42
43#ifdef USE_IRAM
44extern char iramcopy[];
45extern char iramstart[];
46extern char iramend[];
47extern char iedata[];
48extern char iend[];
49#endif
50
51static int16_t int16_samples[AIF_CHUNK_SIZE] IBSS_ATTR;
52
53
54/* this is the codec entry point */
55enum codec_status codec_start(struct codec_api* api)
56{
57 struct codec_api* ci;
58 uint32_t numbytes, bytesdone;
59 uint16_t numChannels = 0;
60 uint32_t numSampleFrames = 0;
61 uint16_t sampleSize = 0;
62 uint32_t sampleRate = 0;
63 uint32_t i;
64 size_t n, aifbufsize;
65 int endofstream;
66 unsigned char* buf;
67 uint16_t* aifbuf;
68 long chunksize;
69 uint32_t offset2snd = 0;
70 uint16_t blockSize = 0;
71 uint32_t avgbytespersec = 0;
72 off_t firstblockposn; /* position of the first block in file */
73 int shortorlong = 1; /* do we output shorts (1) or longs (2)? */
74 int32_t * const int32_samples = (int32_t*)int16_samples;
75
76 /* Generic codec initialisation */
77 rb = api;
78 ci = api;
79
80#ifdef USE_IRAM
81 ci->memcpy(iramstart, iramcopy, iramend-iramstart);
82 ci->memset(iedata, 0, iend - iedata);
83#endif
84
85 ci->configure(CODEC_SET_FILEBUF_WATERMARK, (int *)(1024*512));
86 ci->configure(CODEC_SET_FILEBUF_CHUNKSIZE, (int *)(1024*256));
87
88 ci->configure(DSP_DITHER, (bool *)false);
89
90 next_track:
91
92 if (codec_init(api)) {
93 i = CODEC_ERROR;
94 goto exit;
95 }
96
97 while (!*ci->taginfo_ready)
98 ci->yield();
99
100 /* assume the AIFF header is less than 1024 bytes */
101 buf=ci->request_buffer((long *)&n,1024);
102 if (n<44) {
103 i = CODEC_ERROR;
104 goto exit;
105 }
106 if ((memcmp(buf,"FORM",4)!=0) || (memcmp(&buf[8],"AIFF",4)!=0)) {
107 i = CODEC_ERROR;
108 goto exit;
109 }
110
111 buf += 12;
112 n -= 12;
113 numbytes = 0;
114
115 /* read until 'SSND' chunk, which typically is last */
116 while(numbytes == 0 && n >= 8) {
117 /* chunkSize */
118 i = ((buf[4]<<24)|(buf[5]<<16)|(buf[6]<<8)|buf[7]);
119 if (memcmp(buf,"COMM",4)==0) {
120 if (i != 18) {
121 DEBUGF("CODEC_ERROR: 'COMM' chunk size=%lu != 18\n",i);
122 i = CODEC_ERROR;
123 goto exit;
124 }
125 /* numChannels */
126 numChannels = ((buf[8]<<8)|buf[9]);
127 /* numSampleFrames */
128 numSampleFrames = ((buf[10]<<24)|(buf[11]<<16)|(buf[12]<<8)|buf[13]);
129 /* sampleSize */
130 sampleSize = ((buf[14]<<8)|buf[15]);
131 /* sampleRate (don't use last 4 bytes, only integer fs) */
132 if (buf[16] != 0x40) {
133 DEBUGF("CODEC_ERROR: wierd sampling rate (no @)\n",i);
134 i = CODEC_ERROR;
135 goto exit;
136 }
137 sampleRate = ((buf[18]<<24)|(buf[19]<<16)|(buf[20]<<8)|buf[21])+1;
138 sampleRate = sampleRate >> (16+14-buf[17]);
139 /* calc average bytes per second */
140 avgbytespersec = sampleRate*numChannels*sampleSize/8;
141 }
142 else if (memcmp(buf,"SSND",4)==0) {
143 if (sampleSize == 0) {
144 DEBUGF("CODEC_ERROR: unsupported chunk order\n");
145 i = CODEC_ERROR;
146 goto exit;
147 }
148 /* offset2snd */
149 offset2snd = ((buf[8]<<8)|buf[9]);
150 /* blockSize */
151 blockSize = ((buf[10]<<8)|buf[11]);
152 if (blockSize == 0)
153 blockSize = numChannels*sampleSize;
154 numbytes = i-8-offset2snd;
155 i = 8+offset2snd; /* advance to the beginning of data */
156 }
157 else {
158 DEBUGF("unsupported AIFF chunk: '%c%c%c%c', size=%lu\n",
159 buf[0], buf[1], buf[2], buf[3], i);
160 }
161
162 if (i & 0x01) /* odd chunk sizes must be padded */
163 i++;
164 buf += i+8;
165 if (n < (i+8)) {
166 DEBUGF("CODEC_ERROR: AIFF header size > 1024\n");
167 i = CODEC_ERROR;
168 goto exit;
169 }
170 n -= i+8;
171 } /* while 'SSND' */
172
173 if (numChannels == 0) {
174 DEBUGF("CODEC_ERROR: 'COMM' chunk not found or 0-channels file\n");
175 i = CODEC_ERROR;
176 goto exit;
177 }
178 if (numbytes == 0) {
179 DEBUGF("CODEC_ERROR: 'SSND' chunk not found or has zero length\n");
180 i = CODEC_ERROR;
181 goto exit;
182 }
183 if (sampleSize > 24) {
184 DEBUGF("CODEC_ERROR: PCM with more than 24 bits per sample "
185 "is unsupported\n");
186 i = CODEC_ERROR;
187 goto exit;
188 }
189
190 ci->configure(CODEC_DSP_ENABLE, (bool *)true);
191 ci->configure(DSP_SET_FREQUENCY, (long *)(ci->id3->frequency));
192
193 if (sampleSize <= 16) {
194 ci->configure(DSP_SET_SAMPLE_DEPTH, (int *)(16));
195 } else {
196 shortorlong = 2;
197 ci->configure(DSP_DITHER, (bool *)false);
198 ci->configure(DSP_SET_SAMPLE_DEPTH, (long *) (32));
199 ci->configure(DSP_SET_CLIP_MAX, (long *) (2147483647));
200 ci->configure(DSP_SET_CLIP_MIN, (long *) (-2147483647-1));
201 }
202
203 if (numChannels == 2) {
204 ci->configure(DSP_SET_STEREO_MODE, (int *)STEREO_INTERLEAVED);
205 } else if (numChannels == 1) {
206 ci->configure(DSP_SET_STEREO_MODE, (int *)STEREO_MONO);
207 } else {
208 DEBUGF("CODEC_ERROR: more than 2 channels unsupported\n");
209 i = CODEC_ERROR;
210 goto exit;
211 }
212
213 firstblockposn = (1024-n);
214 ci->advance_buffer(firstblockposn);
215
216 /* The main decoder loop */
217
218 bytesdone=0;
219 ci->set_elapsed(0);
220 endofstream=0;
221 /* chunksize is computed so that one chunk is about 1/50s.
222 * this make 4096 for 44.1kHz 16bits stereo.
223 * It also has to be a multiple of blockalign */
224 chunksize = (1 + avgbytespersec / (50*blockSize)) * blockSize;
225 /* check that the output buffer is big enough (convert to samplespersec,
226 then round to the blockSize multiple below) */
227 if (((uint64_t)chunksize*ci->id3->frequency*numChannels*shortorlong)
228 / (uint64_t)avgbytespersec >= AIF_CHUNK_SIZE) {
229 chunksize = ((uint64_t)AIF_CHUNK_SIZE * avgbytespersec
230 / ((uint64_t)ci->id3->frequency * numChannels * shortorlong
231 * blockSize)) * blockSize;
232 }
233
234 while (!endofstream) {
235 uint8_t *aifbuf8;
236
237 ci->yield();
238 if (ci->stop_codec || ci->reload_codec) {
239 break;
240 }
241
242 if (ci->seek_time) {
243 uint32_t newpos;
244
245 /* use avgbytespersec to round to the closest blockalign multiple,
246 add firstblockposn. 64-bit casts to avoid overflows. */
247 newpos = (((uint64_t)avgbytespersec * (ci->seek_time - 1))
248 / (1000LL*blockSize)) * blockSize;
249 if (newpos > numbytes)
250 break;
251 if (ci->seek_buffer(firstblockposn + newpos)) {
252 bytesdone = newpos;
253 }
254 ci->seek_complete();
255 }
256 aifbuf=ci->request_buffer((long *)&n,chunksize);
257 aifbuf8 = (uint8_t*)aifbuf;
258
259 if (n==0)
260 break; /* End of stream */
261
262 if (bytesdone + n > numbytes) {
263 n = numbytes - bytesdone;
264 endofstream = 1;
265 }
266
267 aifbufsize = sizeof(int16_samples);
268
269 if (sampleSize > 24) {
270 for (i=0;i<n;i+=4) {
271 int32_samples[i/4]=(int32_t)((aifbuf8[i]<<24)|
272 (aifbuf8[i+1]<<16)|(aifbuf8[i+2]<<8)|aifbuf8[i+3]);
273 }
274 aifbufsize = n;
275 } else if (sampleSize > 16) {
276 for (i=0;i<n;i+=3) {
277 int32_samples[i/3]=(int32_t)((aifbuf8[i]<<24)|
278 (aifbuf8[i+1]<<16)|(aifbuf8[i+2]<<8));
279 }
280 aifbufsize = n*4/3;
281 } else if (sampleSize > 8) {
282 /* copy data. */
283 for (i=0;i<n;i+=2) {
284 int16_samples[i/2]=(int16_t)((aifbuf8[i]<<8)|aifbuf8[i+1]);
285 }
286 aifbufsize = n;
287 } else {
288 for (i=0;i<n;i++) {
289 int16_samples[i] = (aifbuf8[i]<<8) - 0x8000;
290 }
291 aifbufsize = n*2;
292 }
293
294 while (!ci->pcmbuf_insert((char*)int16_samples, aifbufsize)) {
295 ci->yield();
296 }
297
298 ci->advance_buffer(n);
299 bytesdone += n;
300 if (bytesdone >= numbytes) {
301 endofstream=1;
302 }
303
304 ci->set_elapsed(bytesdone*1000LL/avgbytespersec);
305 }
306
307 if (ci->request_next_track())
308 goto next_track;
309
310 i = CODEC_OK;
311exit:
312 return i;
313}
314