1 /***************************************************************************
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
10 * Copyright (C) 2010 Yoshihisa Uchida
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 ****************************************************************************/
23 #include "codecs/libpcm/support_formats.h"
27 /* Sun Audio file (Au file format) codec
30 * [1] Sun Microsystems, Inc., Header file for Audio, .au, 1992
31 * URL http://www.opengroup.org/public/pubs/external/auformat.html
32 * [2] Wikipedia, Au file format, URL: http://en.wikipedia.org/wiki/Sun_Audio
35 #define PCM_SAMPLE_SIZE (1024*2)
37 static int32_t samples
[PCM_SAMPLE_SIZE
] IBSS_ATTR
;
41 AU_FORMAT_UNSUPPORT
= 0, /* unsupported format */
42 AU_FORMAT_MULAW
, /* G.711 MULAW */
43 AU_FORMAT_PCM
, /* Linear PCM */
44 AU_FORMAT_IEEE_FLOAT
, /* IEEE float */
45 AU_FORMAT_ALAW
, /* G.711 ALAW */
48 static int support_formats
[28][2] = {
49 { AU_FORMAT_UNSUPPORT
, 0 },
50 { AU_FORMAT_MULAW
, 8 }, /* G.711 MULAW */
51 { AU_FORMAT_PCM
, 8 }, /* Linear PCM 8bit (signed) */
52 { AU_FORMAT_PCM
, 16 }, /* Linear PCM 16bit (signed, big endian) */
53 { AU_FORMAT_PCM
, 24 }, /* Linear PCM 24bit (signed, big endian) */
54 { AU_FORMAT_PCM
, 32 }, /* Linear PCM 32bit (signed, big endian) */
55 { AU_FORMAT_IEEE_FLOAT
, 32 }, /* Linear PCM float 32bit (signed, big endian) */
56 { AU_FORMAT_IEEE_FLOAT
, 64 }, /* Linear PCM float 64bit (signed, big endian) */
57 { AU_FORMAT_UNSUPPORT
, 0 }, /* Fragmented sample data */
58 { AU_FORMAT_UNSUPPORT
, 0 }, /* DSP program */
59 { AU_FORMAT_UNSUPPORT
, 0 }, /* 8bit fixed point */
60 { AU_FORMAT_UNSUPPORT
, 0 }, /* 16bit fixed point */
61 { AU_FORMAT_UNSUPPORT
, 0 }, /* 24bit fixed point */
62 { AU_FORMAT_UNSUPPORT
, 0 }, /* 32bit fixed point */
63 { AU_FORMAT_UNSUPPORT
, 0 },
64 { AU_FORMAT_UNSUPPORT
, 0 },
65 { AU_FORMAT_UNSUPPORT
, 0 },
66 { AU_FORMAT_UNSUPPORT
, 0 },
67 { AU_FORMAT_UNSUPPORT
, 0 }, /* 16bit linear with emphasis */
68 { AU_FORMAT_UNSUPPORT
, 0 }, /* 16bit linear compressed */
69 { AU_FORMAT_UNSUPPORT
, 0 }, /* 16bit linear with emphasis and compression */
70 { AU_FORMAT_UNSUPPORT
, 0 }, /* Music kit DSP commands */
71 { AU_FORMAT_UNSUPPORT
, 0 },
72 { AU_FORMAT_UNSUPPORT
, 0 }, /* G.721 MULAW */
73 { AU_FORMAT_UNSUPPORT
, 0 }, /* G.722 */
74 { AU_FORMAT_UNSUPPORT
, 0 }, /* G.723 3bit */
75 { AU_FORMAT_UNSUPPORT
, 0 }, /* G.723 5bit */
76 { AU_FORMAT_ALAW
, 8 }, /* G.711 ALAW */
79 const struct pcm_entry au_codecs
[] = {
80 { AU_FORMAT_MULAW
, get_itut_g711_mulaw_codec
},
81 { AU_FORMAT_PCM
, get_linear_pcm_codec
},
82 { AU_FORMAT_IEEE_FLOAT
, get_ieee_float_codec
},
83 { AU_FORMAT_ALAW
, get_itut_g711_alaw_codec
},
88 static const struct pcm_codec
*get_au_codec(uint32_t formattag
)
92 for (i
= 0; i
< NUM_FORMATS
; i
++)
94 if (au_codecs
[i
].format_tag
== formattag
)
96 if (au_codecs
[i
].get_codec
)
97 return au_codecs
[i
].get_codec();
104 static unsigned int get_be32(uint8_t *buf
)
106 return (buf
[0] << 24) | (buf
[1] << 16) | (buf
[2] << 8) | buf
[3];
109 static int convert_au_format(unsigned int encoding
, struct pcm_format
*fmt
)
113 fmt
->formattag
= AU_FORMAT_UNSUPPORT
;
114 fmt
->bitspersample
= 0;
118 fmt
->formattag
= support_formats
[encoding
][0];
119 fmt
->bitspersample
= support_formats
[encoding
][1];
122 return fmt
->formattag
;
125 /* this is the codec entry point */
126 enum codec_status
codec_main(void)
128 int status
= CODEC_OK
;
129 struct pcm_format format
;
130 uint32_t bytesdone
, decodedsamples
;
136 off_t firstblockposn
; /* position of the first block in file */
137 const struct pcm_codec
*codec
;
140 /* Generic codec initialisation */
141 ci
->configure(DSP_SET_SAMPLE_DEPTH
, 28);
145 DEBUGF("codec_init() error\n");
146 status
= CODEC_ERROR
;
150 while (!*ci
->taginfo_ready
&& !ci
->stop_codec
)
153 codec_set_replaygain(ci
->id3
);
155 ci
->memset(&format
, 0, sizeof(struct pcm_format
));
156 format
.is_signed
= true;
157 format
.is_little_endian
= false;
160 buf
= ci
->request_buffer(&n
, 24);
161 if (n
< 24 || (memcmp(buf
, ".snd", 4) != 0))
164 * headerless sun audio file
165 * It is decoded under conditions.
166 * format: G.711 mu-law
168 * frequency: 8000 kHz
171 format
.formattag
= AU_FORMAT_MULAW
;
173 format
.bitspersample
= 8;
174 format
.numbytes
= ci
->id3
->filesize
;
181 offset
= get_be32(buf
+ 4);
184 DEBUGF("CODEC_ERROR: sun audio offset size is small: %d\n", offset
);
185 status
= CODEC_ERROR
;
189 format
.numbytes
= get_be32(buf
+ 8);
190 if (format
.numbytes
== (uint32_t)0xffffffff)
191 format
.numbytes
= ci
->id3
->filesize
- offset
;
193 format
.formattag
= convert_au_format(get_be32(buf
+ 12), &format
);
194 if (format
.formattag
== AU_FORMAT_UNSUPPORT
)
196 DEBUGF("CODEC_ERROR: sun audio unsupport format: %d\n", get_be32(buf
+ 12));
197 status
= CODEC_ERROR
;
200 /* skip sample rate */
201 format
.channels
= get_be32(buf
+ 20);
202 if (format
.channels
== 0) {
203 DEBUGF("CODEC_ERROR: sun audio 0-channels file\n");
204 status
= CODEC_ERROR
;
209 /* advance to first WAVE chunk */
210 ci
->advance_buffer(offset
);
212 firstblockposn
= offset
;
218 /* blockalign = 1 sample */
219 format
.blockalign
= format
.bitspersample
* format
.channels
>> 3;
222 codec
= get_au_codec(format
.formattag
);
225 DEBUGF("CODEC_ERROR: unsupport sun audio format: %lx\n", format
.formattag
);
226 status
= CODEC_ERROR
;
230 if (!codec
->set_format(&format
))
232 status
= CODEC_ERROR
;
236 if (format
.numbytes
== 0) {
237 DEBUGF("CODEC_ERROR: data size is 0\n");
238 status
= CODEC_ERROR
;
242 /* check chunksize */
243 if ((format
.chunksize
/ format
.blockalign
) * format
.samplesperblock
* format
.channels
245 format
.chunksize
= (PCM_SAMPLE_SIZE
/ format
.blockalign
) * format
.blockalign
;
246 if (format
.chunksize
== 0)
248 DEBUGF("CODEC_ERROR: chunksize is 0\n");
249 status
= CODEC_ERROR
;
253 ci
->configure(DSP_SWITCH_FREQUENCY
, ci
->id3
->frequency
);
254 if (format
.channels
== 2) {
255 ci
->configure(DSP_SET_STEREO_MODE
, STEREO_INTERLEAVED
);
256 } else if (format
.channels
== 1) {
257 ci
->configure(DSP_SET_STEREO_MODE
, STEREO_MONO
);
259 DEBUGF("CODEC_ERROR: more than 2 channels\n");
260 status
= CODEC_ERROR
;
264 /* The main decoder loop */
267 while (!endofstream
) {
269 if (ci
->stop_codec
|| ci
->new_track
) {
274 /* 2nd args(read_buffer) is unnecessary in the format which Sun Audio supports. */
275 struct pcm_pos
*newpos
= codec
->get_seek_pos(ci
->seek_time
, NULL
);
277 decodedsamples
= newpos
->samples
;
278 if (newpos
->pos
> format
.numbytes
)
280 if (ci
->seek_buffer(firstblockposn
+ newpos
->pos
))
282 bytesdone
= newpos
->pos
;
287 aubuf
= (uint8_t *)ci
->request_buffer(&n
, format
.chunksize
);
289 break; /* End of stream */
290 if (bytesdone
+ n
> format
.numbytes
) {
291 n
= format
.numbytes
- bytesdone
;
295 status
= codec
->decode(aubuf
, n
, samples
, &bufcount
);
296 if (status
== CODEC_ERROR
)
298 DEBUGF("codec error\n");
302 ci
->pcmbuf_insert(samples
, NULL
, bufcount
);
303 ci
->advance_buffer(n
);
305 decodedsamples
+= bufcount
;
307 if (bytesdone
>= format
.numbytes
)
309 ci
->set_elapsed(decodedsamples
*1000LL/ci
->id3
->frequency
);
314 if (ci
->request_next_track())