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