Mercurial > sdl-ios-xcode
annotate src/audio/SDL_wave.c @ 4001:6831b8723a85 SDL-1.2
Don't initialize the audio buffer passed to the application's audio callback,
since they are expected to entirely fill it with data or silence.
For legacy apps that might expect the buffer to already have silence and thus
may not fill the buffer in the callback, there's an environment variable to
expose the old behaviour.
Fixes Bugzilla #416.
author | Ryan C. Gordon <icculus@icculus.org> |
---|---|
date | Thu, 05 Jul 2007 02:24:36 +0000 |
parents | 7995cc87b777 |
children | 782fd950bd46 c121d94672cb 96ce26f24b01 |
rev | line source |
---|---|
0 | 1 /* |
2 SDL - Simple DirectMedia Layer | |
1312
c9b51268668f
Updated copyright information and removed rcs id lines (problematic in branch merges)
Sam Lantinga <slouken@libsdl.org>
parents:
1260
diff
changeset
|
3 Copyright (C) 1997-2006 Sam Lantinga |
0 | 4 |
5 This library is free software; you can redistribute it and/or | |
1312
c9b51268668f
Updated copyright information and removed rcs id lines (problematic in branch merges)
Sam Lantinga <slouken@libsdl.org>
parents:
1260
diff
changeset
|
6 modify it under the terms of the GNU Lesser General Public |
0 | 7 License as published by the Free Software Foundation; either |
1312
c9b51268668f
Updated copyright information and removed rcs id lines (problematic in branch merges)
Sam Lantinga <slouken@libsdl.org>
parents:
1260
diff
changeset
|
8 version 2.1 of the License, or (at your option) any later version. |
0 | 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 | |
1312
c9b51268668f
Updated copyright information and removed rcs id lines (problematic in branch merges)
Sam Lantinga <slouken@libsdl.org>
parents:
1260
diff
changeset
|
13 Lesser General Public License for more details. |
0 | 14 |
1312
c9b51268668f
Updated copyright information and removed rcs id lines (problematic in branch merges)
Sam Lantinga <slouken@libsdl.org>
parents:
1260
diff
changeset
|
15 You should have received a copy of the GNU Lesser General Public |
c9b51268668f
Updated copyright information and removed rcs id lines (problematic in branch merges)
Sam Lantinga <slouken@libsdl.org>
parents:
1260
diff
changeset
|
16 License along with this library; if not, write to the Free Software |
c9b51268668f
Updated copyright information and removed rcs id lines (problematic in branch merges)
Sam Lantinga <slouken@libsdl.org>
parents:
1260
diff
changeset
|
17 Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA |
0 | 18 |
19 Sam Lantinga | |
252
e8157fcb3114
Updated the source with the correct e-mail address
Sam Lantinga <slouken@libsdl.org>
parents:
171
diff
changeset
|
20 slouken@libsdl.org |
0 | 21 */ |
1402
d910939febfa
Use consistent identifiers for the various platforms we support.
Sam Lantinga <slouken@libsdl.org>
parents:
1361
diff
changeset
|
22 #include "SDL_config.h" |
0 | 23 |
24 /* Microsoft WAVE file loading routines */ | |
25 | |
26 #include "SDL_audio.h" | |
27 #include "SDL_wave.h" | |
28 | |
29 | |
30 static int ReadChunk(SDL_RWops *src, Chunk *chunk); | |
31 | |
32 struct MS_ADPCM_decodestate { | |
33 Uint8 hPredictor; | |
34 Uint16 iDelta; | |
35 Sint16 iSamp1; | |
36 Sint16 iSamp2; | |
37 }; | |
38 static struct MS_ADPCM_decoder { | |
39 WaveFMT wavefmt; | |
40 Uint16 wSamplesPerBlock; | |
41 Uint16 wNumCoef; | |
42 Sint16 aCoeff[7][2]; | |
43 /* * * */ | |
44 struct MS_ADPCM_decodestate state[2]; | |
45 } MS_ADPCM_state; | |
46 | |
47 static int InitMS_ADPCM(WaveFMT *format) | |
48 { | |
49 Uint8 *rogue_feel; | |
50 Uint16 extra_info; | |
51 int i; | |
52 | |
53 /* Set the rogue pointer to the MS_ADPCM specific data */ | |
54 MS_ADPCM_state.wavefmt.encoding = SDL_SwapLE16(format->encoding); | |
55 MS_ADPCM_state.wavefmt.channels = SDL_SwapLE16(format->channels); | |
56 MS_ADPCM_state.wavefmt.frequency = SDL_SwapLE32(format->frequency); | |
57 MS_ADPCM_state.wavefmt.byterate = SDL_SwapLE32(format->byterate); | |
58 MS_ADPCM_state.wavefmt.blockalign = SDL_SwapLE16(format->blockalign); | |
59 MS_ADPCM_state.wavefmt.bitspersample = | |
60 SDL_SwapLE16(format->bitspersample); | |
61 rogue_feel = (Uint8 *)format+sizeof(*format); | |
62 if ( sizeof(*format) == 16 ) { | |
63 extra_info = ((rogue_feel[1]<<8)|rogue_feel[0]); | |
64 rogue_feel += sizeof(Uint16); | |
65 } | |
66 MS_ADPCM_state.wSamplesPerBlock = ((rogue_feel[1]<<8)|rogue_feel[0]); | |
67 rogue_feel += sizeof(Uint16); | |
68 MS_ADPCM_state.wNumCoef = ((rogue_feel[1]<<8)|rogue_feel[0]); | |
69 rogue_feel += sizeof(Uint16); | |
70 if ( MS_ADPCM_state.wNumCoef != 7 ) { | |
71 SDL_SetError("Unknown set of MS_ADPCM coefficients"); | |
72 return(-1); | |
73 } | |
74 for ( i=0; i<MS_ADPCM_state.wNumCoef; ++i ) { | |
75 MS_ADPCM_state.aCoeff[i][0] = ((rogue_feel[1]<<8)|rogue_feel[0]); | |
76 rogue_feel += sizeof(Uint16); | |
77 MS_ADPCM_state.aCoeff[i][1] = ((rogue_feel[1]<<8)|rogue_feel[0]); | |
78 rogue_feel += sizeof(Uint16); | |
79 } | |
80 return(0); | |
81 } | |
82 | |
83 static Sint32 MS_ADPCM_nibble(struct MS_ADPCM_decodestate *state, | |
84 Uint8 nybble, Sint16 *coeff) | |
85 { | |
86 const Sint32 max_audioval = ((1<<(16-1))-1); | |
87 const Sint32 min_audioval = -(1<<(16-1)); | |
88 const Sint32 adaptive[] = { | |
89 230, 230, 230, 230, 307, 409, 512, 614, | |
90 768, 614, 512, 409, 307, 230, 230, 230 | |
91 }; | |
92 Sint32 new_sample, delta; | |
93 | |
94 new_sample = ((state->iSamp1 * coeff[0]) + | |
95 (state->iSamp2 * coeff[1]))/256; | |
96 if ( nybble & 0x08 ) { | |
97 new_sample += state->iDelta * (nybble-0x10); | |
98 } else { | |
99 new_sample += state->iDelta * nybble; | |
100 } | |
101 if ( new_sample < min_audioval ) { | |
102 new_sample = min_audioval; | |
103 } else | |
104 if ( new_sample > max_audioval ) { | |
105 new_sample = max_audioval; | |
106 } | |
107 delta = ((Sint32)state->iDelta * adaptive[nybble])/256; | |
108 if ( delta < 16 ) { | |
109 delta = 16; | |
110 } | |
1428
5f52867ba65c
Update for Visual C++ 6.0
Sam Lantinga <slouken@libsdl.org>
parents:
1402
diff
changeset
|
111 state->iDelta = (Uint16)delta; |
0 | 112 state->iSamp2 = state->iSamp1; |
1428
5f52867ba65c
Update for Visual C++ 6.0
Sam Lantinga <slouken@libsdl.org>
parents:
1402
diff
changeset
|
113 state->iSamp1 = (Sint16)new_sample; |
0 | 114 return(new_sample); |
115 } | |
116 | |
117 static int MS_ADPCM_decode(Uint8 **audio_buf, Uint32 *audio_len) | |
118 { | |
119 struct MS_ADPCM_decodestate *state[2]; | |
120 Uint8 *freeable, *encoded, *decoded; | |
121 Sint32 encoded_len, samplesleft; | |
122 Sint8 nybble, stereo; | |
123 Sint16 *coeff[2]; | |
124 Sint32 new_sample; | |
125 | |
126 /* Allocate the proper sized output buffer */ | |
127 encoded_len = *audio_len; | |
128 encoded = *audio_buf; | |
129 freeable = *audio_buf; | |
130 *audio_len = (encoded_len/MS_ADPCM_state.wavefmt.blockalign) * | |
131 MS_ADPCM_state.wSamplesPerBlock* | |
132 MS_ADPCM_state.wavefmt.channels*sizeof(Sint16); | |
1336
3692456e7b0f
Use SDL_ prefixed versions of C library functions.
Sam Lantinga <slouken@libsdl.org>
parents:
1330
diff
changeset
|
133 *audio_buf = (Uint8 *)SDL_malloc(*audio_len); |
0 | 134 if ( *audio_buf == NULL ) { |
135 SDL_Error(SDL_ENOMEM); | |
136 return(-1); | |
137 } | |
138 decoded = *audio_buf; | |
139 | |
140 /* Get ready... Go! */ | |
141 stereo = (MS_ADPCM_state.wavefmt.channels == 2); | |
142 state[0] = &MS_ADPCM_state.state[0]; | |
143 state[1] = &MS_ADPCM_state.state[stereo]; | |
144 while ( encoded_len >= MS_ADPCM_state.wavefmt.blockalign ) { | |
145 /* Grab the initial information for this block */ | |
146 state[0]->hPredictor = *encoded++; | |
147 if ( stereo ) { | |
148 state[1]->hPredictor = *encoded++; | |
149 } | |
150 state[0]->iDelta = ((encoded[1]<<8)|encoded[0]); | |
151 encoded += sizeof(Sint16); | |
152 if ( stereo ) { | |
153 state[1]->iDelta = ((encoded[1]<<8)|encoded[0]); | |
154 encoded += sizeof(Sint16); | |
155 } | |
156 state[0]->iSamp1 = ((encoded[1]<<8)|encoded[0]); | |
157 encoded += sizeof(Sint16); | |
158 if ( stereo ) { | |
159 state[1]->iSamp1 = ((encoded[1]<<8)|encoded[0]); | |
160 encoded += sizeof(Sint16); | |
161 } | |
162 state[0]->iSamp2 = ((encoded[1]<<8)|encoded[0]); | |
163 encoded += sizeof(Sint16); | |
164 if ( stereo ) { | |
165 state[1]->iSamp2 = ((encoded[1]<<8)|encoded[0]); | |
166 encoded += sizeof(Sint16); | |
167 } | |
168 coeff[0] = MS_ADPCM_state.aCoeff[state[0]->hPredictor]; | |
169 coeff[1] = MS_ADPCM_state.aCoeff[state[1]->hPredictor]; | |
170 | |
171 /* Store the two initial samples we start with */ | |
172 decoded[0] = state[0]->iSamp2&0xFF; | |
173 decoded[1] = state[0]->iSamp2>>8; | |
174 decoded += 2; | |
175 if ( stereo ) { | |
176 decoded[0] = state[1]->iSamp2&0xFF; | |
177 decoded[1] = state[1]->iSamp2>>8; | |
178 decoded += 2; | |
179 } | |
180 decoded[0] = state[0]->iSamp1&0xFF; | |
181 decoded[1] = state[0]->iSamp1>>8; | |
182 decoded += 2; | |
183 if ( stereo ) { | |
184 decoded[0] = state[1]->iSamp1&0xFF; | |
185 decoded[1] = state[1]->iSamp1>>8; | |
186 decoded += 2; | |
187 } | |
188 | |
189 /* Decode and store the other samples in this block */ | |
190 samplesleft = (MS_ADPCM_state.wSamplesPerBlock-2)* | |
191 MS_ADPCM_state.wavefmt.channels; | |
192 while ( samplesleft > 0 ) { | |
193 nybble = (*encoded)>>4; | |
194 new_sample = MS_ADPCM_nibble(state[0],nybble,coeff[0]); | |
195 decoded[0] = new_sample&0xFF; | |
196 new_sample >>= 8; | |
197 decoded[1] = new_sample&0xFF; | |
198 decoded += 2; | |
199 | |
200 nybble = (*encoded)&0x0F; | |
201 new_sample = MS_ADPCM_nibble(state[1],nybble,coeff[1]); | |
202 decoded[0] = new_sample&0xFF; | |
203 new_sample >>= 8; | |
204 decoded[1] = new_sample&0xFF; | |
205 decoded += 2; | |
206 | |
207 ++encoded; | |
208 samplesleft -= 2; | |
209 } | |
210 encoded_len -= MS_ADPCM_state.wavefmt.blockalign; | |
211 } | |
1336
3692456e7b0f
Use SDL_ prefixed versions of C library functions.
Sam Lantinga <slouken@libsdl.org>
parents:
1330
diff
changeset
|
212 SDL_free(freeable); |
0 | 213 return(0); |
214 } | |
215 | |
216 struct IMA_ADPCM_decodestate { | |
217 Sint32 sample; | |
218 Sint8 index; | |
219 }; | |
220 static struct IMA_ADPCM_decoder { | |
221 WaveFMT wavefmt; | |
222 Uint16 wSamplesPerBlock; | |
223 /* * * */ | |
224 struct IMA_ADPCM_decodestate state[2]; | |
225 } IMA_ADPCM_state; | |
226 | |
227 static int InitIMA_ADPCM(WaveFMT *format) | |
228 { | |
229 Uint8 *rogue_feel; | |
230 Uint16 extra_info; | |
231 | |
232 /* Set the rogue pointer to the IMA_ADPCM specific data */ | |
233 IMA_ADPCM_state.wavefmt.encoding = SDL_SwapLE16(format->encoding); | |
234 IMA_ADPCM_state.wavefmt.channels = SDL_SwapLE16(format->channels); | |
235 IMA_ADPCM_state.wavefmt.frequency = SDL_SwapLE32(format->frequency); | |
236 IMA_ADPCM_state.wavefmt.byterate = SDL_SwapLE32(format->byterate); | |
237 IMA_ADPCM_state.wavefmt.blockalign = SDL_SwapLE16(format->blockalign); | |
238 IMA_ADPCM_state.wavefmt.bitspersample = | |
239 SDL_SwapLE16(format->bitspersample); | |
240 rogue_feel = (Uint8 *)format+sizeof(*format); | |
241 if ( sizeof(*format) == 16 ) { | |
242 extra_info = ((rogue_feel[1]<<8)|rogue_feel[0]); | |
243 rogue_feel += sizeof(Uint16); | |
244 } | |
245 IMA_ADPCM_state.wSamplesPerBlock = ((rogue_feel[1]<<8)|rogue_feel[0]); | |
246 return(0); | |
247 } | |
248 | |
249 static Sint32 IMA_ADPCM_nibble(struct IMA_ADPCM_decodestate *state,Uint8 nybble) | |
250 { | |
251 const Sint32 max_audioval = ((1<<(16-1))-1); | |
252 const Sint32 min_audioval = -(1<<(16-1)); | |
253 const int index_table[16] = { | |
254 -1, -1, -1, -1, | |
255 2, 4, 6, 8, | |
256 -1, -1, -1, -1, | |
257 2, 4, 6, 8 | |
258 }; | |
259 const Sint32 step_table[89] = { | |
260 7, 8, 9, 10, 11, 12, 13, 14, 16, 17, 19, 21, 23, 25, 28, 31, | |
261 34, 37, 41, 45, 50, 55, 60, 66, 73, 80, 88, 97, 107, 118, 130, | |
262 143, 157, 173, 190, 209, 230, 253, 279, 307, 337, 371, 408, | |
263 449, 494, 544, 598, 658, 724, 796, 876, 963, 1060, 1166, 1282, | |
264 1411, 1552, 1707, 1878, 2066, 2272, 2499, 2749, 3024, 3327, | |
265 3660, 4026, 4428, 4871, 5358, 5894, 6484, 7132, 7845, 8630, | |
266 9493, 10442, 11487, 12635, 13899, 15289, 16818, 18500, 20350, | |
267 22385, 24623, 27086, 29794, 32767 | |
268 }; | |
269 Sint32 delta, step; | |
270 | |
271 /* Compute difference and new sample value */ | |
272 step = step_table[state->index]; | |
273 delta = step >> 3; | |
274 if ( nybble & 0x04 ) delta += step; | |
275 if ( nybble & 0x02 ) delta += (step >> 1); | |
276 if ( nybble & 0x01 ) delta += (step >> 2); | |
277 if ( nybble & 0x08 ) delta = -delta; | |
278 state->sample += delta; | |
279 | |
280 /* Update index value */ | |
281 state->index += index_table[nybble]; | |
282 if ( state->index > 88 ) { | |
283 state->index = 88; | |
284 } else | |
285 if ( state->index < 0 ) { | |
286 state->index = 0; | |
287 } | |
288 | |
289 /* Clamp output sample */ | |
290 if ( state->sample > max_audioval ) { | |
291 state->sample = max_audioval; | |
292 } else | |
293 if ( state->sample < min_audioval ) { | |
294 state->sample = min_audioval; | |
295 } | |
296 return(state->sample); | |
297 } | |
298 | |
299 /* Fill the decode buffer with a channel block of data (8 samples) */ | |
300 static void Fill_IMA_ADPCM_block(Uint8 *decoded, Uint8 *encoded, | |
301 int channel, int numchannels, struct IMA_ADPCM_decodestate *state) | |
302 { | |
303 int i; | |
304 Sint8 nybble; | |
305 Sint32 new_sample; | |
306 | |
307 decoded += (channel * 2); | |
308 for ( i=0; i<4; ++i ) { | |
309 nybble = (*encoded)&0x0F; | |
310 new_sample = IMA_ADPCM_nibble(state, nybble); | |
311 decoded[0] = new_sample&0xFF; | |
312 new_sample >>= 8; | |
313 decoded[1] = new_sample&0xFF; | |
314 decoded += 2 * numchannels; | |
315 | |
316 nybble = (*encoded)>>4; | |
317 new_sample = IMA_ADPCM_nibble(state, nybble); | |
318 decoded[0] = new_sample&0xFF; | |
319 new_sample >>= 8; | |
320 decoded[1] = new_sample&0xFF; | |
321 decoded += 2 * numchannels; | |
322 | |
323 ++encoded; | |
324 } | |
325 } | |
326 | |
327 static int IMA_ADPCM_decode(Uint8 **audio_buf, Uint32 *audio_len) | |
328 { | |
329 struct IMA_ADPCM_decodestate *state; | |
330 Uint8 *freeable, *encoded, *decoded; | |
331 Sint32 encoded_len, samplesleft; | |
1612
97d0966f4bf7
Fixed some ultra-pedantic gcc warnings
Sam Lantinga <slouken@libsdl.org>
parents:
1487
diff
changeset
|
332 unsigned int c, channels; |
0 | 333 |
334 /* Check to make sure we have enough variables in the state array */ | |
335 channels = IMA_ADPCM_state.wavefmt.channels; | |
1330
450721ad5436
It's now possible to build SDL without any C runtime at all on Windows,
Sam Lantinga <slouken@libsdl.org>
parents:
1312
diff
changeset
|
336 if ( channels > SDL_arraysize(IMA_ADPCM_state.state) ) { |
0 | 337 SDL_SetError("IMA ADPCM decoder can only handle %d channels", |
1330
450721ad5436
It's now possible to build SDL without any C runtime at all on Windows,
Sam Lantinga <slouken@libsdl.org>
parents:
1312
diff
changeset
|
338 SDL_arraysize(IMA_ADPCM_state.state)); |
0 | 339 return(-1); |
340 } | |
341 state = IMA_ADPCM_state.state; | |
342 | |
343 /* Allocate the proper sized output buffer */ | |
344 encoded_len = *audio_len; | |
345 encoded = *audio_buf; | |
346 freeable = *audio_buf; | |
347 *audio_len = (encoded_len/IMA_ADPCM_state.wavefmt.blockalign) * | |
348 IMA_ADPCM_state.wSamplesPerBlock* | |
349 IMA_ADPCM_state.wavefmt.channels*sizeof(Sint16); | |
1336
3692456e7b0f
Use SDL_ prefixed versions of C library functions.
Sam Lantinga <slouken@libsdl.org>
parents:
1330
diff
changeset
|
350 *audio_buf = (Uint8 *)SDL_malloc(*audio_len); |
0 | 351 if ( *audio_buf == NULL ) { |
352 SDL_Error(SDL_ENOMEM); | |
353 return(-1); | |
354 } | |
355 decoded = *audio_buf; | |
356 | |
357 /* Get ready... Go! */ | |
358 while ( encoded_len >= IMA_ADPCM_state.wavefmt.blockalign ) { | |
359 /* Grab the initial information for this block */ | |
360 for ( c=0; c<channels; ++c ) { | |
361 /* Fill the state information for this block */ | |
362 state[c].sample = ((encoded[1]<<8)|encoded[0]); | |
363 encoded += 2; | |
364 if ( state[c].sample & 0x8000 ) { | |
365 state[c].sample -= 0x10000; | |
366 } | |
367 state[c].index = *encoded++; | |
368 /* Reserved byte in buffer header, should be 0 */ | |
369 if ( *encoded++ != 0 ) { | |
370 /* Uh oh, corrupt data? Buggy code? */; | |
371 } | |
372 | |
373 /* Store the initial sample we start with */ | |
1428
5f52867ba65c
Update for Visual C++ 6.0
Sam Lantinga <slouken@libsdl.org>
parents:
1402
diff
changeset
|
374 decoded[0] = (Uint8)(state[c].sample&0xFF); |
5f52867ba65c
Update for Visual C++ 6.0
Sam Lantinga <slouken@libsdl.org>
parents:
1402
diff
changeset
|
375 decoded[1] = (Uint8)(state[c].sample>>8); |
0 | 376 decoded += 2; |
377 } | |
378 | |
379 /* Decode and store the other samples in this block */ | |
380 samplesleft = (IMA_ADPCM_state.wSamplesPerBlock-1)*channels; | |
381 while ( samplesleft > 0 ) { | |
382 for ( c=0; c<channels; ++c ) { | |
383 Fill_IMA_ADPCM_block(decoded, encoded, | |
384 c, channels, &state[c]); | |
385 encoded += 4; | |
386 samplesleft -= 8; | |
387 } | |
388 decoded += (channels * 8 * 2); | |
389 } | |
390 encoded_len -= IMA_ADPCM_state.wavefmt.blockalign; | |
391 } | |
1336
3692456e7b0f
Use SDL_ prefixed versions of C library functions.
Sam Lantinga <slouken@libsdl.org>
parents:
1330
diff
changeset
|
392 SDL_free(freeable); |
0 | 393 return(0); |
394 } | |
395 | |
396 SDL_AudioSpec * SDL_LoadWAV_RW (SDL_RWops *src, int freesrc, | |
397 SDL_AudioSpec *spec, Uint8 **audio_buf, Uint32 *audio_len) | |
398 { | |
399 int was_error; | |
400 Chunk chunk; | |
401 int lenread; | |
402 int MS_ADPCM_encoded, IMA_ADPCM_encoded; | |
403 int samplesize; | |
404 | |
405 /* WAV magic header */ | |
406 Uint32 RIFFchunk; | |
1260
80f8c94b5199
Date: 10 Jun 2003 15:30:59 -0400
Sam Lantinga <slouken@libsdl.org>
parents:
769
diff
changeset
|
407 Uint32 wavelen = 0; |
0 | 408 Uint32 WAVEmagic; |
1260
80f8c94b5199
Date: 10 Jun 2003 15:30:59 -0400
Sam Lantinga <slouken@libsdl.org>
parents:
769
diff
changeset
|
409 Uint32 headerDiff = 0; |
0 | 410 |
411 /* FMT chunk */ | |
412 WaveFMT *format = NULL; | |
413 | |
414 /* Make sure we are passed a valid data source */ | |
415 was_error = 0; | |
416 if ( src == NULL ) { | |
417 was_error = 1; | |
418 goto done; | |
419 } | |
420 | |
421 /* Check the magic header */ | |
422 RIFFchunk = SDL_ReadLE32(src); | |
423 wavelen = SDL_ReadLE32(src); | |
171
02e27b705645
Handle the case where the WAVE magic number was already read in a non-seekable
Sam Lantinga <slouken@libsdl.org>
parents:
0
diff
changeset
|
424 if ( wavelen == WAVE ) { /* The RIFFchunk has already been read */ |
02e27b705645
Handle the case where the WAVE magic number was already read in a non-seekable
Sam Lantinga <slouken@libsdl.org>
parents:
0
diff
changeset
|
425 WAVEmagic = wavelen; |
02e27b705645
Handle the case where the WAVE magic number was already read in a non-seekable
Sam Lantinga <slouken@libsdl.org>
parents:
0
diff
changeset
|
426 wavelen = RIFFchunk; |
02e27b705645
Handle the case where the WAVE magic number was already read in a non-seekable
Sam Lantinga <slouken@libsdl.org>
parents:
0
diff
changeset
|
427 RIFFchunk = RIFF; |
02e27b705645
Handle the case where the WAVE magic number was already read in a non-seekable
Sam Lantinga <slouken@libsdl.org>
parents:
0
diff
changeset
|
428 } else { |
02e27b705645
Handle the case where the WAVE magic number was already read in a non-seekable
Sam Lantinga <slouken@libsdl.org>
parents:
0
diff
changeset
|
429 WAVEmagic = SDL_ReadLE32(src); |
02e27b705645
Handle the case where the WAVE magic number was already read in a non-seekable
Sam Lantinga <slouken@libsdl.org>
parents:
0
diff
changeset
|
430 } |
0 | 431 if ( (RIFFchunk != RIFF) || (WAVEmagic != WAVE) ) { |
432 SDL_SetError("Unrecognized file type (not WAVE)"); | |
433 was_error = 1; | |
434 goto done; | |
435 } | |
1487
dc6b59e925a2
Cleaning up warnings on MacOS X
Sam Lantinga <slouken@libsdl.org>
parents:
1465
diff
changeset
|
436 headerDiff += sizeof(Uint32); /* for WAVE */ |
0 | 437 |
438 /* Read the audio data format chunk */ | |
439 chunk.data = NULL; | |
440 do { | |
441 if ( chunk.data != NULL ) { | |
1336
3692456e7b0f
Use SDL_ prefixed versions of C library functions.
Sam Lantinga <slouken@libsdl.org>
parents:
1330
diff
changeset
|
442 SDL_free(chunk.data); |
0 | 443 } |
444 lenread = ReadChunk(src, &chunk); | |
445 if ( lenread < 0 ) { | |
446 was_error = 1; | |
447 goto done; | |
448 } | |
1487
dc6b59e925a2
Cleaning up warnings on MacOS X
Sam Lantinga <slouken@libsdl.org>
parents:
1465
diff
changeset
|
449 /* 2 Uint32's for chunk header+len, plus the lenread */ |
1260
80f8c94b5199
Date: 10 Jun 2003 15:30:59 -0400
Sam Lantinga <slouken@libsdl.org>
parents:
769
diff
changeset
|
450 headerDiff += lenread + 2 * sizeof(Uint32); |
0 | 451 } while ( (chunk.magic == FACT) || (chunk.magic == LIST) ); |
452 | |
453 /* Decode the audio data format */ | |
454 format = (WaveFMT *)chunk.data; | |
455 if ( chunk.magic != FMT ) { | |
456 SDL_SetError("Complex WAVE files not supported"); | |
457 was_error = 1; | |
458 goto done; | |
459 } | |
460 MS_ADPCM_encoded = IMA_ADPCM_encoded = 0; | |
461 switch (SDL_SwapLE16(format->encoding)) { | |
462 case PCM_CODE: | |
463 /* We can understand this */ | |
464 break; | |
465 case MS_ADPCM_CODE: | |
466 /* Try to understand this */ | |
467 if ( InitMS_ADPCM(format) < 0 ) { | |
468 was_error = 1; | |
469 goto done; | |
470 } | |
471 MS_ADPCM_encoded = 1; | |
472 break; | |
473 case IMA_ADPCM_CODE: | |
474 /* Try to understand this */ | |
475 if ( InitIMA_ADPCM(format) < 0 ) { | |
476 was_error = 1; | |
477 goto done; | |
478 } | |
479 IMA_ADPCM_encoded = 1; | |
480 break; | |
1818
7995cc87b777
Fixed some bugs in string handling
Sam Lantinga <slouken@libsdl.org>
parents:
1612
diff
changeset
|
481 case MP3_CODE: |
7995cc87b777
Fixed some bugs in string handling
Sam Lantinga <slouken@libsdl.org>
parents:
1612
diff
changeset
|
482 SDL_SetError("MPEG Layer 3 data not supported", |
7995cc87b777
Fixed some bugs in string handling
Sam Lantinga <slouken@libsdl.org>
parents:
1612
diff
changeset
|
483 SDL_SwapLE16(format->encoding)); |
7995cc87b777
Fixed some bugs in string handling
Sam Lantinga <slouken@libsdl.org>
parents:
1612
diff
changeset
|
484 was_error = 1; |
7995cc87b777
Fixed some bugs in string handling
Sam Lantinga <slouken@libsdl.org>
parents:
1612
diff
changeset
|
485 goto done; |
0 | 486 default: |
487 SDL_SetError("Unknown WAVE data format: 0x%.4x", | |
488 SDL_SwapLE16(format->encoding)); | |
489 was_error = 1; | |
490 goto done; | |
491 } | |
1336
3692456e7b0f
Use SDL_ prefixed versions of C library functions.
Sam Lantinga <slouken@libsdl.org>
parents:
1330
diff
changeset
|
492 SDL_memset(spec, 0, (sizeof *spec)); |
0 | 493 spec->freq = SDL_SwapLE32(format->frequency); |
494 switch (SDL_SwapLE16(format->bitspersample)) { | |
495 case 4: | |
496 if ( MS_ADPCM_encoded || IMA_ADPCM_encoded ) { | |
497 spec->format = AUDIO_S16; | |
498 } else { | |
499 was_error = 1; | |
500 } | |
501 break; | |
502 case 8: | |
503 spec->format = AUDIO_U8; | |
504 break; | |
505 case 16: | |
506 spec->format = AUDIO_S16; | |
507 break; | |
508 default: | |
509 was_error = 1; | |
510 break; | |
511 } | |
512 if ( was_error ) { | |
513 SDL_SetError("Unknown %d-bit PCM data format", | |
514 SDL_SwapLE16(format->bitspersample)); | |
515 goto done; | |
516 } | |
517 spec->channels = (Uint8)SDL_SwapLE16(format->channels); | |
518 spec->samples = 4096; /* Good default buffer size */ | |
519 | |
520 /* Read the audio data chunk */ | |
521 *audio_buf = NULL; | |
522 do { | |
523 if ( *audio_buf != NULL ) { | |
1336
3692456e7b0f
Use SDL_ prefixed versions of C library functions.
Sam Lantinga <slouken@libsdl.org>
parents:
1330
diff
changeset
|
524 SDL_free(*audio_buf); |
0 | 525 } |
526 lenread = ReadChunk(src, &chunk); | |
527 if ( lenread < 0 ) { | |
528 was_error = 1; | |
529 goto done; | |
530 } | |
531 *audio_len = lenread; | |
532 *audio_buf = chunk.data; | |
1260
80f8c94b5199
Date: 10 Jun 2003 15:30:59 -0400
Sam Lantinga <slouken@libsdl.org>
parents:
769
diff
changeset
|
533 if(chunk.magic != DATA) headerDiff += lenread + 2 * sizeof(Uint32); |
0 | 534 } while ( chunk.magic != DATA ); |
1487
dc6b59e925a2
Cleaning up warnings on MacOS X
Sam Lantinga <slouken@libsdl.org>
parents:
1465
diff
changeset
|
535 headerDiff += 2 * sizeof(Uint32); /* for the data chunk and len */ |
0 | 536 |
537 if ( MS_ADPCM_encoded ) { | |
538 if ( MS_ADPCM_decode(audio_buf, audio_len) < 0 ) { | |
539 was_error = 1; | |
540 goto done; | |
541 } | |
542 } | |
543 if ( IMA_ADPCM_encoded ) { | |
544 if ( IMA_ADPCM_decode(audio_buf, audio_len) < 0 ) { | |
545 was_error = 1; | |
546 goto done; | |
547 } | |
548 } | |
549 | |
550 /* Don't return a buffer that isn't a multiple of samplesize */ | |
551 samplesize = ((spec->format & 0xFF)/8)*spec->channels; | |
552 *audio_len &= ~(samplesize-1); | |
553 | |
554 done: | |
555 if ( format != NULL ) { | |
1336
3692456e7b0f
Use SDL_ prefixed versions of C library functions.
Sam Lantinga <slouken@libsdl.org>
parents:
1330
diff
changeset
|
556 SDL_free(format); |
0 | 557 } |
1465
8dfa9a6d69a5
Updated WinCE support by Dmitry (with some tweaks)
Sam Lantinga <slouken@libsdl.org>
parents:
1428
diff
changeset
|
558 if ( src ) { |
8dfa9a6d69a5
Updated WinCE support by Dmitry (with some tweaks)
Sam Lantinga <slouken@libsdl.org>
parents:
1428
diff
changeset
|
559 if ( freesrc ) { |
8dfa9a6d69a5
Updated WinCE support by Dmitry (with some tweaks)
Sam Lantinga <slouken@libsdl.org>
parents:
1428
diff
changeset
|
560 SDL_RWclose(src); |
8dfa9a6d69a5
Updated WinCE support by Dmitry (with some tweaks)
Sam Lantinga <slouken@libsdl.org>
parents:
1428
diff
changeset
|
561 } else { |
1487
dc6b59e925a2
Cleaning up warnings on MacOS X
Sam Lantinga <slouken@libsdl.org>
parents:
1465
diff
changeset
|
562 /* seek to the end of the file (given by the RIFF chunk) */ |
1465
8dfa9a6d69a5
Updated WinCE support by Dmitry (with some tweaks)
Sam Lantinga <slouken@libsdl.org>
parents:
1428
diff
changeset
|
563 SDL_RWseek(src, wavelen - chunk.length - headerDiff, RW_SEEK_CUR); |
8dfa9a6d69a5
Updated WinCE support by Dmitry (with some tweaks)
Sam Lantinga <slouken@libsdl.org>
parents:
1428
diff
changeset
|
564 } |
1260
80f8c94b5199
Date: 10 Jun 2003 15:30:59 -0400
Sam Lantinga <slouken@libsdl.org>
parents:
769
diff
changeset
|
565 } |
0 | 566 if ( was_error ) { |
567 spec = NULL; | |
568 } | |
569 return(spec); | |
570 } | |
571 | |
572 /* Since the WAV memory is allocated in the shared library, it must also | |
573 be freed here. (Necessary under Win32, VC++) | |
574 */ | |
575 void SDL_FreeWAV(Uint8 *audio_buf) | |
576 { | |
577 if ( audio_buf != NULL ) { | |
1336
3692456e7b0f
Use SDL_ prefixed versions of C library functions.
Sam Lantinga <slouken@libsdl.org>
parents:
1330
diff
changeset
|
578 SDL_free(audio_buf); |
0 | 579 } |
580 } | |
581 | |
582 static int ReadChunk(SDL_RWops *src, Chunk *chunk) | |
583 { | |
584 chunk->magic = SDL_ReadLE32(src); | |
585 chunk->length = SDL_ReadLE32(src); | |
1336
3692456e7b0f
Use SDL_ prefixed versions of C library functions.
Sam Lantinga <slouken@libsdl.org>
parents:
1330
diff
changeset
|
586 chunk->data = (Uint8 *)SDL_malloc(chunk->length); |
0 | 587 if ( chunk->data == NULL ) { |
588 SDL_Error(SDL_ENOMEM); | |
589 return(-1); | |
590 } | |
591 if ( SDL_RWread(src, chunk->data, chunk->length, 1) != 1 ) { | |
592 SDL_Error(SDL_EFREAD); | |
1336
3692456e7b0f
Use SDL_ prefixed versions of C library functions.
Sam Lantinga <slouken@libsdl.org>
parents:
1330
diff
changeset
|
593 SDL_free(chunk->data); |
0 | 594 return(-1); |
595 } | |
596 return(chunk->length); | |
597 } |