Skip to content

Latest commit

 

History

History
383 lines (324 loc) · 12.3 KB

au.c

File metadata and controls

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