music_wav.c
author Ozkan Sezer <sezeroz@gmail.com>
Wed, 03 Oct 2018 21:55:00 +0300
changeset 863 b81eb791d10d
parent 848 3907db698eb5
child 926 d6c9518fb5ee
permissions -rw-r--r--
readmidi.c (groom_list): avoid integer overflow when recomputing time.

from libtimidity -- see:
https://sourceforge.net/p/libtimidity/libtimidity/ci/11be98a89eac229111420e6a3d521edbfddb0dbc/
     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: */