wavestream.c
author Sam Lantinga <slouken@libsdl.org>
Fri, 29 Jan 2016 12:44:13 -0800
changeset 718 fb0562cc1559
parent 711 f40c5ac95b12
child 725 bdf7b8d20566
permissions -rw-r--r--
Added Mix_OpenAudioDevice() so you can specify the audio device to open
     1 /*
     2   SDL_mixer:  An audio mixer library based on the SDL library
     3   Copyright (C) 1997-2016 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;
   215 
   216         original_len = (int)((double)len/music->cvt.len_ratio);
   217         if (music->cvt.len != original_len) {
   218             int worksize;
   219             if (music->cvt.buf != NULL) {
   220                 SDL_free(music->cvt.buf);
   221             }
   222             worksize = original_len*music->cvt.len_mult;
   223             music->cvt.buf=(Uint8 *)SDL_malloc(worksize);
   224             if (music->cvt.buf == NULL) {
   225                 return 0;
   226             }
   227             music->cvt.len = original_len;
   228         }
   229         if ((stop - pos) < original_len) {
   230             original_len = (int)(stop - pos);
   231         }
   232         original_len = SDL_RWread(music->src, music->cvt.buf, 1, original_len);
   233         /* At least at the time of writing, SDL_ConvertAudio()
   234            does byte-order swapping starting at the end of the
   235            buffer. Thus, if we are reading 16-bit samples, we
   236            had better make damn sure that we get an even
   237            number of bytes, or we'll get garbage.
   238          */
   239         if ((music->cvt.src_format & 0x0010) && (original_len & 1)) {
   240             original_len--;
   241         }
   242         music->cvt.len = original_len;
   243         SDL_ConvertAudio(&music->cvt);
   244         SDL_MixAudioFormat(stream, music->cvt.buf, mixer.format,music->cvt.len_cvt, wavestream_volume);
   245         consumed = music->cvt.len_cvt;
   246     } else {
   247         Uint8 *data;
   248         if ((stop - pos) < len) {
   249             len = (int)(stop - pos);
   250         }
   251         data = SDL_stack_alloc(Uint8, len);
   252         if (data) {
   253             len = SDL_RWread(music->src, data, 1, len);
   254             SDL_MixAudioFormat(stream, data, mixer.format, len, wavestream_volume);
   255             SDL_stack_free(data);
   256         }
   257         consumed = len;
   258     }
   259 
   260     if (loop && SDL_RWtell(music->src) >= stop) {
   261         if (loop->current_play_count == 1) {
   262             loop->active = SDL_FALSE;
   263         } else {
   264             if (loop->current_play_count > 0) {
   265                 --loop->current_play_count;
   266             }
   267             SDL_RWseek(music->src, loop_start, RW_SEEK_SET);
   268         }
   269     }
   270     return consumed;
   271 }
   272 
   273 int WAVStream_PlaySome(Uint8 *stream, int len)
   274 {
   275     if (!music)
   276         return 0;
   277 
   278     while ((SDL_RWtell(music->src) < music->stop) && (len > 0)) {
   279         int consumed = PlaySome(stream, len);
   280         if (!consumed)
   281             break;
   282 
   283         stream += consumed;
   284         len -= consumed;
   285     }
   286     return len;
   287 }
   288 
   289 /* Stop playback of a stream previously started with WAVStream_Start() */
   290 void WAVStream_Stop(void)
   291 {
   292     music = NULL;
   293 }
   294 
   295 /* Close the given WAV stream */
   296 void WAVStream_FreeSong(WAVStream *wave)
   297 {
   298     if (wave) {
   299         /* Clean up associated data */
   300         if (wave->loops) {
   301             SDL_free(wave->loops);
   302         }
   303         if (wave->cvt.buf) {
   304             SDL_free(wave->cvt.buf);
   305         }
   306         if (wave->freesrc) {
   307             SDL_RWclose(wave->src);
   308         }
   309         SDL_free(wave);
   310     }
   311 }
   312 
   313 /* Return non-zero if a stream is currently playing */
   314 int WAVStream_Active(void)
   315 {
   316     int active;
   317 
   318     active = 0;
   319     if (music && (SDL_RWtell(music->src) < music->stop)) {
   320         active = 1;
   321     }
   322     return(active);
   323 }
   324 
   325 static SDL_bool ParseFMT(WAVStream *wave, Uint32 chunk_length)
   326 {
   327     SDL_RWops *src = wave->src;
   328     SDL_AudioSpec *spec = &wave->spec;
   329     WaveFMT *format;
   330     Uint8 *data;
   331     SDL_bool loaded = SDL_FALSE;
   332 
   333     if (chunk_length < sizeof(*format)) {
   334         Mix_SetError("Wave format chunk too small");
   335         return SDL_FALSE;
   336     }
   337 
   338     data = (Uint8 *)SDL_malloc(chunk_length);
   339     if (!data) {
   340         Mix_SetError("Out of memory");
   341         return SDL_FALSE;
   342     }
   343     if (!SDL_RWread(wave->src, data, chunk_length, 1)) {
   344         Mix_SetError("Couldn't read %d bytes from WAV file", chunk_length);
   345         return SDL_FALSE;
   346     }
   347     format = (WaveFMT *)data;
   348 
   349     /* Decode the audio data format */
   350     switch (SDL_SwapLE16(format->encoding)) {
   351         case PCM_CODE:
   352             /* We can understand this */
   353             break;
   354         default:
   355             Mix_SetError("Unknown WAVE data format");
   356             goto done;
   357     }
   358     spec->freq = SDL_SwapLE32(format->frequency);
   359     switch (SDL_SwapLE16(format->bitspersample)) {
   360         case 8:
   361             spec->format = AUDIO_U8;
   362             break;
   363         case 16:
   364             spec->format = AUDIO_S16;
   365             break;
   366         default:
   367             Mix_SetError("Unknown PCM data format");
   368             goto done;
   369     }
   370     spec->channels = (Uint8) SDL_SwapLE16(format->channels);
   371     spec->samples = 4096;       /* Good default buffer size */
   372 
   373     loaded = SDL_TRUE;
   374 
   375 done:
   376     SDL_free(data);
   377     return loaded;
   378 }
   379 
   380 static SDL_bool ParseDATA(WAVStream *wave, Uint32 chunk_length)
   381 {
   382     wave->start = SDL_RWtell(wave->src);
   383     wave->stop = wave->start + chunk_length;
   384     SDL_RWseek(wave->src, chunk_length, RW_SEEK_CUR);
   385     return SDL_TRUE;
   386 }
   387 
   388 static SDL_bool AddLoopPoint(WAVStream *wave, Uint32 play_count, Uint32 start, Uint32 stop)
   389 {
   390     WAVLoopPoint *loop;
   391     WAVLoopPoint *loops = SDL_realloc(wave->loops, (wave->numloops + 1)*sizeof(*wave->loops));
   392     if (!loops) {
   393         Mix_SetError("Out of memory");
   394         return SDL_FALSE;
   395     }
   396 
   397     loop = &loops[ wave->numloops ];
   398     loop->start = start;
   399     loop->stop = stop;
   400     loop->initial_play_count = play_count;
   401     loop->current_play_count = play_count;
   402 
   403     wave->loops = loops;
   404     ++wave->numloops;
   405     return SDL_TRUE;
   406 }
   407 
   408 static SDL_bool ParseSMPL(WAVStream *wave, Uint32 chunk_length)
   409 {
   410     SamplerChunk *chunk;
   411     Uint8 *data;
   412     int i;
   413     SDL_bool loaded = SDL_FALSE;
   414 
   415     data = (Uint8 *)SDL_malloc(chunk_length);
   416     if (!data) {
   417         Mix_SetError("Out of memory");
   418         return SDL_FALSE;
   419     }
   420     if (!SDL_RWread(wave->src, data, chunk_length, 1)) {
   421         Mix_SetError("Couldn't read %d bytes from WAV file", chunk_length);
   422         return SDL_FALSE;
   423     }
   424     chunk = (SamplerChunk *)data;
   425 
   426     for (i = 0; i < SDL_SwapLE32(chunk->sample_loops); ++i) {
   427         const Uint32 LOOP_TYPE_FORWARD = 0;
   428         Uint32 loop_type = SDL_SwapLE32(chunk->loops[i].type);
   429         if (loop_type == LOOP_TYPE_FORWARD) {
   430             AddLoopPoint(wave, SDL_SwapLE32(chunk->loops[i].play_count), SDL_SwapLE32(chunk->loops[i].start), SDL_SwapLE32(chunk->loops[i].end));
   431         }
   432     }
   433 
   434     loaded = SDL_TRUE;
   435 
   436 done:
   437     SDL_free(data);
   438     return loaded;
   439 }
   440 
   441 static SDL_bool LoadWAVStream(WAVStream *wave)
   442 {
   443     SDL_RWops *src = wave->src;
   444     Uint32 chunk_type;
   445     Uint32 chunk_length;
   446     SDL_bool found_FMT = SDL_FALSE;
   447     SDL_bool found_DATA = SDL_FALSE;
   448 
   449     /* WAV magic header */
   450     Uint32 wavelen;
   451     Uint32 WAVEmagic;
   452 
   453     /* Check the magic header */
   454     wavelen = SDL_ReadLE32(src);
   455     WAVEmagic = SDL_ReadLE32(src);
   456 
   457     /* Read the chunks */
   458     for (; ;) {
   459         chunk_type = SDL_ReadLE32(src);
   460         chunk_length = SDL_ReadLE32(src);
   461 
   462         if (chunk_length == 0)
   463             break;
   464 
   465         switch (chunk_type)
   466         {
   467         case FMT:
   468             found_FMT = SDL_TRUE;
   469             if (!ParseFMT(wave, chunk_length))
   470                 return SDL_FALSE;
   471             break;
   472         case DATA:
   473             found_DATA = SDL_TRUE;
   474             if (!ParseDATA(wave, chunk_length))
   475                 return SDL_FALSE;
   476             break;
   477         case SMPL:
   478             if (!ParseSMPL(wave, chunk_length))
   479                 return SDL_FALSE;
   480             break;
   481         default:
   482             SDL_RWseek(src, chunk_length, RW_SEEK_CUR);
   483             break;
   484         }
   485     }
   486 
   487     if (!found_FMT) {
   488         Mix_SetError("Bad WAV file (no FMT chunk)");
   489         return SDL_FALSE;
   490     }
   491 
   492     if (!found_DATA) {
   493         Mix_SetError("Bad WAV file (no DATA chunk)");
   494         return SDL_FALSE;
   495     }
   496 
   497     return SDL_TRUE;
   498 }
   499 
   500 /* I couldn't get SANE_to_double() to work, so I stole this from libsndfile.
   501  * I don't pretend to fully understand it.
   502  */
   503 
   504 static Uint32 SANE_to_Uint32 (Uint8 *sanebuf)
   505 {
   506     /* Negative number? */
   507     if (sanebuf[0] & 0x80)
   508         return 0;
   509 
   510     /* Less than 1? */
   511     if (sanebuf[0] <= 0x3F)
   512         return 1;
   513 
   514     /* Way too big? */
   515     if (sanebuf[0] > 0x40)
   516         return 0x4000000;
   517 
   518     /* Still too big? */
   519     if (sanebuf[0] == 0x40 && sanebuf[1] > 0x1C)
   520         return 800000000;
   521 
   522     return ((sanebuf[2] << 23) | (sanebuf[3] << 15) | (sanebuf[4] << 7) |
   523             (sanebuf[5] >> 1)) >> (29 - sanebuf[1]);
   524 }
   525 
   526 static SDL_bool LoadAIFFStream(WAVStream *wave)
   527 {
   528     SDL_RWops *src = wave->src;
   529     SDL_AudioSpec *spec = &wave->spec;
   530     SDL_bool found_SSND = SDL_FALSE;
   531     SDL_bool found_COMM = SDL_FALSE;
   532 
   533     Uint32 chunk_type;
   534     Uint32 chunk_length;
   535     Sint64 next_chunk;
   536 
   537     /* AIFF magic header */
   538     Uint32 AIFFmagic;
   539     /* SSND chunk        */
   540     Uint32 offset;
   541     Uint32 blocksize;
   542     /* COMM format chunk */
   543     Uint16 channels = 0;
   544     Uint32 numsamples = 0;
   545     Uint16 samplesize = 0;
   546     Uint8 sane_freq[10];
   547     Uint32 frequency = 0;
   548 
   549     /* Check the magic header */
   550     chunk_length = SDL_ReadBE32(src);
   551     AIFFmagic = SDL_ReadLE32(src);
   552     if (AIFFmagic != AIFF) {
   553         Mix_SetError("Unrecognized file type (not AIFF)");
   554         return SDL_FALSE;
   555     }
   556 
   557     /* From what I understand of the specification, chunks may appear in
   558      * any order, and we should just ignore unknown ones.
   559      *
   560      * TODO: Better sanity-checking. E.g. what happens if the AIFF file
   561      *       contains compressed sound data?
   562      */
   563     do {
   564         chunk_type      = SDL_ReadLE32(src);
   565         chunk_length    = SDL_ReadBE32(src);
   566         next_chunk      = SDL_RWtell(src) + chunk_length;
   567 
   568         /* Paranoia to avoid infinite loops */
   569         if (chunk_length == 0)
   570             break;
   571 
   572         switch (chunk_type) {
   573         case SSND:
   574             found_SSND = SDL_TRUE;
   575             offset = SDL_ReadBE32(src);
   576             blocksize = SDL_ReadBE32(src);
   577             wave->start = SDL_RWtell(src) + offset;
   578             break;
   579 
   580         case COMM:
   581             found_COMM = SDL_TRUE;
   582 
   583             /* Read the audio data format chunk */
   584             channels = SDL_ReadBE16(src);
   585             numsamples = SDL_ReadBE32(src);
   586             samplesize = SDL_ReadBE16(src);
   587             SDL_RWread(src, sane_freq, sizeof(sane_freq), 1);
   588             frequency = SANE_to_Uint32(sane_freq);
   589             break;
   590 
   591         default:
   592             break;
   593         }
   594     } while ((!found_SSND || !found_COMM)
   595          && SDL_RWseek(src, next_chunk, RW_SEEK_SET) != -1);
   596 
   597     if (!found_SSND) {
   598         Mix_SetError("Bad AIFF file (no SSND chunk)");
   599         return SDL_FALSE;
   600     }
   601 
   602     if (!found_COMM) {
   603         Mix_SetError("Bad AIFF file (no COMM chunk)");
   604         return SDL_FALSE;
   605     }
   606 
   607     wave->stop = wave->start + channels * numsamples * (samplesize / 8);
   608 
   609     /* Decode the audio data format */
   610     SDL_memset(spec, 0, (sizeof *spec));
   611     spec->freq = frequency;
   612     switch (samplesize) {
   613         case 8:
   614             spec->format = AUDIO_S8;
   615             break;
   616         case 16:
   617             spec->format = AUDIO_S16MSB;
   618             break;
   619         default:
   620             Mix_SetError("Unknown samplesize in data format");
   621             return SDL_FALSE;
   622     }
   623     spec->channels = (Uint8) channels;
   624     spec->samples = 4096;       /* Good default buffer size */
   625 
   626     return SDL_TRUE;
   627 }
   628