summaryrefslogtreecommitdiff
path: root/apps/codecs/aiff.c
diff options
context:
space:
mode:
Diffstat (limited to 'apps/codecs/aiff.c')
-rw-r--r--apps/codecs/aiff.c213
1 files changed, 120 insertions, 93 deletions
diff --git a/apps/codecs/aiff.c b/apps/codecs/aiff.c
index 9a675415e2..1b8c2da920 100644
--- a/apps/codecs/aiff.c
+++ b/apps/codecs/aiff.c
@@ -8,6 +8,7 @@
8 * $Id$ 8 * $Id$
9 * 9 *
10 * Copyright (c) 2005 Jvo Studer 10 * Copyright (c) 2005 Jvo Studer
11 * Copyright (c) 2009 Yoshihisa Uchida
11 * 12 *
12 * This program is free software; you can redistribute it and/or 13 * This program is free software; you can redistribute it and/or
13 * modify it under the terms of the GNU General Public License 14 * modify it under the terms of the GNU General Public License
@@ -21,48 +22,62 @@
21 22
22#include "codeclib.h" 23#include "codeclib.h"
23#include <inttypes.h> 24#include <inttypes.h>
25#include "codecs/libpcm/support_formats.h"
24 26
25CODEC_HEADER 27CODEC_HEADER
26 28
27/* Macro that sign extends an unsigned byte */ 29#define FOURCC(c1, c2, c3, c4) \
28#define SE(x) ((int32_t)((int8_t)(x))) 30((((uint32_t)c1)<<24)|(((uint32_t)c2)<<16)|(((uint32_t)c3)<<8)|((uint32_t)c4))
29 31
30/* This codec supports AIFF files with the following formats: 32/* This codec supports the following AIFC compressionType formats */
31 * - PCM, 8, 16 and 24 bits, mono or stereo 33enum {
32 */ 34 AIFC_FORMAT_PCM = FOURCC('N', 'O', 'N', 'E'), /* AIFC PCM Format (big endian) */
35 AIFC_FORMAT_ALAW = FOURCC('a', 'l', 'a', 'w'), /* AIFC ALaw compressed */
36 AIFC_FORMAT_MULAW = FOURCC('u', 'l', 'a', 'w'), /* AIFC uLaw compressed */
37};
33 38
34enum 39static const struct pcm_entry pcm_codecs[] = {
35{ 40 { AIFC_FORMAT_PCM, get_linear_pcm_codec },
36 AIFF_FORMAT_PCM = 0x0001, /* AIFF PCM Format (big endian) */ 41 { AIFC_FORMAT_ALAW, get_itut_g711_alaw_codec },
37 IEEE_FORMAT_FLOAT = 0x0003, /* IEEE Float */ 42 { AIFC_FORMAT_MULAW, get_itut_g711_mulaw_codec },
38 AIFF_FORMAT_ALAW = 0x0004, /* AIFC ALaw compressed */
39 AIFF_FORMAT_ULAW = 0x0005 /* AIFC uLaw compressed */
40}; 43};
41 44
42/* Maximum number of bytes to process in one iteration */ 45#define NUM_FORMATS 3
43/* for 44.1kHz stereo 16bits, this represents 0.023s ~= 1/50s */
44#define AIF_CHUNK_SIZE (1024*2)
45 46
46static int32_t samples[AIF_CHUNK_SIZE] IBSS_ATTR; 47static int32_t samples[PCM_CHUNK_SIZE] IBSS_ATTR;
48
49static const struct pcm_codec *get_codec(uint32_t formattag)
50{
51 int i;
52
53 for (i = 0; i < NUM_FORMATS; i++)
54 {
55 if (pcm_codecs[i].format_tag == formattag)
56 {
57 if (pcm_codecs[i].get_codec)
58 return pcm_codecs[i].get_codec();
59 return 0;
60 }
61 }
62 return 0;
63}
47 64
48enum codec_status codec_main(void) 65enum codec_status codec_main(void)
49{ 66{
50 uint32_t numbytes, bytesdone; 67 int status = CODEC_OK;
51 uint16_t num_channels = 0; 68 struct pcm_format format;
69 uint32_t bytesdone, decodedbytes;
52 uint32_t num_sample_frames = 0; 70 uint32_t num_sample_frames = 0;
53 uint16_t sample_size = 0; 71 uint32_t i = CODEC_OK;
54 uint32_t sample_rate = 0;
55 uint32_t i;
56 size_t n; 72 size_t n;
57 int bufcount; 73 int bufcount;
58 int endofstream; 74 int endofstream;
59 unsigned char *buf; 75 unsigned char *buf;
60 uint8_t *aifbuf; 76 uint8_t *aifbuf;
61 long chunksize;
62 uint32_t offset2snd = 0; 77 uint32_t offset2snd = 0;
63 uint16_t block_size = 0;
64 uint32_t avgbytespersec = 0;
65 off_t firstblockposn; /* position of the first block in file */ 78 off_t firstblockposn; /* position of the first block in file */
79 bool is_aifc = false;
80 const struct pcm_codec *codec;
66 81
67 /* Generic codec initialisation */ 82 /* Generic codec initialisation */
68 ci->configure(DSP_SET_SAMPLE_DEPTH, 28); 83 ci->configure(DSP_SET_SAMPLE_DEPTH, 28);
@@ -84,45 +99,80 @@ next_track:
84 i = CODEC_ERROR; 99 i = CODEC_ERROR;
85 goto done; 100 goto done;
86 } 101 }
87 if ((memcmp(buf, "FORM", 4) != 0) || (memcmp(&buf[8], "AIFF", 4) != 0)) { 102
103 if (memcmp(buf, "FORM", 4) != 0)
104 {
105 DEBUGF("CODEC_ERROR: does not aiff format %c%c%c%c\n", buf[0], buf[1], buf[2], buf[3]);
106 i = CODEC_ERROR;
107 goto done;
108 }
109 if (memcmp(&buf[8], "AIFF", 4) == 0)
110 is_aifc = false;
111 else if (memcmp(&buf[8], "AIFC", 4) == 0)
112 is_aifc = true;
113 else
114 {
115 DEBUGF("CODEC_ERROR: does not aiff format %c%c%c%c\n", buf[8], buf[9], buf[10], buf[11]);
88 i = CODEC_ERROR; 116 i = CODEC_ERROR;
89 goto done; 117 goto done;
90 } 118 }
91 119
92 buf += 12; 120 buf += 12;
93 n -= 12; 121 n -= 12;
94 numbytes = 0; 122
123 ci->memset(&format, 0, sizeof(struct pcm_format));
124 format.is_signed = true;
125 format.is_little_endian = false;
126
127 decodedbytes = 0;
128 codec = 0;
95 129
96 /* read until 'SSND' chunk, which typically is last */ 130 /* read until 'SSND' chunk, which typically is last */
97 while (numbytes == 0 && n >= 8) { 131 while (format.numbytes == 0 && n >= 8)
132 {
98 /* chunkSize */ 133 /* chunkSize */
99 i = ((buf[4]<<24)|(buf[5]<<16)|(buf[6]<<8)|buf[7]); 134 i = ((buf[4]<<24)|(buf[5]<<16)|(buf[6]<<8)|buf[7]);
100 if (memcmp(buf, "COMM", 4) == 0) { 135 if (memcmp(buf, "COMM", 4) == 0) {
101 if (i < 18) { 136 if ((!is_aifc && i < 18) || (is_aifc && i < 22))
102 DEBUGF("CODEC_ERROR: 'COMM' chunk size=%lu < 18\n", 137 {
103 (unsigned long)i); 138 DEBUGF("CODEC_ERROR: 'COMM' chunk size=%lu < %d\n",
139 (unsigned long)i, (is_aifc)?22:18);
104 i = CODEC_ERROR; 140 i = CODEC_ERROR;
105 goto done; 141 goto done;
106 } 142 }
107 /* num_channels */ 143 /* num_channels */
108 num_channels = ((buf[8]<<8)|buf[9]); 144 format.channels = ((buf[8]<<8)|buf[9]);
109 /* num_sample_frames */ 145 /* num_sample_frames */
110 num_sample_frames = ((buf[10]<<24)|(buf[11]<<16)|(buf[12]<<8) 146 num_sample_frames = ((buf[10]<<24)|(buf[11]<<16)|(buf[12]<<8)
111 |buf[13]); 147 |buf[13]);
112 /* sample_size */ 148 /* sample_size */
113 sample_size = ((buf[14]<<8)|buf[15]); 149 format.bitspersample = ((buf[14]<<8)|buf[15]);
114 /* sample_rate (don't use last 4 bytes, only integer fs) */ 150 /* sample_rate (don't use last 4 bytes, only integer fs) */
115 if (buf[16] != 0x40) { 151 if (buf[16] != 0x40) {
116 DEBUGF("CODEC_ERROR: weird sampling rate (no @)\n"); 152 DEBUGF("CODEC_ERROR: weird sampling rate (no @)\n");
117 i = CODEC_ERROR; 153 i = CODEC_ERROR;
118 goto done; 154 goto done;
119 } 155 }
120 sample_rate = ((buf[18]<<24)|(buf[19]<<16)|(buf[20]<<8)|buf[21])+1; 156 format.samplespersec = ((buf[18]<<24)|(buf[19]<<16)|(buf[20]<<8)|buf[21])+1;
121 sample_rate = sample_rate >> (16 + 14 - buf[17]); 157 format.samplespersec >>= (16 + 14 - buf[17]);
158 /* compressionType (AIFC only) */
159 if (is_aifc)
160 {
161 format.formattag = (buf[26]<<24)|(buf[27]<<16)|(buf[28]<<8)|buf[29];
162
163 /*
164 * aiff's sample_size is uncompressed sound data size.
165 * But format.bitspersample is compressed sound data size.
166 */
167 if (format.formattag == AIFC_FORMAT_ALAW || format.formattag == AIFC_FORMAT_MULAW)
168 format.bitspersample = 8;
169 }
170 else
171 format.formattag = AIFC_FORMAT_PCM;
122 /* calc average bytes per second */ 172 /* calc average bytes per second */
123 avgbytespersec = sample_rate*num_channels*sample_size/8; 173 format.avgbytespersec = format.samplespersec*format.channels*format.bitspersample/8;
124 } else if (memcmp(buf, "SSND", 4)==0) { 174 } else if (memcmp(buf, "SSND", 4)==0) {
125 if (sample_size == 0) { 175 if (format.bitspersample == 0) {
126 DEBUGF("CODEC_ERROR: unsupported chunk order\n"); 176 DEBUGF("CODEC_ERROR: unsupported chunk order\n");
127 i = CODEC_ERROR; 177 i = CODEC_ERROR;
128 goto done; 178 goto done;
@@ -130,11 +180,14 @@ next_track:
130 /* offset2snd */ 180 /* offset2snd */
131 offset2snd = (buf[8]<<24)|(buf[9]<<16)|(buf[10]<<8)|buf[11]; 181 offset2snd = (buf[8]<<24)|(buf[9]<<16)|(buf[10]<<8)|buf[11];
132 /* block_size */ 182 /* block_size */
133 block_size = (buf[12]<<24)|(buf[13]<<16)|(buf[14]<<8)|buf[15]; 183 format.blockalign = (buf[12]<<24)|(buf[13]<<16)|(buf[14]<<8)|buf[15];
134 if (block_size == 0) 184 if (format.blockalign == 0)
135 block_size = num_channels*sample_size; 185 format.blockalign = format.channels*format.bitspersample;
136 numbytes = i - 8 - offset2snd; 186 format.numbytes = i - 8 - offset2snd;
137 i = 8 + offset2snd; /* advance to the beginning of data */ 187 i = 8 + offset2snd; /* advance to the beginning of data */
188 } else if (is_aifc && (memcmp(buf, "FVER", 4)==0)) {
189 /* Format Version Chunk (AIFC only chunk) */
190 /* skip this chunk */
138 } else { 191 } else {
139 DEBUGF("unsupported AIFF chunk: '%c%c%c%c', size=%lu\n", 192 DEBUGF("unsupported AIFF chunk: '%c%c%c%c', size=%lu\n",
140 buf[0], buf[1], buf[2], buf[3], (unsigned long)i); 193 buf[0], buf[1], buf[2], buf[3], (unsigned long)i);
@@ -151,28 +204,36 @@ next_track:
151 n -= i + 8; 204 n -= i + 8;
152 } /* while 'SSND' */ 205 } /* while 'SSND' */
153 206
154 if (num_channels == 0) { 207 if (format.channels == 0) {
155 DEBUGF("CODEC_ERROR: 'COMM' chunk not found or 0-channels file\n"); 208 DEBUGF("CODEC_ERROR: 'COMM' chunk not found or 0-channels file\n");
156 i = CODEC_ERROR; 209 i = CODEC_ERROR;
157 goto done; 210 goto done;
158 } 211 }
159 if (numbytes == 0) { 212 if (format.numbytes == 0) {
160 DEBUGF("CODEC_ERROR: 'SSND' chunk not found or has zero length\n"); 213 DEBUGF("CODEC_ERROR: 'SSND' chunk not found or has zero length\n");
161 i = CODEC_ERROR; 214 i = CODEC_ERROR;
162 goto done; 215 goto done;
163 } 216 }
164 if (sample_size > 24) { 217
165 DEBUGF("CODEC_ERROR: PCM with more than 24 bits per sample " 218 codec = get_codec(format.formattag);
166 "is unsupported\n"); 219 if (codec == 0)
220 {
221 DEBUGF("CODEC_ERROR: AIFC does not support compressionType: 0x%x\n", format.formattag);
222 i = CODEC_ERROR;
223 goto done;
224 }
225
226 if (!codec->set_format(&format, 0))
227 {
167 i = CODEC_ERROR; 228 i = CODEC_ERROR;
168 goto done; 229 goto done;
169 } 230 }
170 231
171 ci->configure(DSP_SWITCH_FREQUENCY, ci->id3->frequency); 232 ci->configure(DSP_SWITCH_FREQUENCY, ci->id3->frequency);
172 233
173 if (num_channels == 2) { 234 if (format.channels == 2) {
174 ci->configure(DSP_SET_STEREO_MODE, STEREO_INTERLEAVED); 235 ci->configure(DSP_SET_STEREO_MODE, STEREO_INTERLEAVED);
175 } else if (num_channels == 1) { 236 } else if (format.channels == 1) {
176 ci->configure(DSP_SET_STEREO_MODE, STEREO_MONO); 237 ci->configure(DSP_SET_STEREO_MODE, STEREO_MONO);
177 } else { 238 } else {
178 DEBUGF("CODEC_ERROR: more than 2 channels unsupported\n"); 239 DEBUGF("CODEC_ERROR: more than 2 channels unsupported\n");
@@ -187,18 +248,6 @@ next_track:
187 bytesdone = 0; 248 bytesdone = 0;
188 ci->set_elapsed(0); 249 ci->set_elapsed(0);
189 endofstream = 0; 250 endofstream = 0;
190 /* chunksize is computed so that one chunk is about 1/50s.
191 * this make 4096 for 44.1kHz 16bits stereo.
192 * It also has to be a multiple of blockalign */
193 chunksize = (1 + avgbytespersec/(50*block_size))*block_size;
194 /* check that the output buffer is big enough (convert to samplespersec,
195 then round to the block_size multiple below) */
196 if (((uint64_t)chunksize*ci->id3->frequency*num_channels*2)
197 /(uint64_t)avgbytespersec >= AIF_CHUNK_SIZE) {
198 chunksize = ((uint64_t)AIF_CHUNK_SIZE*avgbytespersec
199 /((uint64_t)ci->id3->frequency*num_channels*2
200 *block_size))*block_size;
201 }
202 251
203 while (!endofstream) { 252 while (!endofstream) {
204 ci->yield(); 253 ci->yield();
@@ -206,61 +255,39 @@ next_track:
206 break; 255 break;
207 256
208 if (ci->seek_time) { 257 if (ci->seek_time) {
209 uint32_t newpos; 258 uint32_t newpos = codec->get_seek_pos(ci->seek_time);
210 259 if (newpos > format.numbytes)
211 /* use avgbytespersec to round to the closest blockalign multiple,
212 add firstblockposn. 64-bit casts to avoid overflows. */
213 newpos = (((uint64_t)avgbytespersec*(ci->seek_time - 1))
214 /(1000LL*block_size))*block_size;
215 if (newpos > numbytes)
216 break; 260 break;
217 if (ci->seek_buffer(firstblockposn + newpos)) 261 if (ci->seek_buffer(firstblockposn + newpos))
218 bytesdone = newpos; 262 bytesdone = newpos;
219 ci->seek_complete(); 263 ci->seek_complete();
220 } 264 }
221 aifbuf = (uint8_t *)ci->request_buffer(&n, chunksize); 265 aifbuf = (uint8_t *)ci->request_buffer(&n, format.chunksize);
222 266
223 if (n == 0) 267 if (n == 0)
224 break; /* End of stream */ 268 break; /* End of stream */
225 269
226 if (bytesdone + n > numbytes) { 270 if (bytesdone + n > format.numbytes) {
227 n = numbytes - bytesdone; 271 n = format.numbytes - bytesdone;
228 endofstream = 1; 272 endofstream = 1;
229 } 273 }
230 274
231 if (sample_size > 24) { 275 status = codec->decode(aifbuf, n, samples, &bufcount);
232 for (i = 0; i < n; i += 4) { 276 if (status == CODEC_ERROR)
233 samples[i/4] = (SE(aifbuf[i])<<21)|(aifbuf[i + 1]<<13) 277 {
234 |(aifbuf[i + 2]<<5)|(aifbuf[i + 3]>>3); 278 DEBUGF("codec error\n");
235 } 279 goto done;
236 bufcount = n >> 2;
237 } else if (sample_size > 16) {
238 for (i = 0; i < n; i += 3) {
239 samples[i/3] = (SE(aifbuf[i])<<21)|(aifbuf[i + 1]<<13)
240 |(aifbuf[i + 2]<<5);
241 }
242 bufcount = n/3;
243 } else if (sample_size > 8) {
244 for (i = 0; i < n; i += 2)
245 samples[i/2] = (SE(aifbuf[i])<<21)|(aifbuf[i + 1]<<13);
246 bufcount = n >> 1;
247 } else {
248 for (i = 0; i < n; i++)
249 samples[i] = SE(aifbuf[i]) << 21;
250 bufcount = n;
251 } 280 }
252 281
253 if (num_channels == 2)
254 bufcount >>= 1;
255
256 ci->pcmbuf_insert(samples, NULL, bufcount); 282 ci->pcmbuf_insert(samples, NULL, bufcount);
257 283
258 ci->advance_buffer(n); 284 ci->advance_buffer(n);
259 bytesdone += n; 285 bytesdone += n;
260 if (bytesdone >= numbytes) 286 decodedbytes += bufcount;
287 if (bytesdone >= format.numbytes)
261 endofstream = 1; 288 endofstream = 1;
262 289
263 ci->set_elapsed(bytesdone*1000LL/avgbytespersec); 290 ci->set_elapsed(decodedbytes*1000LL/ci->id3->frequency);
264 } 291 }
265 i = CODEC_OK; 292 i = CODEC_OK;
266 293