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