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