1 /* 2 SDL_mixer: An audio mixer library based on the SDL library 3 Copyright (C) 1997-2018 Sam Lantinga <slouken@libsdl.org> 4 5 This software is provided 'as-is', without any express or implied 6 warranty. In no event will the authors be held liable for any damages 7 arising from the use of this software. 8 9 Permission is granted to anyone to use this software for any purpose, 10 including commercial applications, and to alter it and redistribute it 11 freely, subject to the following restrictions: 12 13 1. The origin of this software must not be misrepresented; you must not 14 claim that you wrote the original software. If you use this software 15 in a product, an acknowledgment in the product documentation would be 16 appreciated but is not required. 17 2. Altered source versions must be plainly marked as such, and must not be 18 misrepresented as being the original software. 19 3. This notice may not be removed or altered from any source distribution. 20 */ 21 22 #ifdef MUSIC_WAV 23 24 /* This file supports streaming WAV files */ 25 26 #include "music_wav.h" 27 28 29 typedef struct { 30 SDL_bool active; 31 Uint32 start; 32 Uint32 stop; 33 Uint32 initial_play_count; 34 Uint32 current_play_count; 35 } WAVLoopPoint; 36 37 typedef struct { 38 SDL_RWops *src; 39 SDL_bool freesrc; 40 SDL_AudioSpec spec; 41 int volume; 42 int play_count; 43 Sint64 start; 44 Sint64 stop; 45 Uint8 *buffer; 46 SDL_AudioStream *stream; 47 int numloops; 48 WAVLoopPoint *loops; 49 } WAV_Music; 50 51 /* 52 Taken with permission from SDL_wave.h, part of the SDL library, 53 available at: http://www.libsdl.org/ 54 and placed under the same license as this mixer library. 55 */ 56 57 /* WAVE files are little-endian */ 58 59 /*******************************************/ 60 /* Define values for Microsoft WAVE format */ 61 /*******************************************/ 62 #define RIFF 0x46464952 /* "RIFF" */ 63 #define WAVE 0x45564157 /* "WAVE" */ 64 #define FMT 0x20746D66 /* "fmt " */ 65 #define DATA 0x61746164 /* "data" */ 66 #define SMPL 0x6c706d73 /* "smpl" */ 67 #define PCM_CODE 1 68 #define ADPCM_CODE 2 69 #define WAVE_MONO 1 70 #define WAVE_STEREO 2 71 72 typedef struct { 73 /* Not saved in the chunk we read: 74 Uint32 chunkID; 75 Uint32 chunkLen; 76 */ 77 Uint16 encoding; 78 Uint16 channels; /* 1 = mono, 2 = stereo */ 79 Uint32 frequency; /* One of 11025, 22050, or 44100 Hz */ 80 Uint32 byterate; /* Average bytes per second */ 81 Uint16 blockalign; /* Bytes per sample block */ 82 Uint16 bitspersample; /* One of 8, 12, 16, or 4 for ADPCM */ 83 } WaveFMT; 84 85 typedef struct { 86 Uint32 identifier; 87 Uint32 type; 88 Uint32 start; 89 Uint32 end; 90 Uint32 fraction; 91 Uint32 play_count; 92 } SampleLoop; 93 94 typedef struct { 95 /* Not saved in the chunk we read: 96 Uint32 chunkID; 97 Uint32 chunkLen; 98 */ 99 Uint32 manufacturer; 100 Uint32 product; 101 Uint32 sample_period; 102 Uint32 MIDI_unity_note; 103 Uint32 MIDI_pitch_fraction; 104 Uint32 SMTPE_format; 105 Uint32 SMTPE_offset; 106 Uint32 sample_loops; 107 Uint32 sampler_data; 108 SampleLoop loops[1]; 109 } SamplerChunk; 110 111 /*********************************************/ 112 /* Define values for AIFF (IFF audio) format */ 113 /*********************************************/ 114 #define FORM 0x4d524f46 /* "FORM" */ 115 #define AIFF 0x46464941 /* "AIFF" */ 116 #define SSND 0x444e5353 /* "SSND" */ 117 #define COMM 0x4d4d4f43 /* "COMM" */ 118 119 120 /* Function to load the WAV/AIFF stream */ 121 static SDL_bool LoadWAVMusic(WAV_Music *wave); 122 static SDL_bool LoadAIFFMusic(WAV_Music *wave); 123 124 static void WAV_Delete(void *context); 125 126 /* Load a WAV stream from the given RWops object */ 127 static void *WAV_CreateFromRW(SDL_RWops *src, int freesrc) 128 { 129 WAV_Music *music; 130 Uint32 magic; 131 SDL_bool loaded = SDL_FALSE; 132 133 music = (WAV_Music *)SDL_calloc(1, sizeof(*music)); 134 if (!music) { 135 SDL_OutOfMemory(); 136 return NULL; 137 } 138 music->src = src; 139 music->volume = MIX_MAX_VOLUME; 140 141 magic = SDL_ReadLE32(src); 142 if (magic == RIFF || magic == WAVE) { 143 loaded = LoadWAVMusic(music); 144 } else if (magic == FORM) { 145 loaded = LoadAIFFMusic(music); 146 } else { 147 Mix_SetError("Unknown WAVE format"); 148 } 149 if (!loaded) { 150 SDL_free(music); 151 return NULL; 152 } 153 music->buffer = (Uint8*)SDL_malloc(music->spec.size); 154 if (!music->buffer) { 155 WAV_Delete(music); 156 return NULL; 157 } 158 music->stream = SDL_NewAudioStream( 159 music->spec.format, music->spec.channels, music->spec.freq, 160 music_spec.format, music_spec.channels, music_spec.freq); 161 if (!music->stream) { 162 WAV_Delete(music); 163 return NULL; 164 } 165 166 music->freesrc = freesrc; 167 return music; 168 } 169 170 static void WAV_SetVolume(void *context, int volume) 171 { 172 WAV_Music *music = (WAV_Music *)context; 173 music->volume = volume; 174 } 175 176 /* Start playback of a given WAV stream */ 177 static int WAV_Play(void *context, int play_count) 178 { 179 WAV_Music *music = (WAV_Music *)context; 180 int i; 181 for (i = 0; i < music->numloops; ++i) { 182 WAVLoopPoint *loop = &music->loops[i]; 183 loop->active = SDL_TRUE; 184 loop->current_play_count = loop->initial_play_count; 185 } 186 music->play_count = play_count; 187 if (SDL_RWseek(music->src, music->start, RW_SEEK_SET) < 0) { 188 return -1; 189 } 190 return 0; 191 } 192 193 /* Play some of a stream previously started with WAV_Play() */ 194 static int WAV_GetSome(void *context, void *data, int bytes, SDL_bool *done) 195 { 196 WAV_Music *music = (WAV_Music *)context; 197 Sint64 pos, stop; 198 WAVLoopPoint *loop; 199 Sint64 loop_start; 200 Sint64 loop_stop; 201 SDL_bool looped = SDL_FALSE; 202 int i; 203 int filled, amount, result; 204 205 filled = SDL_AudioStreamGet(music->stream, data, bytes); 206 if (filled != 0) { 207 return filled; 208 } 209 210 if (!music->play_count) { 211 /* All done */ 212 *done = SDL_TRUE; 213 return 0; 214 } 215 216 pos = SDL_RWtell(music->src); 217 stop = music->stop; 218 loop = NULL; 219 for (i = 0; i < music->numloops; ++i) { 220 loop = &music->loops[i]; 221 if (loop->active) { 222 const int bytes_per_sample = (SDL_AUDIO_BITSIZE(music->spec.format) / 8) * music->spec.channels; 223 loop_start = music->start + loop->start * bytes_per_sample; 224 loop_stop = music->start + (loop->stop + 1) * bytes_per_sample; 225 if (pos >= loop_start && pos < loop_stop) 226 { 227 stop = loop_stop; 228 break; 229 } 230 } 231 loop = NULL; 232 } 233 234 amount = music->spec.size; 235 if ((stop - pos) < amount) { 236 amount = (int)(stop - pos); 237 } 238 amount = (int)SDL_RWread(music->src, music->buffer, 1, amount); 239 if (amount > 0) { 240 result = SDL_AudioStreamPut(music->stream, music->buffer, amount); 241 if (result < 0) { 242 return -1; 243 } 244 } else { 245 /* We might be looping, continue */ 246 } 247 248 if (loop && SDL_RWtell(music->src) >= stop) { 249 if (loop->current_play_count == 1) { 250 loop->active = SDL_FALSE; 251 } else { 252 if (loop->current_play_count > 0) { 253 --loop->current_play_count; 254 } 255 SDL_RWseek(music->src, loop_start, RW_SEEK_SET); 256 looped = SDL_TRUE; 257 } 258 } 259 260 if (!looped && SDL_RWtell(music->src) >= music->stop) { 261 if (music->play_count == 1) { 262 music->play_count = 0; 263 SDL_AudioStreamFlush(music->stream); 264 } else { 265 int play_count = -1; 266 if (music->play_count > 0) { 267 play_count = (music->play_count - 1); 268 } 269 if (WAV_Play(music, play_count) < 0) { 270 return -1; 271 } 272 } 273 } 274 275 /* We'll get called again in the case where we looped or have more data */ 276 return 0; 277 } 278 279 static int WAV_GetAudio(void *context, void *data, int bytes) 280 { 281 WAV_Music *music = (WAV_Music *)context; 282 return music_pcm_getaudio(context, data, bytes, music->volume, WAV_GetSome); 283 } 284 285 /* Close the given WAV stream */ 286 static void WAV_Delete(void *context) 287 { 288 WAV_Music *music = (WAV_Music *)context; 289 290 /* Clean up associated data */ 291 if (music->loops) { 292 SDL_free(music->loops); 293 } 294 if (music->stream) { 295 SDL_FreeAudioStream(music->stream); 296 } 297 if (music->buffer) { 298 SDL_free(music->buffer); 299 } 300 if (music->freesrc) { 301 SDL_RWclose(music->src); 302 } 303 SDL_free(music); 304 } 305 306 static SDL_bool ParseFMT(WAV_Music *wave, Uint32 chunk_length) 307 { 308 SDL_AudioSpec *spec = &wave->spec; 309 WaveFMT *format; 310 Uint8 *data; 311 SDL_bool loaded = SDL_FALSE; 312 313 if (chunk_length < sizeof(*format)) { 314 Mix_SetError("Wave format chunk too small"); 315 return SDL_FALSE; 316 } 317 318 data = (Uint8 *)SDL_malloc(chunk_length); 319 if (!data) { 320 Mix_SetError("Out of memory"); 321 return SDL_FALSE; 322 } 323 if (!SDL_RWread(wave->src, data, chunk_length, 1)) { 324 Mix_SetError("Couldn't read %d bytes from WAV file", chunk_length); 325 return SDL_FALSE; 326 } 327 format = (WaveFMT *)data; 328 329 /* Decode the audio data format */ 330 switch (SDL_SwapLE16(format->encoding)) { 331 case PCM_CODE: 332 /* We can understand this */ 333 break; 334 default: 335 Mix_SetError("Unknown WAVE data format"); 336 goto done; 337 } 338 spec->freq = SDL_SwapLE32(format->frequency); 339 switch (SDL_SwapLE16(format->bitspersample)) { 340 case 8: 341 spec->format = AUDIO_U8; 342 break; 343 case 16: 344 spec->format = AUDIO_S16; 345 break; 346 default: 347 Mix_SetError("Unknown PCM data format"); 348 goto done; 349 } 350 spec->channels = (Uint8) SDL_SwapLE16(format->channels); 351 spec->samples = 4096; /* Good default buffer size */ 352 /* SDL_CalculateAudioSpec */ 353 spec->size = SDL_AUDIO_BITSIZE(spec->format) / 8; 354 spec->size *= spec->channels; 355 spec->size *= spec->samples; 356 357 loaded = SDL_TRUE; 358 359 done: 360 SDL_free(data); 361 return loaded; 362 } 363 364 static SDL_bool ParseDATA(WAV_Music *wave, Uint32 chunk_length) 365 { 366 wave->start = SDL_RWtell(wave->src); 367 wave->stop = wave->start + chunk_length; 368 SDL_RWseek(wave->src, chunk_length, RW_SEEK_CUR); 369 return SDL_TRUE; 370 } 371 372 static SDL_bool AddLoopPoint(WAV_Music *wave, Uint32 play_count, Uint32 start, Uint32 stop) 373 { 374 WAVLoopPoint *loop; 375 WAVLoopPoint *loops = SDL_realloc(wave->loops, (wave->numloops + 1)*sizeof(*wave->loops)); 376 if (!loops) { 377 Mix_SetError("Out of memory"); 378 return SDL_FALSE; 379 } 380 381 loop = &loops[ wave->numloops ]; 382 loop->start = start; 383 loop->stop = stop; 384 loop->initial_play_count = play_count; 385 loop->current_play_count = play_count; 386 387 wave->loops = loops; 388 ++wave->numloops; 389 return SDL_TRUE; 390 } 391 392 static SDL_bool ParseSMPL(WAV_Music *wave, Uint32 chunk_length) 393 { 394 SamplerChunk *chunk; 395 Uint8 *data; 396 Uint32 i; 397 SDL_bool loaded = SDL_FALSE; 398 399 data = (Uint8 *)SDL_malloc(chunk_length); 400 if (!data) { 401 Mix_SetError("Out of memory"); 402 return SDL_FALSE; 403 } 404 if (!SDL_RWread(wave->src, data, chunk_length, 1)) { 405 Mix_SetError("Couldn't read %d bytes from WAV file", chunk_length); 406 return SDL_FALSE; 407 } 408 chunk = (SamplerChunk *)data; 409 410 for (i = 0; i < SDL_SwapLE32(chunk->sample_loops); ++i) { 411 const Uint32 LOOP_TYPE_FORWARD = 0; 412 Uint32 loop_type = SDL_SwapLE32(chunk->loops[i].type); 413 if (loop_type == LOOP_TYPE_FORWARD) { 414 AddLoopPoint(wave, SDL_SwapLE32(chunk->loops[i].play_count), SDL_SwapLE32(chunk->loops[i].start), SDL_SwapLE32(chunk->loops[i].end)); 415 } 416 } 417 418 loaded = SDL_TRUE; 419 SDL_free(data); 420 return loaded; 421 } 422 423 static SDL_bool LoadWAVMusic(WAV_Music *wave) 424 { 425 SDL_RWops *src = wave->src; 426 Uint32 chunk_type; 427 Uint32 chunk_length; 428 SDL_bool found_FMT = SDL_FALSE; 429 SDL_bool found_DATA = SDL_FALSE; 430 431 /* WAV magic header */ 432 Uint32 wavelen; 433 Uint32 WAVEmagic; 434 435 /* Check the magic header */ 436 wavelen = SDL_ReadLE32(src); 437 WAVEmagic = SDL_ReadLE32(src); 438 439 /* Read the chunks */ 440 for (; ;) { 441 chunk_type = SDL_ReadLE32(src); 442 chunk_length = SDL_ReadLE32(src); 443 444 if (chunk_length == 0) 445 break; 446 447 switch (chunk_type) 448 { 449 case FMT: 450 found_FMT = SDL_TRUE; 451 if (!ParseFMT(wave, chunk_length)) 452 return SDL_FALSE; 453 break; 454 case DATA: 455 found_DATA = SDL_TRUE; 456 if (!ParseDATA(wave, chunk_length)) 457 return SDL_FALSE; 458 break; 459 case SMPL: 460 if (!ParseSMPL(wave, chunk_length)) 461 return SDL_FALSE; 462 break; 463 default: 464 SDL_RWseek(src, chunk_length, RW_SEEK_CUR); 465 break; 466 } 467 } 468 469 if (!found_FMT) { 470 Mix_SetError("Bad WAV file (no FMT chunk)"); 471 return SDL_FALSE; 472 } 473 474 if (!found_DATA) { 475 Mix_SetError("Bad WAV file (no DATA chunk)"); 476 return SDL_FALSE; 477 } 478 479 return SDL_TRUE; 480 } 481 482 /* I couldn't get SANE_to_double() to work, so I stole this from libsndfile. 483 * I don't pretend to fully understand it. 484 */ 485 486 static Uint32 SANE_to_Uint32 (Uint8 *sanebuf) 487 { 488 /* Negative number? */ 489 if (sanebuf[0] & 0x80) 490 return 0; 491 492 /* Less than 1? */ 493 if (sanebuf[0] <= 0x3F) 494 return 1; 495 496 /* Way too big? */ 497 if (sanebuf[0] > 0x40) 498 return 0x4000000; 499 500 /* Still too big? */ 501 if (sanebuf[0] == 0x40 && sanebuf[1] > 0x1C) 502 return 800000000; 503 504 return ((sanebuf[2] << 23) | (sanebuf[3] << 15) | (sanebuf[4] << 7) | 505 (sanebuf[5] >> 1)) >> (29 - sanebuf[1]); 506 } 507 508 static SDL_bool LoadAIFFMusic(WAV_Music *wave) 509 { 510 SDL_RWops *src = wave->src; 511 SDL_AudioSpec *spec = &wave->spec; 512 SDL_bool found_SSND = SDL_FALSE; 513 SDL_bool found_COMM = SDL_FALSE; 514 515 Uint32 chunk_type; 516 Uint32 chunk_length; 517 Sint64 next_chunk; 518 519 /* AIFF magic header */ 520 Uint32 AIFFmagic; 521 /* SSND chunk */ 522 Uint32 offset; 523 Uint32 blocksize; 524 /* COMM format chunk */ 525 Uint16 channels = 0; 526 Uint32 numsamples = 0; 527 Uint16 samplesize = 0; 528 Uint8 sane_freq[10]; 529 Uint32 frequency = 0; 530 531 /* Check the magic header */ 532 chunk_length = SDL_ReadBE32(src); 533 AIFFmagic = SDL_ReadLE32(src); 534 if (AIFFmagic != AIFF) { 535 Mix_SetError("Unrecognized file type (not AIFF)"); 536 return SDL_FALSE; 537 } 538 539 /* From what I understand of the specification, chunks may appear in 540 * any order, and we should just ignore unknown ones. 541 * 542 * TODO: Better sanity-checking. E.g. what happens if the AIFF file 543 * contains compressed sound data? 544 */ 545 do { 546 chunk_type = SDL_ReadLE32(src); 547 chunk_length = SDL_ReadBE32(src); 548 next_chunk = SDL_RWtell(src) + chunk_length; 549 550 /* Paranoia to avoid infinite loops */ 551 if (chunk_length == 0) 552 break; 553 554 switch (chunk_type) { 555 case SSND: 556 found_SSND = SDL_TRUE; 557 offset = SDL_ReadBE32(src); 558 blocksize = SDL_ReadBE32(src); 559 wave->start = SDL_RWtell(src) + offset; 560 break; 561 562 case COMM: 563 found_COMM = SDL_TRUE; 564 565 /* Read the audio data format chunk */ 566 channels = SDL_ReadBE16(src); 567 numsamples = SDL_ReadBE32(src); 568 samplesize = SDL_ReadBE16(src); 569 SDL_RWread(src, sane_freq, sizeof(sane_freq), 1); 570 frequency = SANE_to_Uint32(sane_freq); 571 break; 572 573 default: 574 break; 575 } 576 } while ((!found_SSND || !found_COMM) 577 && SDL_RWseek(src, next_chunk, RW_SEEK_SET) != -1); 578 579 if (!found_SSND) { 580 Mix_SetError("Bad AIFF file (no SSND chunk)"); 581 return SDL_FALSE; 582 } 583 584 if (!found_COMM) { 585 Mix_SetError("Bad AIFF file (no COMM chunk)"); 586 return SDL_FALSE; 587 } 588 589 wave->stop = wave->start + channels * numsamples * (samplesize / 8); 590 591 /* Decode the audio data format */ 592 SDL_memset(spec, 0, (sizeof *spec)); 593 spec->freq = frequency; 594 switch (samplesize) { 595 case 8: 596 spec->format = AUDIO_S8; 597 break; 598 case 16: 599 spec->format = AUDIO_S16MSB; 600 break; 601 default: 602 Mix_SetError("Unknown samplesize in data format"); 603 return SDL_FALSE; 604 } 605 spec->channels = (Uint8) channels; 606 spec->samples = 4096; /* Good default buffer size */ 607 608 return SDL_TRUE; 609 } 610 611 Mix_MusicInterface Mix_MusicInterface_WAV = 612 { 613 "WAVE", 614 MIX_MUSIC_WAVE, 615 MUS_WAV, 616 SDL_FALSE, 617 SDL_FALSE, 618 619 NULL, /* Load */ 620 NULL, /* Open */ 621 WAV_CreateFromRW, 622 NULL, /* CreateFromFile */ 623 WAV_SetVolume, 624 WAV_Play, 625 NULL, /* IsPlaying */ 626 WAV_GetAudio, 627 NULL, /* Seek */ 628 NULL, /* Pause */ 629 NULL, /* Resume */ 630 NULL, /* Stop */ 631 WAV_Delete, 632 NULL, /* Close */ 633 NULL, /* Unload */ 634 }; 635 636 #endif /* MUSIC_WAV */ 637 638 /* vi: set ts=4 sw=4 expandtab: */ 639