Mercurial > sdl-ios-xcode
annotate src/audio/SDL_wave.c @ 1604:bfba1ea4452a
*** empty log message ***
author | Sam Lantinga <slouken@libsdl.org> |
---|---|
date | Thu, 23 Mar 2006 21:39:02 +0000 |
parents | dc6b59e925a2 |
children | 97d0966f4bf7 |
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; | |
332 int c, channels; | |
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; | |
481 default: | |
482 SDL_SetError("Unknown WAVE data format: 0x%.4x", | |
483 SDL_SwapLE16(format->encoding)); | |
484 was_error = 1; | |
485 goto done; | |
486 } | |
1336
3692456e7b0f
Use SDL_ prefixed versions of C library functions.
Sam Lantinga <slouken@libsdl.org>
parents:
1330
diff
changeset
|
487 SDL_memset(spec, 0, (sizeof *spec)); |
0 | 488 spec->freq = SDL_SwapLE32(format->frequency); |
489 switch (SDL_SwapLE16(format->bitspersample)) { | |
490 case 4: | |
491 if ( MS_ADPCM_encoded || IMA_ADPCM_encoded ) { | |
492 spec->format = AUDIO_S16; | |
493 } else { | |
494 was_error = 1; | |
495 } | |
496 break; | |
497 case 8: | |
498 spec->format = AUDIO_U8; | |
499 break; | |
500 case 16: | |
501 spec->format = AUDIO_S16; | |
502 break; | |
503 default: | |
504 was_error = 1; | |
505 break; | |
506 } | |
507 if ( was_error ) { | |
508 SDL_SetError("Unknown %d-bit PCM data format", | |
509 SDL_SwapLE16(format->bitspersample)); | |
510 goto done; | |
511 } | |
512 spec->channels = (Uint8)SDL_SwapLE16(format->channels); | |
513 spec->samples = 4096; /* Good default buffer size */ | |
514 | |
515 /* Read the audio data chunk */ | |
516 *audio_buf = NULL; | |
517 do { | |
518 if ( *audio_buf != NULL ) { | |
1336
3692456e7b0f
Use SDL_ prefixed versions of C library functions.
Sam Lantinga <slouken@libsdl.org>
parents:
1330
diff
changeset
|
519 SDL_free(*audio_buf); |
0 | 520 } |
521 lenread = ReadChunk(src, &chunk); | |
522 if ( lenread < 0 ) { | |
523 was_error = 1; | |
524 goto done; | |
525 } | |
526 *audio_len = lenread; | |
527 *audio_buf = chunk.data; | |
1260
80f8c94b5199
Date: 10 Jun 2003 15:30:59 -0400
Sam Lantinga <slouken@libsdl.org>
parents:
769
diff
changeset
|
528 if(chunk.magic != DATA) headerDiff += lenread + 2 * sizeof(Uint32); |
0 | 529 } while ( chunk.magic != DATA ); |
1487
dc6b59e925a2
Cleaning up warnings on MacOS X
Sam Lantinga <slouken@libsdl.org>
parents:
1465
diff
changeset
|
530 headerDiff += 2 * sizeof(Uint32); /* for the data chunk and len */ |
0 | 531 |
532 if ( MS_ADPCM_encoded ) { | |
533 if ( MS_ADPCM_decode(audio_buf, audio_len) < 0 ) { | |
534 was_error = 1; | |
535 goto done; | |
536 } | |
537 } | |
538 if ( IMA_ADPCM_encoded ) { | |
539 if ( IMA_ADPCM_decode(audio_buf, audio_len) < 0 ) { | |
540 was_error = 1; | |
541 goto done; | |
542 } | |
543 } | |
544 | |
545 /* Don't return a buffer that isn't a multiple of samplesize */ | |
546 samplesize = ((spec->format & 0xFF)/8)*spec->channels; | |
547 *audio_len &= ~(samplesize-1); | |
548 | |
549 done: | |
550 if ( format != NULL ) { | |
1336
3692456e7b0f
Use SDL_ prefixed versions of C library functions.
Sam Lantinga <slouken@libsdl.org>
parents:
1330
diff
changeset
|
551 SDL_free(format); |
0 | 552 } |
1465
8dfa9a6d69a5
Updated WinCE support by Dmitry (with some tweaks)
Sam Lantinga <slouken@libsdl.org>
parents:
1428
diff
changeset
|
553 if ( src ) { |
8dfa9a6d69a5
Updated WinCE support by Dmitry (with some tweaks)
Sam Lantinga <slouken@libsdl.org>
parents:
1428
diff
changeset
|
554 if ( freesrc ) { |
8dfa9a6d69a5
Updated WinCE support by Dmitry (with some tweaks)
Sam Lantinga <slouken@libsdl.org>
parents:
1428
diff
changeset
|
555 SDL_RWclose(src); |
8dfa9a6d69a5
Updated WinCE support by Dmitry (with some tweaks)
Sam Lantinga <slouken@libsdl.org>
parents:
1428
diff
changeset
|
556 } else { |
1487
dc6b59e925a2
Cleaning up warnings on MacOS X
Sam Lantinga <slouken@libsdl.org>
parents:
1465
diff
changeset
|
557 /* 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
|
558 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
|
559 } |
1260
80f8c94b5199
Date: 10 Jun 2003 15:30:59 -0400
Sam Lantinga <slouken@libsdl.org>
parents:
769
diff
changeset
|
560 } |
0 | 561 if ( was_error ) { |
562 spec = NULL; | |
563 } | |
564 return(spec); | |
565 } | |
566 | |
567 /* Since the WAV memory is allocated in the shared library, it must also | |
568 be freed here. (Necessary under Win32, VC++) | |
569 */ | |
570 void SDL_FreeWAV(Uint8 *audio_buf) | |
571 { | |
572 if ( audio_buf != NULL ) { | |
1336
3692456e7b0f
Use SDL_ prefixed versions of C library functions.
Sam Lantinga <slouken@libsdl.org>
parents:
1330
diff
changeset
|
573 SDL_free(audio_buf); |
0 | 574 } |
575 } | |
576 | |
577 static int ReadChunk(SDL_RWops *src, Chunk *chunk) | |
578 { | |
579 chunk->magic = SDL_ReadLE32(src); | |
580 chunk->length = SDL_ReadLE32(src); | |
1336
3692456e7b0f
Use SDL_ prefixed versions of C library functions.
Sam Lantinga <slouken@libsdl.org>
parents:
1330
diff
changeset
|
581 chunk->data = (Uint8 *)SDL_malloc(chunk->length); |
0 | 582 if ( chunk->data == NULL ) { |
583 SDL_Error(SDL_ENOMEM); | |
584 return(-1); | |
585 } | |
586 if ( SDL_RWread(src, chunk->data, chunk->length, 1) != 1 ) { | |
587 SDL_Error(SDL_EFREAD); | |
1336
3692456e7b0f
Use SDL_ prefixed versions of C library functions.
Sam Lantinga <slouken@libsdl.org>
parents:
1330
diff
changeset
|
588 SDL_free(chunk->data); |
0 | 589 return(-1); |
590 } | |
591 return(chunk->length); | |
592 } |