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