1 /*
2 SDL_mixer: An audio mixer library based on the SDL library
3 Copyright (C) 1997-2009 Sam Lantinga
4
5 This library is free software; you can redistribute it and/or
6 modify it under the terms of the GNU Library General Public
7 License as published by the Free Software Foundation; either
8 version 2 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 Library General Public License for more details.
14
15 You should have received a copy of the GNU Library General Public
16 License along with this library; if not, write to the Free
17 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
18
19 Sam Lantinga
20 slouken@libsdl.org
21 */
22
23 /* $Id: wavestream.c 5214 2009-11-08 17:11:09Z slouken $ */
24
25 /* This file supports streaming WAV files, without volume adjustment */
26
27 #include <stdlib.h>
28 #include <string.h>
29
30 #include "SDL_audio.h"
31 #include "SDL_mutex.h"
32 #include "SDL_rwops.h"
33 #include "SDL_endian.h"
34
35 #include "SDL_mixer.h"
36 #include "wavestream.h"
37
38 /*
39 Taken with permission from SDL_wave.h, part of the SDL library,
40 available at: http://www.libsdl.org/
41 and placed under the same license as this mixer library.
42 */
43
44 /* WAVE files are little-endian */
45
46 /*******************************************/
47 /* Define values for Microsoft WAVE format */
48 /*******************************************/
49 #define RIFF 0x46464952 /* "RIFF" */
50 #define WAVE 0x45564157 /* "WAVE" */
51 #define FACT 0x74636166 /* "fact" */
52 #define LIST 0x5453494c /* "LIST" */
53 #define FMT 0x20746D66 /* "fmt " */
54 #define DATA 0x61746164 /* "data" */
55 #define PCM_CODE 1
56 #define ADPCM_CODE 2
57 #define WAVE_MONO 1
58 #define WAVE_STEREO 2
59
60 /* Normally, these three chunks come consecutively in a WAVE file */
61 typedef struct WaveFMT {
62 /* Not saved in the chunk we read:
63 Uint32 FMTchunk;
64 Uint32 fmtlen;
65 */
66 Uint16 encoding;
67 Uint16 channels; /* 1 = mono, 2 = stereo */
68 Uint32 frequency; /* One of 11025, 22050, or 44100 Hz */
69 Uint32 byterate; /* Average bytes per second */
70 Uint16 blockalign; /* Bytes per sample block */
71 Uint16 bitspersample; /* One of 8, 12, 16, or 4 for ADPCM */
72 } WaveFMT;
73
74 /* The general chunk found in the WAVE file */
75 typedef struct Chunk {
76 Uint32 magic;
77 Uint32 length;
78 Uint8 *data; /* Data includes magic and length */
79 } Chunk;
80
81 /*********************************************/
82 /* Define values for AIFF (IFF audio) format */
83 /*********************************************/
84 #define FORM 0x4d524f46 /* "FORM" */
85 #define AIFF 0x46464941 /* "AIFF" */
86 #define SSND 0x444e5353 /* "SSND" */
87 #define COMM 0x4d4d4f43 /* "COMM" */
88
89
90 /* Currently we only support a single stream at a time */
91 static WAVStream *music = NULL;
92
93 /* This is the format of the audio mixer data */
94 static SDL_AudioSpec mixer;
95 static int wavestream_volume = MIX_MAX_VOLUME;
96
97 /* Function to load the WAV/AIFF stream */
98 static SDL_RWops *LoadWAVStream (SDL_RWops *rw, SDL_AudioSpec *spec,
99 long *start, long *stop);
100 static SDL_RWops *LoadAIFFStream (SDL_RWops *rw, SDL_AudioSpec *spec,
101 long *start, long *stop);
102
103 /* Initialize the WAVStream player, with the given mixer settings
104 This function returns 0, or -1 if there was an error.
105 */
WAVStream_Init(SDL_AudioSpec * mixerfmt)106 int WAVStream_Init(SDL_AudioSpec *mixerfmt)
107 {
108 mixer = *mixerfmt;
109 return(0);
110 }
111
WAVStream_SetVolume(int volume)112 void WAVStream_SetVolume(int volume)
113 {
114 wavestream_volume = volume;
115 }
116
WAVStream_LoadSong(const char * file,const char * magic)117 WAVStream *WAVStream_LoadSong(const char *file, const char *magic)
118 {
119 SDL_RWops *rw;
120 WAVStream *wave;
121
122 rw = SDL_RWFromFile(file, "rb");
123 if ( rw == NULL ) {
124 SDL_SetError("Couldn't open %s", file);
125 return NULL;
126 }
127 wave = WAVStream_LoadSong_RW(rw, magic);
128 if ( wave == NULL ) {
129 SDL_FreeRW(rw);
130 return NULL;
131 }
132 return wave;
133 }
134
135 /* Load a WAV stream from the given file */
WAVStream_LoadSong_RW(SDL_RWops * rw,const char * magic)136 WAVStream *WAVStream_LoadSong_RW(SDL_RWops *rw, const char *magic)
137 {
138 WAVStream *wave;
139 SDL_AudioSpec wavespec;
140
141 if ( ! mixer.format ) {
142 Mix_SetError("WAV music output not started");
143 return(NULL);
144 }
145 wave = (WAVStream *)malloc(sizeof *wave);
146 if ( wave ) {
147 memset(wave, 0, (sizeof *wave));
148 if ( strcmp(magic, "RIFF") == 0 ) {
149 wave->rw = LoadWAVStream(rw, &wavespec,
150 &wave->start, &wave->stop);
151 } else
152 if ( strcmp(magic, "FORM") == 0 ) {
153 wave->rw = LoadAIFFStream(rw, &wavespec,
154 &wave->start, &wave->stop);
155 } else {
156 Mix_SetError("Unknown WAVE format");
157 }
158 if ( wave->rw == NULL ) {
159 free(wave);
160 return(NULL);
161 }
162 SDL_BuildAudioCVT(&wave->cvt,
163 wavespec.format, wavespec.channels, wavespec.freq,
164 mixer.format, mixer.channels, mixer.freq);
165 }
166 return(wave);
167 }
168
169 /* Start playback of a given WAV stream */
WAVStream_Start(WAVStream * wave)170 void WAVStream_Start(WAVStream *wave)
171 {
172 SDL_RWseek (wave->rw, wave->start, RW_SEEK_SET);
173 music = wave;
174 }
175
176 /* Play some of a stream previously started with WAVStream_Start() */
WAVStream_PlaySome(Uint8 * stream,int len)177 int WAVStream_PlaySome(Uint8 *stream, int len)
178 {
179 long pos;
180 int left = 0;
181
182 if ( music && ((pos=SDL_RWtell(music->rw)) < music->stop) ) {
183 if ( music->cvt.needed ) {
184 int original_len;
185
186 original_len=(int)((double)len/music->cvt.len_ratio);
187 if ( music->cvt.len != original_len ) {
188 int worksize;
189 if ( music->cvt.buf != NULL ) {
190 free(music->cvt.buf);
191 }
192 worksize = original_len*music->cvt.len_mult;
193 music->cvt.buf=(Uint8 *)malloc(worksize);
194 if ( music->cvt.buf == NULL ) {
195 return 0;
196 }
197 music->cvt.len = original_len;
198 }
199 if ( (music->stop - pos) < original_len ) {
200 left = (original_len - (music->stop - pos));
201 original_len -= left;
202 left = (int)((double)left*music->cvt.len_ratio);
203 }
204 original_len = SDL_RWread(music->rw, music->cvt.buf,1,original_len);
205 /* At least at the time of writing, SDL_ConvertAudio()
206 does byte-order swapping starting at the end of the
207 buffer. Thus, if we are reading 16-bit samples, we
208 had better make damn sure that we get an even
209 number of bytes, or we'll get garbage.
210 */
211 if ( (music->cvt.src_format & 0x0010) && (original_len & 1) ) {
212 original_len--;
213 }
214 music->cvt.len = original_len;
215 SDL_ConvertAudio(&music->cvt);
216 SDL_MixAudio(stream, music->cvt.buf, music->cvt.len_cvt, wavestream_volume);
217 } else {
218 Uint8 *data;
219 if ( (music->stop - pos) < len ) {
220 left = (len - (music->stop - pos));
221 len -= left;
222 }
223 data = SDL_stack_alloc(Uint8, len);
224 if (data)
225 {
226 SDL_RWread(music->rw, data, len, 1);
227 SDL_MixAudio(stream, data, len, wavestream_volume);
228 SDL_stack_free(data);
229 }
230 }
231 }
232 return left;
233 }
234
235 /* Stop playback of a stream previously started with WAVStream_Start() */
WAVStream_Stop(void)236 void WAVStream_Stop(void)
237 {
238 music = NULL;
239 }
240
241 /* Close the given WAV stream */
WAVStream_FreeSong(WAVStream * wave)242 void WAVStream_FreeSong(WAVStream *wave)
243 {
244 if ( wave ) {
245 /* Clean up associated data */
246 if ( wave->freerw ) {
247 SDL_FreeRW(wave->rw);
248 }
249 if ( wave->cvt.buf ) {
250 free(wave->cvt.buf);
251 }
252 free(wave);
253 }
254 }
255
256 /* Return non-zero if a stream is currently playing */
WAVStream_Active(void)257 int WAVStream_Active(void)
258 {
259 int active;
260
261 active = 0;
262 if ( music && (SDL_RWtell(music->rw) < music->stop) ) {
263 active = 1;
264 }
265 return(active);
266 }
267
ReadChunk(SDL_RWops * src,Chunk * chunk,int read_data)268 static int ReadChunk(SDL_RWops *src, Chunk *chunk, int read_data)
269 {
270 chunk->magic = SDL_ReadLE32(src);
271 chunk->length = SDL_ReadLE32(src);
272 if ( read_data ) {
273 chunk->data = (Uint8 *)malloc(chunk->length);
274 if ( chunk->data == NULL ) {
275 Mix_SetError("Out of memory");
276 return(-1);
277 }
278 if ( SDL_RWread(src, chunk->data, chunk->length, 1) != 1 ) {
279 Mix_SetError("Couldn't read chunk");
280 free(chunk->data);
281 return(-1);
282 }
283 } else {
284 SDL_RWseek(src, chunk->length, RW_SEEK_CUR);
285 }
286 return(chunk->length);
287 }
288
LoadWAVStream(SDL_RWops * src,SDL_AudioSpec * spec,long * start,long * stop)289 static SDL_RWops *LoadWAVStream (SDL_RWops *src, SDL_AudioSpec *spec,
290 long *start, long *stop)
291 {
292 int was_error;
293 Chunk chunk;
294 int lenread;
295
296 /* WAV magic header */
297 Uint32 RIFFchunk;
298 Uint32 wavelen;
299 Uint32 WAVEmagic;
300
301 /* FMT chunk */
302 WaveFMT *format = NULL;
303
304 was_error = 0;
305
306 /* Check the magic header */
307 RIFFchunk = SDL_ReadLE32(src);
308 wavelen = SDL_ReadLE32(src);
309 WAVEmagic = SDL_ReadLE32(src);
310 if ( (RIFFchunk != RIFF) || (WAVEmagic != WAVE) ) {
311 Mix_SetError("Unrecognized file type (not WAVE)");
312 was_error = 1;
313 goto done;
314 }
315
316 /* Read the audio data format chunk */
317 chunk.data = NULL;
318 do {
319 /* FIXME! Add this logic to SDL_LoadWAV_RW() */
320 if ( chunk.data ) {
321 free(chunk.data);
322 }
323 lenread = ReadChunk(src, &chunk, 1);
324 if ( lenread < 0 ) {
325 was_error = 1;
326 goto done;
327 }
328 } while ( (chunk.magic == FACT) || (chunk.magic == LIST) );
329
330 /* Decode the audio data format */
331 format = (WaveFMT *)chunk.data;
332 if ( chunk.magic != FMT ) {
333 free(chunk.data);
334 Mix_SetError("Complex WAVE files not supported");
335 was_error = 1;
336 goto done;
337 }
338 switch (SDL_SwapLE16(format->encoding)) {
339 case PCM_CODE:
340 /* We can understand this */
341 break;
342 default:
343 Mix_SetError("Unknown WAVE data format");
344 was_error = 1;
345 goto done;
346 }
347 memset(spec, 0, (sizeof *spec));
348 spec->freq = SDL_SwapLE32(format->frequency);
349 switch (SDL_SwapLE16(format->bitspersample)) {
350 case 8:
351 spec->format = AUDIO_U8;
352 break;
353 case 16:
354 spec->format = AUDIO_S16;
355 break;
356 default:
357 Mix_SetError("Unknown PCM data format");
358 was_error = 1;
359 goto done;
360 }
361 spec->channels = (Uint8) SDL_SwapLE16(format->channels);
362 spec->samples = 4096; /* Good default buffer size */
363
364 /* Set the file offset to the DATA chunk data */
365 chunk.data = NULL;
366 do {
367 *start = SDL_RWtell(src) + 2*sizeof(Uint32);
368 lenread = ReadChunk(src, &chunk, 0);
369 if ( lenread < 0 ) {
370 was_error = 1;
371 goto done;
372 }
373 } while ( chunk.magic != DATA );
374 *stop = SDL_RWtell(src);
375
376 done:
377 if ( format != NULL ) {
378 free(format);
379 }
380 if ( was_error ) {
381 return NULL;
382 }
383 return(src);
384 }
385
386 /* I couldn't get SANE_to_double() to work, so I stole this from libsndfile.
387 * I don't pretend to fully understand it.
388 */
389
SANE_to_Uint32(Uint8 * sanebuf)390 static Uint32 SANE_to_Uint32 (Uint8 *sanebuf)
391 {
392 /* Negative number? */
393 if (sanebuf[0] & 0x80)
394 return 0;
395
396 /* Less than 1? */
397 if (sanebuf[0] <= 0x3F)
398 return 1;
399
400 /* Way too big? */
401 if (sanebuf[0] > 0x40)
402 return 0x4000000;
403
404 /* Still too big? */
405 if (sanebuf[0] == 0x40 && sanebuf[1] > 0x1C)
406 return 800000000;
407
408 return ((sanebuf[2] << 23) | (sanebuf[3] << 15) | (sanebuf[4] << 7)
409 | (sanebuf[5] >> 1)) >> (29 - sanebuf[1]);
410 }
411
LoadAIFFStream(SDL_RWops * src,SDL_AudioSpec * spec,long * start,long * stop)412 static SDL_RWops *LoadAIFFStream (SDL_RWops *src, SDL_AudioSpec *spec,
413 long *start, long *stop)
414 {
415 int was_error;
416 int found_SSND;
417 int found_COMM;
418
419 Uint32 chunk_type;
420 Uint32 chunk_length;
421 long next_chunk;
422
423 /* AIFF magic header */
424 Uint32 FORMchunk;
425 Uint32 AIFFmagic;
426 /* SSND chunk */
427 Uint32 offset;
428 Uint32 blocksize;
429 /* COMM format chunk */
430 Uint16 channels = 0;
431 Uint32 numsamples = 0;
432 Uint16 samplesize = 0;
433 Uint8 sane_freq[10];
434 Uint32 frequency = 0;
435
436 was_error = 0;
437
438 /* Check the magic header */
439 FORMchunk = SDL_ReadLE32(src);
440 chunk_length = SDL_ReadBE32(src);
441 AIFFmagic = SDL_ReadLE32(src);
442 if ( (FORMchunk != FORM) || (AIFFmagic != AIFF) ) {
443 Mix_SetError("Unrecognized file type (not AIFF)");
444 was_error = 1;
445 goto done;
446 }
447
448 /* From what I understand of the specification, chunks may appear in
449 * any order, and we should just ignore unknown ones.
450 *
451 * TODO: Better sanity-checking. E.g. what happens if the AIFF file
452 * contains compressed sound data?
453 */
454
455 found_SSND = 0;
456 found_COMM = 0;
457
458 do {
459 chunk_type = SDL_ReadLE32(src);
460 chunk_length = SDL_ReadBE32(src);
461 next_chunk = SDL_RWtell(src) + chunk_length;
462
463 /* Paranoia to avoid infinite loops */
464 if (chunk_length == 0)
465 break;
466
467 switch (chunk_type) {
468 case SSND:
469 found_SSND = 1;
470 offset = SDL_ReadBE32(src);
471 blocksize = SDL_ReadBE32(src);
472 *start = SDL_RWtell(src) + offset;
473 break;
474
475 case COMM:
476 found_COMM = 1;
477
478 /* Read the audio data format chunk */
479 channels = SDL_ReadBE16(src);
480 numsamples = SDL_ReadBE32(src);
481 samplesize = SDL_ReadBE16(src);
482 SDL_RWread(src, sane_freq, sizeof(sane_freq), 1);
483 frequency = SANE_to_Uint32(sane_freq);
484 break;
485
486 default:
487 break;
488 }
489 } while ((!found_SSND || !found_COMM)
490 && SDL_RWseek(src, next_chunk, RW_SEEK_SET) != -1);
491
492 if (!found_SSND) {
493 Mix_SetError("Bad AIFF file (no SSND chunk)");
494 was_error = 1;
495 goto done;
496 }
497
498 if (!found_COMM) {
499 Mix_SetError("Bad AIFF file (no COMM chunk)");
500 was_error = 1;
501 goto done;
502 }
503
504 *stop = *start + channels * numsamples * (samplesize / 8);
505
506 /* Decode the audio data format */
507 memset(spec, 0, (sizeof *spec));
508 spec->freq = frequency;
509 switch (samplesize) {
510 case 8:
511 spec->format = AUDIO_S8;
512 break;
513 case 16:
514 spec->format = AUDIO_S16MSB;
515 break;
516 default:
517 Mix_SetError("Unknown samplesize in data format");
518 was_error = 1;
519 goto done;
520 }
521 spec->channels = (Uint8) channels;
522 spec->samples = 4096; /* Good default buffer size */
523
524 done:
525 if ( was_error ) {
526 return NULL;
527 }
528 return(src);
529 }
530
531