comparison decoders/au.c @ 213:948b62500a54

Initial add.
author Ryan C. Gordon <icculus@icculus.org>
date Sun, 13 Jan 2002 19:48:16 +0000
parents
children 9bab949e2318
comparison
equal deleted inserted replaced
212:8c2cb920a383 213:948b62500a54
1 /*
2 * SDL_sound -- An abstract sound format decoding API.
3 * Copyright (C) 2001 Ryan C. Gordon.
4 *
5 * This library is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU Lesser General Public
7 * License as published by the Free Software Foundation; either
8 * version 2.1 of the License, or (at your option) any later version.
9 *
10 * This library is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 * Lesser General Public License for more details.
14 *
15 * You should have received a copy of the GNU Lesser General Public
16 * License along with this library; if not, write to the Free Software
17 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
18 */
19
20 /*
21 * Sun/NeXT .au decoder for SDL_sound.
22 * Formats supported: 8 and 16 bit linear PCM, 8 bit µ-law.
23 * Files without valid header are assumed to be 8 bit µ-law, 8kHz, mono.
24 *
25 * Please see the file COPYING in the source's root directory.
26 *
27 * This file written by Mattias Engdegĺrd. (f91-men@nada.kth.se)
28 */
29
30 #if HAVE_CONFIG_H
31 # include <config.h>
32 #endif
33
34 #ifdef SOUND_SUPPORTS_AU
35
36 #include <stdio.h>
37 #include <stdlib.h>
38 #include <string.h>
39 #include <assert.h>
40
41 #include "SDL_sound.h"
42
43 #define __SDL_SOUND_INTERNAL__
44 #include "SDL_sound_internal.h"
45
46 static int AU_init(void);
47 static void AU_quit(void);
48 static int AU_open(Sound_Sample *sample, const char *ext);
49 static void AU_close(Sound_Sample *sample);
50 static Uint32 AU_read(Sound_Sample *sample);
51
52 /*
53 * Sometimes the extension ".snd" is used for these files (mostly on the NeXT),
54 * and the magic number comes from this. However it may clash with other
55 * formats and is somewhat of an anachronism, so only .au is used here.
56 */
57 static const char *extensions_au[] = { "AU", NULL };
58 const Sound_DecoderFunctions __Sound_DecoderFunctions_AU =
59 {
60 {
61 extensions_au,
62 "Sun/NeXT audio file format",
63 "Mattias Engdegĺrd <f91-men@nada.kth.se>",
64 "http://www.icculus.org/SDL_sound/"
65 },
66
67 AU_init,
68 AU_quit,
69 AU_open,
70 AU_close,
71 AU_read
72 };
73
74 /* no init/deinit needed */
75 static int AU_init(void)
76 {
77 return(1);
78 }
79
80 static void AU_quit(void)
81 {
82 /* no-op. */
83 }
84
85 struct au_file_hdr
86 {
87 Uint32 magic;
88 Uint32 hdr_size;
89 Uint32 data_size;
90 Uint32 encoding;
91 Uint32 sample_rate;
92 Uint32 channels;
93 };
94
95 #define HDR_SIZE 24
96
97 enum
98 {
99 AU_ENC_ULAW_8 = 1, /* 8-bit ISDN µ-law */
100 AU_ENC_LINEAR_8 = 2, /* 8-bit linear PCM */
101 AU_ENC_LINEAR_16 = 3, /* 16-bit linear PCM */
102
103 /* the rest are unsupported (I have never seen them in the wild) */
104 AU_ENC_LINEAR_24 = 4, /* 24-bit linear PCM */
105 AU_ENC_LINEAR_32 = 5, /* 32-bit linear PCM */
106 AU_ENC_FLOAT = 6, /* 32-bit IEEE floating point */
107 AU_ENC_DOUBLE = 7, /* 64-bit IEEE floating point */
108 /* more Sun formats, not supported either */
109 AU_ENC_ADPCM_G721 = 23,
110 AU_ENC_ADPCM_G722 = 24,
111 AU_ENC_ADPCM_G723_3 = 25,
112 AU_ENC_ADPCM_G723_5 = 26,
113 AU_ENC_ALAW_8 = 27
114 };
115
116 struct audec
117 {
118 unsigned remaining;
119 int encoding;
120 };
121
122
123 #define AU_MAGIC 0x646E732E /* ".snd", in ASCII */
124
125 static int AU_open(Sound_Sample *sample, const char *ext)
126 {
127 Sound_SampleInternal *internal = sample->opaque;
128 SDL_RWops *rw = internal->rw;
129 int r, skip, hsize, i;
130 struct au_file_hdr hdr;
131 char c;
132 struct audec *dec = malloc(sizeof *dec);
133 BAIL_IF_MACRO(dec == NULL, ERR_OUT_OF_MEMORY, 0);
134 internal->decoder_private = dec;
135
136 r = SDL_RWread(rw, &hdr, 1, HDR_SIZE);
137 if (r < HDR_SIZE)
138 {
139 Sound_SetError("No .au file (bad header)");
140 free(dec);
141 return 0;
142 }
143
144 if (SDL_SwapLE32(hdr.magic) == AU_MAGIC)
145 {
146 /* valid magic */
147 dec->encoding = SDL_SwapBE32(hdr.encoding);
148 switch(dec->encoding)
149 {
150 case AU_ENC_ULAW_8:
151 /* Convert 8-bit µ-law to 16-bit linear on the fly. This is
152 slightly wasteful if the audio driver must convert them
153 back, but µ-law only devices are rare (mostly _old_ Suns) */
154 sample->actual.format = AUDIO_S16SYS;
155 break;
156
157 case AU_ENC_LINEAR_8:
158 sample->actual.format = AUDIO_S8;
159 break;
160
161 case AU_ENC_LINEAR_16:
162 sample->actual.format = AUDIO_S16MSB;
163 break;
164
165 default:
166 Sound_SetError("Unsupported .au encoding");
167 free(dec);
168 return 0;
169 }
170
171 sample->actual.rate = SDL_SwapBE32(hdr.sample_rate);
172 sample->actual.channels = SDL_SwapBE32(hdr.channels);
173 dec->remaining = SDL_SwapBE32(hdr.data_size);
174 hsize = SDL_SwapBE32(hdr.hdr_size);
175
176 /* skip remaining part of header (input may be unseekable) */
177 for (i = HDR_SIZE; i < hsize; i++)
178 SDL_RWread(rw, &c, 1, 1);
179 }
180
181 else if (__Sound_strcasecmp(ext, "au") == 0)
182 {
183 /*
184 * A number of files in the wild have the .au extension but no valid
185 * header; these are traditionally assumed to be 8kHz µ-law. Handle
186 * them here only if the extension is recognized.
187 */
188
189 SNDDBG(("AU: Invalid header, assuming raw 8kHz µ-law.\n"));
190 /* if seeking fails, we lose 24 samples. big deal */
191 SDL_RWseek(rw, -HDR_SIZE, SEEK_CUR);
192 dec->encoding = AU_ENC_ULAW_8;
193 dec->remaining = (Uint32)-1; /* no limit */
194 sample->actual.format = AUDIO_S16SYS;
195 sample->actual.rate = 8000;
196 sample->actual.channels = 1;
197 }
198
199 sample->flags = SOUND_SAMPLEFLAG_NONE;
200
201 SNDDBG(("AU: Accepting data stream.\n"));
202 return 1;
203 }
204
205
206 static void AU_close(Sound_Sample *sample)
207 {
208 Sound_SampleInternal *internal = sample->opaque;
209 free(internal->decoder_private);
210 }
211
212 /* table to convert from µ-law encoding to signed 16-bit samples,
213 generated by a throwaway perl script */
214 static Sint16 ulaw_to_linear[256] = {
215 -32124,-31100,-30076,-29052,-28028,-27004,-25980,-24956,
216 -23932,-22908,-21884,-20860,-19836,-18812,-17788,-16764,
217 -15996,-15484,-14972,-14460,-13948,-13436,-12924,-12412,
218 -11900,-11388,-10876,-10364, -9852, -9340, -8828, -8316,
219 -7932, -7676, -7420, -7164, -6908, -6652, -6396, -6140,
220 -5884, -5628, -5372, -5116, -4860, -4604, -4348, -4092,
221 -3900, -3772, -3644, -3516, -3388, -3260, -3132, -3004,
222 -2876, -2748, -2620, -2492, -2364, -2236, -2108, -1980,
223 -1884, -1820, -1756, -1692, -1628, -1564, -1500, -1436,
224 -1372, -1308, -1244, -1180, -1116, -1052, -988, -924,
225 -876, -844, -812, -780, -748, -716, -684, -652,
226 -620, -588, -556, -524, -492, -460, -428, -396,
227 -372, -356, -340, -324, -308, -292, -276, -260,
228 -244, -228, -212, -196, -180, -164, -148, -132,
229 -120, -112, -104, -96, -88, -80, -72, -64,
230 -56, -48, -40, -32, -24, -16, -8, 0,
231 32124, 31100, 30076, 29052, 28028, 27004, 25980, 24956,
232 23932, 22908, 21884, 20860, 19836, 18812, 17788, 16764,
233 15996, 15484, 14972, 14460, 13948, 13436, 12924, 12412,
234 11900, 11388, 10876, 10364, 9852, 9340, 8828, 8316,
235 7932, 7676, 7420, 7164, 6908, 6652, 6396, 6140,
236 5884, 5628, 5372, 5116, 4860, 4604, 4348, 4092,
237 3900, 3772, 3644, 3516, 3388, 3260, 3132, 3004,
238 2876, 2748, 2620, 2492, 2364, 2236, 2108, 1980,
239 1884, 1820, 1756, 1692, 1628, 1564, 1500, 1436,
240 1372, 1308, 1244, 1180, 1116, 1052, 988, 924,
241 876, 844, 812, 780, 748, 716, 684, 652,
242 620, 588, 556, 524, 492, 460, 428, 396,
243 372, 356, 340, 324, 308, 292, 276, 260,
244 244, 228, 212, 196, 180, 164, 148, 132,
245 120, 112, 104, 96, 88, 80, 72, 64,
246 56, 48, 40, 32, 24, 16, 8, 0
247 };
248
249 static Uint32 AU_read(Sound_Sample *sample)
250 {
251 int ret;
252 Sound_SampleInternal *internal = sample->opaque;
253 struct audec *dec = internal->decoder_private;
254 int maxlen;
255 Uint8 *buf;
256
257 maxlen = internal->buffer_size;
258 buf = internal->buffer;
259 if (dec->encoding == AU_ENC_ULAW_8)
260 {
261 /* We read µ-law samples into the second half of the buffer, so
262 we can expand them to 16-bit samples afterwards */
263 maxlen >>= 1;
264 buf += maxlen;
265 }
266
267 if(maxlen > dec->remaining)
268 maxlen = dec->remaining;
269 ret = SDL_RWread(internal->rw, buf, 1, maxlen);
270 if (ret == 0)
271 sample->flags |= SOUND_SAMPLEFLAG_EOF;
272 else if (ret == -1)
273 sample->flags |= SOUND_SAMPLEFLAG_ERROR;
274 else
275 {
276 dec->remaining -= ret;
277 if (ret < maxlen)
278 sample->flags |= SOUND_SAMPLEFLAG_EAGAIN;
279
280 if (dec->encoding == AU_ENC_ULAW_8)
281 {
282 int i;
283 Sint16 *dst = internal->buffer;
284 for (i = 0; i < ret; i++)
285 dst[i] = ulaw_to_linear[buf[i]];
286 ret <<= 1; /* return twice as much as read */
287 }
288 }
289
290 return ret;
291 }
292
293 #endif /* SOUND_SUPPORTS_AU */
294