Mercurial > SDL_sound_CoreAudio
annotate SDL_sound.c @ 31:530fa59d5db9
Added Ogg Vorbis to "showcfg" target.
author | Ryan C. Gordon <icculus@icculus.org> |
---|---|
date | Wed, 19 Sep 2001 15:38:23 +0000 |
parents | ddc3614c9042 |
children | f27bcbcaeab1 |
rev | line source |
---|---|
4 | 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 * This file implements the core API, which is relatively simple. | |
22 * The real meat of SDL_sound is in the decoders directory. | |
23 * | |
24 * Documentation is in SDL_sound.h ... It's verbose, honest. :) | |
25 * | |
26 * Please see the file LICENSE in the source's root directory. | |
27 * | |
28 * This file written by Ryan C. Gordon. (icculus@clutteredmind.org) | |
29 */ | |
30 | |
31 | |
32 #include <stdio.h> | |
33 #include <stdlib.h> | |
34 #include <string.h> | |
35 #include <assert.h> | |
36 #include <ctype.h> | |
37 | |
38 #include "SDL.h" | |
39 #include "SDL_sound.h" | |
40 | |
41 #define __SDL_SOUND_INTERNAL__ | |
42 #include "SDL_sound_internal.h" | |
43 | |
44 | |
45 /* The various decoder drivers... */ | |
46 | |
10
cc2c32349380
Some debugging output, and MP3 and VOC entries, added.
Ryan C. Gordon <icculus@icculus.org>
parents:
4
diff
changeset
|
47 #if (defined SOUND_SUPPORTS_MP3) |
cc2c32349380
Some debugging output, and MP3 and VOC entries, added.
Ryan C. Gordon <icculus@icculus.org>
parents:
4
diff
changeset
|
48 extern const Sound_DecoderFunctions __Sound_DecoderFunctions_MP3; |
cc2c32349380
Some debugging output, and MP3 and VOC entries, added.
Ryan C. Gordon <icculus@icculus.org>
parents:
4
diff
changeset
|
49 #endif |
cc2c32349380
Some debugging output, and MP3 and VOC entries, added.
Ryan C. Gordon <icculus@icculus.org>
parents:
4
diff
changeset
|
50 |
20 | 51 #if (defined SOUND_SUPPORTS_WAV) |
52 extern const Sound_DecoderFunctions __Sound_DecoderFunctions_WAV; | |
53 #endif | |
54 | |
26
ddc3614c9042
Bugfix (thanks Tsuyoshi Iguchi!), and Ogg Vorbis decoder entry.
Ryan C. Gordon <icculus@icculus.org>
parents:
20
diff
changeset
|
55 #if (defined SOUND_SUPPORTS_OGG) |
ddc3614c9042
Bugfix (thanks Tsuyoshi Iguchi!), and Ogg Vorbis decoder entry.
Ryan C. Gordon <icculus@icculus.org>
parents:
20
diff
changeset
|
56 extern const Sound_DecoderFunctions __Sound_DecoderFunctions_OGG; |
ddc3614c9042
Bugfix (thanks Tsuyoshi Iguchi!), and Ogg Vorbis decoder entry.
Ryan C. Gordon <icculus@icculus.org>
parents:
20
diff
changeset
|
57 #endif |
ddc3614c9042
Bugfix (thanks Tsuyoshi Iguchi!), and Ogg Vorbis decoder entry.
Ryan C. Gordon <icculus@icculus.org>
parents:
20
diff
changeset
|
58 |
4 | 59 #if (defined SOUND_SUPPORTS_VOC) |
60 extern const Sound_DecoderFunctions __Sound_DecoderFunctions_VOC; | |
61 #endif | |
62 | |
63 #if (defined SOUND_SUPPORTS_RAW) | |
64 extern const Sound_DecoderFunctions __Sound_DecoderFunctions_RAW; | |
65 #endif | |
66 | |
67 static const Sound_DecoderFunctions *decoderFuncs[] = | |
68 { | |
10
cc2c32349380
Some debugging output, and MP3 and VOC entries, added.
Ryan C. Gordon <icculus@icculus.org>
parents:
4
diff
changeset
|
69 #if (defined SOUND_SUPPORTS_MP3) |
cc2c32349380
Some debugging output, and MP3 and VOC entries, added.
Ryan C. Gordon <icculus@icculus.org>
parents:
4
diff
changeset
|
70 &__Sound_DecoderFunctions_MP3, |
cc2c32349380
Some debugging output, and MP3 and VOC entries, added.
Ryan C. Gordon <icculus@icculus.org>
parents:
4
diff
changeset
|
71 #endif |
cc2c32349380
Some debugging output, and MP3 and VOC entries, added.
Ryan C. Gordon <icculus@icculus.org>
parents:
4
diff
changeset
|
72 |
20 | 73 #if (defined SOUND_SUPPORTS_WAV) |
74 &__Sound_DecoderFunctions_WAV, | |
75 #endif | |
76 | |
26
ddc3614c9042
Bugfix (thanks Tsuyoshi Iguchi!), and Ogg Vorbis decoder entry.
Ryan C. Gordon <icculus@icculus.org>
parents:
20
diff
changeset
|
77 #if (defined SOUND_SUPPORTS_OGG) |
ddc3614c9042
Bugfix (thanks Tsuyoshi Iguchi!), and Ogg Vorbis decoder entry.
Ryan C. Gordon <icculus@icculus.org>
parents:
20
diff
changeset
|
78 &__Sound_DecoderFunctions_OGG, |
ddc3614c9042
Bugfix (thanks Tsuyoshi Iguchi!), and Ogg Vorbis decoder entry.
Ryan C. Gordon <icculus@icculus.org>
parents:
20
diff
changeset
|
79 #endif |
ddc3614c9042
Bugfix (thanks Tsuyoshi Iguchi!), and Ogg Vorbis decoder entry.
Ryan C. Gordon <icculus@icculus.org>
parents:
20
diff
changeset
|
80 |
4 | 81 #if (defined SOUND_SUPPORTS_VOC) |
82 &__Sound_DecoderFunctions_VOC, | |
83 #endif | |
84 | |
85 #if (defined SOUND_SUPPORTS_RAW) | |
86 &__Sound_DecoderFunctions_RAW, | |
87 #endif | |
88 | |
89 NULL | |
90 }; | |
91 | |
92 | |
93 | |
94 /* General SDL_sound state ... */ | |
95 | |
96 static int initialized = 0; | |
97 static Sound_Sample *samplesList = NULL; /* this is a linked list. */ | |
98 static const Sound_DecoderInfo **available_decoders = NULL; | |
99 | |
100 | |
101 /* functions ... */ | |
102 | |
103 void Sound_GetLinkedVersion(Sound_Version *ver) | |
104 { | |
105 if (ver != NULL) | |
106 { | |
107 ver->major = SOUND_VER_MAJOR; | |
108 ver->minor = SOUND_VER_MINOR; | |
109 ver->patch = SOUND_VER_PATCH; | |
110 } /* if */ | |
111 } /* Sound_GetLinkedVersion */ | |
112 | |
113 | |
114 int Sound_Init(void) | |
115 { | |
116 size_t i; | |
117 BAIL_IF_MACRO(initialized, ERR_IS_INITIALIZED, 0); | |
118 samplesList = NULL; | |
119 | |
120 SDL_Init(SDL_INIT_AUDIO); | |
121 | |
122 for (i = 0; decoderFuncs[i] != NULL; i++) | |
123 ; /* do nothing. */ | |
124 | |
125 available_decoders = (const Sound_DecoderInfo **) | |
26
ddc3614c9042
Bugfix (thanks Tsuyoshi Iguchi!), and Ogg Vorbis decoder entry.
Ryan C. Gordon <icculus@icculus.org>
parents:
20
diff
changeset
|
126 malloc((i + 1) * sizeof (Sound_DecoderInfo *)); |
4 | 127 BAIL_IF_MACRO(available_decoders == NULL, ERR_OUT_OF_MEMORY, 0); |
128 | |
129 for (i = 0; decoderFuncs[i] != NULL; i++) | |
130 available_decoders[i] = &decoderFuncs[i]->info; | |
131 | |
26
ddc3614c9042
Bugfix (thanks Tsuyoshi Iguchi!), and Ogg Vorbis decoder entry.
Ryan C. Gordon <icculus@icculus.org>
parents:
20
diff
changeset
|
132 available_decoders[i] = NULL; |
ddc3614c9042
Bugfix (thanks Tsuyoshi Iguchi!), and Ogg Vorbis decoder entry.
Ryan C. Gordon <icculus@icculus.org>
parents:
20
diff
changeset
|
133 |
4 | 134 initialized = 1; |
135 return(1); | |
136 } /* Sound_Init */ | |
137 | |
138 | |
139 int Sound_Quit(void) | |
140 { | |
141 BAIL_IF_MACRO(!initialized, ERR_NOT_INITIALIZED, 0); | |
142 | |
143 while (((volatile Sound_Sample *) samplesList) != NULL) | |
144 Sound_FreeSample(samplesList); | |
145 | |
146 if (available_decoders != NULL) | |
147 free(available_decoders); | |
148 available_decoders = NULL; | |
149 | |
150 initialized = 0; | |
151 | |
152 return(1); | |
153 } /* Sound_Quit */ | |
154 | |
155 | |
156 const Sound_DecoderInfo **Sound_AvailableDecoders(void) | |
157 { | |
158 return(available_decoders); /* READ. ONLY. */ | |
159 } /* Sound_AvailableDecoders */ | |
160 | |
161 | |
162 const char *Sound_GetError(void) | |
163 { | |
164 return(SDL_GetError()); | |
165 } /* Sound_GetError */ | |
166 | |
167 | |
168 void Sound_ClearError(void) | |
169 { | |
170 SDL_ClearError(); | |
171 } /* Sound_ClearError */ | |
172 | |
173 | |
174 /* | |
175 * This is declared in the internal header. | |
176 */ | |
177 void Sound_SetError(const char *err) | |
178 { | |
179 if (err != NULL) | |
10
cc2c32349380
Some debugging output, and MP3 and VOC entries, added.
Ryan C. Gordon <icculus@icculus.org>
parents:
4
diff
changeset
|
180 { |
cc2c32349380
Some debugging output, and MP3 and VOC entries, added.
Ryan C. Gordon <icculus@icculus.org>
parents:
4
diff
changeset
|
181 _D(("Sound_SetError(\"%s\");\n", err)); |
4 | 182 SDL_SetError(err); |
10
cc2c32349380
Some debugging output, and MP3 and VOC entries, added.
Ryan C. Gordon <icculus@icculus.org>
parents:
4
diff
changeset
|
183 } /* if */ |
4 | 184 } /* Sound_SetError */ |
185 | |
186 | |
187 /* | |
188 * -ansi and -pedantic flags prevent use of strcasecmp() on Linux, and | |
189 * I honestly don't want to mess around with figuring out if a given | |
190 * platform has "strcasecmp", "stricmp", or | |
191 * "compare_two_damned_strings_case_insensitive", which I hear is in the | |
192 * next release of Carbon. :) This is exported so decoders may use it if | |
193 * they like. | |
194 */ | |
195 int __Sound_strcasecmp(const char *x, const char *y) | |
196 { | |
197 int ux, uy; | |
198 | |
199 do | |
200 { | |
201 ux = toupper((int) *x); | |
202 uy = toupper((int) *y); | |
203 if (ux > uy) | |
204 return(1); | |
205 else if (ux < uy) | |
206 return(-1); | |
207 x++; | |
208 y++; | |
209 } while ((ux) && (uy)); | |
210 | |
211 return(0); | |
212 } /* __Sound_strcasecmp */ | |
213 | |
214 | |
215 /* | |
216 * Allocate a Sound_Sample, and fill in most of its fields. Those that need | |
217 * to be filled in later, by a decoder, will be initialized to zero. | |
218 */ | |
219 static Sound_Sample *alloc_sample(SDL_RWops *rw, Sound_AudioInfo *desired, | |
220 Uint32 bufferSize) | |
221 { | |
222 Sound_Sample *retval = malloc(sizeof (Sound_Sample)); | |
223 Sound_SampleInternal *internal = malloc(sizeof (Sound_SampleInternal)); | |
224 if ((retval == NULL) || (internal == NULL)) | |
225 { | |
226 Sound_SetError(ERR_OUT_OF_MEMORY); | |
227 if (retval) | |
228 free(retval); | |
229 if (internal) | |
230 free(internal); | |
231 | |
232 return(NULL); | |
233 } /* if */ | |
234 | |
235 memset(retval, '\0', sizeof (Sound_Sample)); | |
236 memset(internal, '\0', sizeof (Sound_SampleInternal)); | |
237 | |
238 assert(bufferSize > 0); | |
239 retval->buffer = malloc(bufferSize); /* pure ugly. */ | |
240 if (!retval->buffer) | |
241 { | |
242 Sound_SetError(ERR_OUT_OF_MEMORY); | |
243 free(internal); | |
244 free(retval); | |
245 return(NULL); | |
246 } /* if */ | |
247 memset(retval->buffer, '\0', bufferSize); | |
248 retval->buffer_size = bufferSize; | |
249 | |
250 if (desired != NULL) | |
251 memcpy(&retval->desired, desired, sizeof (Sound_AudioInfo)); | |
252 | |
253 internal->rw = rw; | |
254 retval->opaque = internal; | |
255 return(retval); | |
256 } /* alloc_sample */ | |
257 | |
258 | |
10
cc2c32349380
Some debugging output, and MP3 and VOC entries, added.
Ryan C. Gordon <icculus@icculus.org>
parents:
4
diff
changeset
|
259 #if (defined DEBUG_CHATTER) |
cc2c32349380
Some debugging output, and MP3 and VOC entries, added.
Ryan C. Gordon <icculus@icculus.org>
parents:
4
diff
changeset
|
260 static __inline__ const char *fmt_to_str(Uint16 fmt) |
cc2c32349380
Some debugging output, and MP3 and VOC entries, added.
Ryan C. Gordon <icculus@icculus.org>
parents:
4
diff
changeset
|
261 { |
cc2c32349380
Some debugging output, and MP3 and VOC entries, added.
Ryan C. Gordon <icculus@icculus.org>
parents:
4
diff
changeset
|
262 switch(fmt) |
cc2c32349380
Some debugging output, and MP3 and VOC entries, added.
Ryan C. Gordon <icculus@icculus.org>
parents:
4
diff
changeset
|
263 { |
cc2c32349380
Some debugging output, and MP3 and VOC entries, added.
Ryan C. Gordon <icculus@icculus.org>
parents:
4
diff
changeset
|
264 case AUDIO_U8: |
cc2c32349380
Some debugging output, and MP3 and VOC entries, added.
Ryan C. Gordon <icculus@icculus.org>
parents:
4
diff
changeset
|
265 return("U8"); |
cc2c32349380
Some debugging output, and MP3 and VOC entries, added.
Ryan C. Gordon <icculus@icculus.org>
parents:
4
diff
changeset
|
266 case AUDIO_S8: |
cc2c32349380
Some debugging output, and MP3 and VOC entries, added.
Ryan C. Gordon <icculus@icculus.org>
parents:
4
diff
changeset
|
267 return("S8"); |
cc2c32349380
Some debugging output, and MP3 and VOC entries, added.
Ryan C. Gordon <icculus@icculus.org>
parents:
4
diff
changeset
|
268 case AUDIO_U16LSB: |
cc2c32349380
Some debugging output, and MP3 and VOC entries, added.
Ryan C. Gordon <icculus@icculus.org>
parents:
4
diff
changeset
|
269 return("U16LSB"); |
cc2c32349380
Some debugging output, and MP3 and VOC entries, added.
Ryan C. Gordon <icculus@icculus.org>
parents:
4
diff
changeset
|
270 case AUDIO_S16LSB: |
cc2c32349380
Some debugging output, and MP3 and VOC entries, added.
Ryan C. Gordon <icculus@icculus.org>
parents:
4
diff
changeset
|
271 return("S16LSB"); |
cc2c32349380
Some debugging output, and MP3 and VOC entries, added.
Ryan C. Gordon <icculus@icculus.org>
parents:
4
diff
changeset
|
272 case AUDIO_U16MSB: |
cc2c32349380
Some debugging output, and MP3 and VOC entries, added.
Ryan C. Gordon <icculus@icculus.org>
parents:
4
diff
changeset
|
273 return("U16MSB"); |
cc2c32349380
Some debugging output, and MP3 and VOC entries, added.
Ryan C. Gordon <icculus@icculus.org>
parents:
4
diff
changeset
|
274 case AUDIO_S16MSB: |
cc2c32349380
Some debugging output, and MP3 and VOC entries, added.
Ryan C. Gordon <icculus@icculus.org>
parents:
4
diff
changeset
|
275 return("S16MSB"); |
cc2c32349380
Some debugging output, and MP3 and VOC entries, added.
Ryan C. Gordon <icculus@icculus.org>
parents:
4
diff
changeset
|
276 } /* switch */ |
cc2c32349380
Some debugging output, and MP3 and VOC entries, added.
Ryan C. Gordon <icculus@icculus.org>
parents:
4
diff
changeset
|
277 |
cc2c32349380
Some debugging output, and MP3 and VOC entries, added.
Ryan C. Gordon <icculus@icculus.org>
parents:
4
diff
changeset
|
278 return("Unknown"); |
cc2c32349380
Some debugging output, and MP3 and VOC entries, added.
Ryan C. Gordon <icculus@icculus.org>
parents:
4
diff
changeset
|
279 } /* fmt_to_str */ |
cc2c32349380
Some debugging output, and MP3 and VOC entries, added.
Ryan C. Gordon <icculus@icculus.org>
parents:
4
diff
changeset
|
280 #endif |
cc2c32349380
Some debugging output, and MP3 and VOC entries, added.
Ryan C. Gordon <icculus@icculus.org>
parents:
4
diff
changeset
|
281 |
cc2c32349380
Some debugging output, and MP3 and VOC entries, added.
Ryan C. Gordon <icculus@icculus.org>
parents:
4
diff
changeset
|
282 |
4 | 283 /* |
284 * The bulk of the Sound_NewSample() work is done here... | |
285 * Ask the specified decoder to handle the data in (rw), and if | |
286 * so, construct the Sound_Sample. Otherwise, try to wind (rw)'s stream | |
287 * back to where it was, and return false. | |
288 * | |
289 * !!! FIXME: This is big, ugly, nasty, and smelly. | |
290 */ | |
291 static int init_sample(const Sound_DecoderFunctions *funcs, | |
292 Sound_Sample *sample, const char *ext, | |
293 Sound_AudioInfo *_desired) | |
294 { | |
295 Sound_SampleInternal *internal = (Sound_SampleInternal *) sample->opaque; | |
296 int pos = SDL_RWtell(internal->rw); /* !!! FIXME: Int? Really? */ | |
297 Sound_AudioInfo desired; | |
298 | |
299 /* fill in the funcs for this decoder... */ | |
300 sample->decoder = &funcs->info; | |
301 internal->funcs = funcs; | |
302 if (!funcs->open(sample, ext)) | |
303 { | |
304 SDL_RWseek(internal->rw, pos, SEEK_SET); /* set for next try... */ | |
305 return(0); | |
306 } /* if */ | |
307 | |
308 /* success; we've got a decoder! */ | |
309 | |
310 /* Now we need to set up the conversion buffer... */ | |
311 | |
312 memcpy(&desired, (_desired != NULL) ? _desired : &sample->actual, | |
313 sizeof (Sound_AudioInfo)); | |
314 | |
315 if (SDL_BuildAudioCVT(&internal->sdlcvt, | |
316 sample->actual.format, | |
317 sample->actual.channels, | |
318 (int) sample->actual.rate, /* !!! FIXME: Int? Really? */ | |
319 desired.format, | |
320 desired.channels, | |
321 (int) desired.rate) == -1) /* !!! FIXME: Int? Really? */ | |
322 { | |
323 Sound_SetError(SDL_GetError()); | |
324 funcs->close(sample); | |
325 SDL_RWseek(internal->rw, pos, SEEK_SET); /* set for next try... */ | |
326 return(0); | |
327 } /* if */ | |
328 | |
329 if (internal->sdlcvt.len_mult > 1) | |
330 { | |
331 void *rc = realloc(sample->buffer, | |
332 sample->buffer_size * internal->sdlcvt.len_mult); | |
333 if (rc == NULL) | |
334 { | |
335 funcs->close(sample); | |
336 SDL_RWseek(internal->rw, pos, SEEK_SET); /* set for next try... */ | |
337 return(0); | |
338 } /* if */ | |
339 | |
340 sample->buffer = rc; | |
341 } /* if */ | |
342 | |
343 /* these pointers are all one and the same. */ | |
344 memcpy(&sample->desired, &desired, sizeof (Sound_AudioInfo)); | |
345 internal->sdlcvt.buf = internal->buffer = sample->buffer; | |
346 internal->buffer_size = sample->buffer_size / internal->sdlcvt.len_mult; | |
347 internal->sdlcvt.len = internal->buffer_size; | |
348 | |
349 /* Prepend our new Sound_Sample to the samplesList... */ | |
350 if (samplesList != NULL) | |
351 { | |
352 internal->next = samplesList; | |
353 if (samplesList != NULL) | |
354 internal->prev = sample; | |
355 } /* if */ | |
356 samplesList = sample; | |
357 | |
10
cc2c32349380
Some debugging output, and MP3 and VOC entries, added.
Ryan C. Gordon <icculus@icculus.org>
parents:
4
diff
changeset
|
358 _D(("New sample DESIRED format: %s format, %d rate, %d channels.\n", |
cc2c32349380
Some debugging output, and MP3 and VOC entries, added.
Ryan C. Gordon <icculus@icculus.org>
parents:
4
diff
changeset
|
359 fmt_to_str(sample->desired.format), |
cc2c32349380
Some debugging output, and MP3 and VOC entries, added.
Ryan C. Gordon <icculus@icculus.org>
parents:
4
diff
changeset
|
360 sample->desired.rate, |
cc2c32349380
Some debugging output, and MP3 and VOC entries, added.
Ryan C. Gordon <icculus@icculus.org>
parents:
4
diff
changeset
|
361 sample->desired.channels)); |
cc2c32349380
Some debugging output, and MP3 and VOC entries, added.
Ryan C. Gordon <icculus@icculus.org>
parents:
4
diff
changeset
|
362 |
cc2c32349380
Some debugging output, and MP3 and VOC entries, added.
Ryan C. Gordon <icculus@icculus.org>
parents:
4
diff
changeset
|
363 _D(("New sample ACTUAL format: %s format, %d rate, %d channels.\n", |
cc2c32349380
Some debugging output, and MP3 and VOC entries, added.
Ryan C. Gordon <icculus@icculus.org>
parents:
4
diff
changeset
|
364 fmt_to_str(sample->actual.format), |
cc2c32349380
Some debugging output, and MP3 and VOC entries, added.
Ryan C. Gordon <icculus@icculus.org>
parents:
4
diff
changeset
|
365 sample->actual.rate, |
cc2c32349380
Some debugging output, and MP3 and VOC entries, added.
Ryan C. Gordon <icculus@icculus.org>
parents:
4
diff
changeset
|
366 sample->actual.channels)); |
cc2c32349380
Some debugging output, and MP3 and VOC entries, added.
Ryan C. Gordon <icculus@icculus.org>
parents:
4
diff
changeset
|
367 |
cc2c32349380
Some debugging output, and MP3 and VOC entries, added.
Ryan C. Gordon <icculus@icculus.org>
parents:
4
diff
changeset
|
368 _D(("On-the-fly conversion: %s.\n", |
cc2c32349380
Some debugging output, and MP3 and VOC entries, added.
Ryan C. Gordon <icculus@icculus.org>
parents:
4
diff
changeset
|
369 internal->sdlcvt.needed ? "ENABLED" : "DISABLED")); |
cc2c32349380
Some debugging output, and MP3 and VOC entries, added.
Ryan C. Gordon <icculus@icculus.org>
parents:
4
diff
changeset
|
370 |
4 | 371 return(1); |
372 } /* init_sample */ | |
373 | |
374 | |
375 Sound_Sample *Sound_NewSample(SDL_RWops *rw, const char *ext, | |
376 Sound_AudioInfo *desired, Uint32 bSize) | |
377 { | |
378 size_t i; | |
379 Sound_Sample *retval; | |
380 | |
381 /* sanity checks. */ | |
382 BAIL_IF_MACRO(!initialized, ERR_NOT_INITIALIZED, NULL); | |
383 BAIL_IF_MACRO(rw == NULL, ERR_INVALID_ARGUMENT, NULL); | |
384 | |
385 retval = alloc_sample(rw, desired, bSize); | |
386 if (!retval) | |
387 return(NULL); /* alloc_sample() sets error message... */ | |
388 | |
389 if (ext != NULL) | |
390 { | |
391 for (i = 0; decoderFuncs[i] != NULL; i++) | |
392 { | |
393 const char *decoderExt = decoderFuncs[i]->info.extension; | |
394 if (__Sound_strcasecmp(decoderExt, ext) == 0) | |
395 { | |
396 if (init_sample(decoderFuncs[i], retval, ext, desired)) | |
397 return(retval); | |
398 } /* if */ | |
399 } /* for */ | |
400 } /* if */ | |
401 | |
402 /* no direct extension match? Try everything we've got... */ | |
403 for (i = 0; decoderFuncs[i] != NULL; i++) | |
404 { | |
405 if (init_sample(decoderFuncs[i], retval, ext, desired)) | |
406 return(retval); | |
407 } /* for */ | |
408 | |
409 /* nothing could handle the sound data... */ | |
410 free(retval->opaque); | |
411 if (retval->buffer != NULL) | |
412 free(retval->buffer); | |
413 free(retval); | |
414 SDL_RWclose(rw); | |
415 Sound_SetError(ERR_UNSUPPORTED_FORMAT); | |
416 return(NULL); | |
417 } /* Sound_NewSample */ | |
418 | |
419 | |
420 Sound_Sample *Sound_NewSampleFromFile(const char *filename, | |
421 Sound_AudioInfo *desired, | |
422 Uint32 bufferSize) | |
423 { | |
424 const char *ext; | |
425 SDL_RWops *rw; | |
426 | |
427 BAIL_IF_MACRO(!initialized, ERR_NOT_INITIALIZED, NULL); | |
428 BAIL_IF_MACRO(filename == NULL, ERR_INVALID_ARGUMENT, NULL); | |
429 | |
430 ext = strrchr(filename, '.'); | |
431 rw = SDL_RWFromFile(filename, "rb"); | |
432 BAIL_IF_MACRO(rw == NULL, SDL_GetError(), NULL); | |
433 | |
434 if (ext != NULL) | |
435 ext++; | |
436 | |
437 return(Sound_NewSample(rw, ext, desired, bufferSize)); | |
438 } /* Sound_NewSampleFromFile */ | |
439 | |
440 | |
441 void Sound_FreeSample(Sound_Sample *sample) | |
442 { | |
443 Sound_SampleInternal *internal; | |
444 | |
445 if (!initialized) | |
446 { | |
447 Sound_SetError(ERR_NOT_INITIALIZED); | |
448 return; | |
449 } /* if */ | |
450 | |
451 if (sample == NULL) | |
452 { | |
453 Sound_SetError(ERR_INVALID_ARGUMENT); | |
454 return; | |
455 } /* if */ | |
456 | |
457 internal = (Sound_SampleInternal *) sample->opaque; | |
458 | |
459 internal->funcs->close(sample); | |
460 | |
461 /* update the samplesList... */ | |
462 if (internal->prev != NULL) | |
463 { | |
464 Sound_SampleInternal *prevInternal; | |
465 prevInternal = (Sound_SampleInternal *) internal->prev->opaque; | |
466 prevInternal->next = internal->next; | |
467 } /* if */ | |
468 else | |
469 { | |
470 assert(samplesList == sample); | |
471 samplesList = internal->next; | |
472 } /* else */ | |
473 | |
474 if (internal->next != NULL) | |
475 { | |
476 Sound_SampleInternal *nextInternal; | |
477 nextInternal = (Sound_SampleInternal *) internal->next->opaque; | |
478 nextInternal->prev = internal->prev; | |
479 } /* if */ | |
480 | |
481 /* nuke it... */ | |
482 if (internal->rw != NULL) /* this condition is a "just in case" thing. */ | |
483 SDL_RWclose(internal->rw); | |
484 assert(internal->buffer != NULL); | |
485 if (internal->buffer != sample->buffer) | |
486 free(internal->buffer); | |
487 free(internal); | |
488 if (sample->buffer != NULL) | |
489 free(sample->buffer); | |
490 free(sample); | |
491 } /* Sound_FreeSample */ | |
492 | |
493 | |
494 int Sound_SetBufferSize(Sound_Sample *sample, Uint32 newSize) | |
495 { | |
496 void *newBuf = NULL; | |
497 Sound_SampleInternal *internal = NULL; | |
498 | |
499 BAIL_IF_MACRO(!initialized, ERR_NOT_INITIALIZED, 0); | |
500 BAIL_IF_MACRO(sample == NULL, ERR_INVALID_ARGUMENT, 0); | |
501 internal = ((Sound_SampleInternal *) sample->opaque); | |
502 newBuf = realloc(sample->buffer, newSize * internal->sdlcvt.len_mult); | |
503 BAIL_IF_MACRO(newBuf == NULL, ERR_OUT_OF_MEMORY, 0); | |
504 | |
505 internal->sdlcvt.buf = internal->buffer = sample->buffer = newBuf; | |
506 sample->buffer_size = newSize; | |
507 internal->buffer_size = newSize / internal->sdlcvt.len_mult; | |
508 internal->sdlcvt.len = internal->buffer_size; | |
509 | |
510 return(1); | |
511 } /* Sound_SetBufferSize */ | |
512 | |
513 | |
514 Uint32 Sound_Decode(Sound_Sample *sample) | |
515 { | |
516 Sound_SampleInternal *internal = NULL; | |
517 Uint32 retval = 0; | |
518 | |
519 /* a boatload of sanity checks... */ | |
520 BAIL_IF_MACRO(!initialized, ERR_NOT_INITIALIZED, 0); | |
521 BAIL_IF_MACRO(sample == NULL, ERR_INVALID_ARGUMENT, 0); | |
522 BAIL_IF_MACRO(sample->flags & SOUND_SAMPLEFLAG_ERROR, ERR_PREV_ERROR, 0); | |
523 BAIL_IF_MACRO(sample->flags & SOUND_SAMPLEFLAG_EOF, ERR_PREV_EOF, 0); | |
524 | |
525 internal = (Sound_SampleInternal *) sample->opaque; | |
526 | |
527 assert(sample->buffer != NULL); | |
528 assert(sample->buffer_size > 0); | |
529 assert(internal->buffer != NULL); | |
530 assert(internal->buffer_size > 0); | |
531 | |
532 /* reset EAGAIN. Decoder can flip it back on if it needs to. */ | |
533 sample->flags &= !SOUND_SAMPLEFLAG_EAGAIN; | |
534 | |
535 retval = internal->funcs->read(sample); | |
536 if (internal->sdlcvt.needed) | |
537 { | |
538 internal->sdlcvt.len = retval; | |
539 SDL_ConvertAudio(&internal->sdlcvt); | |
540 retval *= internal->sdlcvt.len_mult; | |
541 } /* if */ | |
542 | |
543 return(retval); | |
544 } /* Sound_Decode */ | |
545 | |
546 | |
547 Uint32 Sound_DecodeAll(Sound_Sample *sample) | |
548 { | |
549 Sound_SampleInternal *internal = NULL; | |
550 void *buf = NULL; | |
551 Uint32 newBufSize = 0; | |
552 | |
553 BAIL_IF_MACRO(!initialized, ERR_NOT_INITIALIZED, 0); | |
554 | |
555 internal = (Sound_SampleInternal *) sample->opaque; | |
556 | |
557 while ( ((sample->flags & SOUND_SAMPLEFLAG_EOF) == 0) && | |
558 ((sample->flags & SOUND_SAMPLEFLAG_ERROR) == 0) ) | |
559 { | |
560 void *ptr = realloc(buf, newBufSize + sample->buffer_size); | |
561 if (ptr == NULL) | |
562 { | |
563 sample->flags |= SOUND_SAMPLEFLAG_ERROR; | |
564 Sound_SetError(ERR_OUT_OF_MEMORY); | |
565 } /* if */ | |
566 else | |
567 { | |
568 Uint32 br = Sound_Decode(sample); | |
569 memcpy( ((char *) buf) + newBufSize, sample->buffer, br ); | |
570 newBufSize += br; | |
571 } /* else */ | |
572 } /* while */ | |
573 | |
574 free(sample->buffer); | |
575 sample->buffer = internal->buffer = internal->sdlcvt.buf = buf; | |
576 sample->buffer_size = newBufSize; | |
577 internal->buffer_size = newBufSize / internal->sdlcvt.len_mult; | |
578 internal->sdlcvt.len_mult = internal->buffer_size; | |
579 | |
580 return(newBufSize); | |
581 } /* Sound_DecodeAll */ | |
582 | |
583 | |
584 /* end of SDL_sound.c ... */ | |
585 |