music_mpg.c
changeset 757 420f3b37dc95
equal deleted inserted replaced
756:db4027cbc804 757:420f3b37dc95
       
     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 #ifdef MP3_MPG_MUSIC
       
    23 
       
    24 #include "SDL_mixer.h"
       
    25 #include "music_mpg.h"
       
    26 
       
    27 static
       
    28 int
       
    29 snd_format_to_mpg123(uint16_t sdl_fmt)
       
    30 {
       
    31     switch (sdl_fmt)
       
    32     {
       
    33         case AUDIO_U8:     return MPG123_ENC_UNSIGNED_8;
       
    34         case AUDIO_U16SYS: return MPG123_ENC_UNSIGNED_16;
       
    35         case AUDIO_S8:     return MPG123_ENC_SIGNED_8;
       
    36         case AUDIO_S16SYS: return MPG123_ENC_SIGNED_16;
       
    37         case AUDIO_S32SYS: return MPG123_ENC_SIGNED_32;
       
    38     }
       
    39 
       
    40     return -1;
       
    41 }
       
    42 
       
    43 static
       
    44 Uint16
       
    45 mpg123_format_to_sdl(int fmt)
       
    46 {
       
    47     switch (fmt)
       
    48     {
       
    49         case MPG123_ENC_UNSIGNED_8:  return AUDIO_U8;
       
    50         case MPG123_ENC_UNSIGNED_16: return AUDIO_U16SYS;
       
    51         case MPG123_ENC_SIGNED_8:    return AUDIO_S8;
       
    52         case MPG123_ENC_SIGNED_16:   return AUDIO_S16SYS;
       
    53         case MPG123_ENC_SIGNED_32:   return AUDIO_S32SYS;
       
    54     }
       
    55 
       
    56     return -1;
       
    57 }
       
    58 
       
    59 static
       
    60 char const*
       
    61 mpg123_format_str(int fmt)
       
    62 {
       
    63     switch (fmt)
       
    64     {
       
    65 #define f(x) case x: return #x;
       
    66         f(MPG123_ENC_UNSIGNED_8)
       
    67         f(MPG123_ENC_UNSIGNED_16)
       
    68         f(MPG123_ENC_SIGNED_8)
       
    69         f(MPG123_ENC_SIGNED_16)
       
    70         f(MPG123_ENC_SIGNED_32)
       
    71 #undef f
       
    72     }
       
    73 
       
    74     return "unknown";
       
    75 }
       
    76 
       
    77 static
       
    78 char const*
       
    79 mpg_err(mpg123_handle* mpg, int code)
       
    80 {
       
    81     char const* err = "unknown error";
       
    82 
       
    83     if (mpg && code == MPG123_ERR) {
       
    84         err = mpg123_strerror(mpg);
       
    85     } else {
       
    86         err = mpg123_plain_strerror(code);
       
    87     }
       
    88 
       
    89     return err;
       
    90 }
       
    91 
       
    92 /* we're gonna override mpg123's I/O with these wrappers for RWops */
       
    93 static
       
    94 ssize_t rwops_read(void* p, void* dst, size_t n) {
       
    95     return (ssize_t)SDL_RWread((SDL_RWops*)p, dst, 1, n);
       
    96 }
       
    97 
       
    98 static
       
    99 off_t rwops_seek(void* p, off_t offset, int whence) {
       
   100     return (off_t)SDL_RWseek((SDL_RWops*)p, (Sint64)offset, whence);
       
   101 }
       
   102 
       
   103 static
       
   104 void rwops_cleanup(void* p) {
       
   105     (void)p;
       
   106     /* do nothing, we will free the file later */
       
   107 }
       
   108 
       
   109 static int getsome(mpg_data* m);
       
   110 
       
   111 mpg_data*
       
   112 mpg_new_rw(SDL_RWops *src, SDL_AudioSpec* mixer, int freesrc)
       
   113 {
       
   114     mpg_data* m;
       
   115     int result;
       
   116     int fmt;
       
   117 
       
   118     if (!Mix_Init(MIX_INIT_MP3)) {
       
   119         return(NULL);
       
   120     }
       
   121 
       
   122     m = (mpg_data*)SDL_malloc(sizeof(mpg_data));
       
   123     if (!m) {
       
   124         return 0;
       
   125     }
       
   126 
       
   127     SDL_memset(m, 0, sizeof(mpg_data));
       
   128 
       
   129     m->src = src;
       
   130     m->freesrc = freesrc;
       
   131 
       
   132     m->handle = mpg123_new(0, &result);
       
   133     if (result != MPG123_OK) {
       
   134         return 0;
       
   135     }
       
   136 
       
   137     result = mpg123_replace_reader_handle(
       
   138         m->handle,
       
   139         rwops_read, rwops_seek, rwops_cleanup
       
   140     );
       
   141     if (result != MPG123_OK) {
       
   142         return 0;
       
   143     }
       
   144 
       
   145     result = mpg123_format_none(m->handle);
       
   146     if (result != MPG123_OK) {
       
   147         return 0;
       
   148     }
       
   149 
       
   150     fmt = snd_format_to_mpg123(mixer->format);
       
   151     if (fmt == -1) {
       
   152         return 0;
       
   153     }
       
   154 
       
   155     result =  mpg123_format(m->handle, mixer->freq, mixer->channels, fmt);
       
   156     if (result != MPG123_OK) {
       
   157         return 0;
       
   158     }
       
   159 
       
   160     result = mpg123_open_handle(m->handle, m->src);
       
   161     if (result != MPG123_OK) {
       
   162         return 0;
       
   163     }
       
   164 
       
   165     m->volume = MIX_MAX_VOLUME;
       
   166     m->mixer = *mixer;
       
   167 
       
   168     /* hacky: read until we can figure out the format then rewind */
       
   169     while (!m->gotformat)
       
   170     {
       
   171         if (!getsome(m)) {
       
   172             return 0;
       
   173         }
       
   174     }
       
   175 
       
   176     /* rewind */
       
   177     mpg123_seek(m->handle, 0, SEEK_SET);
       
   178 
       
   179     m->len_available = 0;
       
   180     m->snd_available = m->cvt.buf;
       
   181 
       
   182     return m;
       
   183 }
       
   184 
       
   185 void
       
   186 mpg_delete(mpg_data* m)
       
   187 {
       
   188     if (!m) {
       
   189         return;
       
   190     }
       
   191 
       
   192     if (m->freesrc) {
       
   193         SDL_RWclose(m->src);
       
   194     }
       
   195 
       
   196     if (m->cvt.buf) {
       
   197         SDL_free(m->cvt.buf);
       
   198     }
       
   199 
       
   200     mpg123_close(m->handle);
       
   201     mpg123_delete(m->handle);
       
   202     SDL_free(m);
       
   203 }
       
   204 
       
   205 void
       
   206 mpg_start(mpg_data* m) {
       
   207     m->playing = 1;
       
   208 }
       
   209 
       
   210 void
       
   211 mpg_stop(mpg_data* m) {
       
   212     m->playing = 0;
       
   213 }
       
   214 
       
   215 int
       
   216 mpg_playing(mpg_data* m) {
       
   217     return m->playing;
       
   218 }
       
   219 
       
   220 /*
       
   221     updates the convert struct and buffer to match the format queried from
       
   222     mpg123.
       
   223 */
       
   224 static
       
   225 int
       
   226 update_format(mpg_data* m)
       
   227 {
       
   228     int code;
       
   229     long rate;
       
   230     int channels, encoding;
       
   231     Uint16 sdlfmt;
       
   232     size_t bufsize;
       
   233 
       
   234     m->gotformat = 1;
       
   235 
       
   236     code =
       
   237         mpg123_getformat(
       
   238             m->handle,
       
   239             &rate, &channels, &encoding
       
   240         );
       
   241 
       
   242     if (code != MPG123_OK) {
       
   243         SDL_SetError("mpg123_getformat: %s", mpg_err(m->handle, code));
       
   244         return 0;
       
   245     }
       
   246 
       
   247     sdlfmt = mpg123_format_to_sdl(encoding);
       
   248     if (sdlfmt == (Uint16)-1)
       
   249     {
       
   250         SDL_SetError(
       
   251             "Format %s is not supported by SDL",
       
   252             mpg123_format_str(encoding)
       
   253         );
       
   254         return 0;
       
   255     }
       
   256 
       
   257     SDL_BuildAudioCVT(
       
   258         &m->cvt,
       
   259         sdlfmt, channels, rate,
       
   260         m->mixer.format,
       
   261         m->mixer.channels,
       
   262         m->mixer.freq
       
   263     );
       
   264 
       
   265     if (m->cvt.buf) {
       
   266         SDL_free(m->cvt.buf);
       
   267     }
       
   268 
       
   269     bufsize = sizeof(m->buf) * m->cvt.len_mult;
       
   270     m->cvt.buf = SDL_malloc(bufsize);
       
   271 
       
   272     if (!m->cvt.buf)
       
   273     {
       
   274         SDL_SetError("Out of memory");
       
   275         mpg_stop(m);
       
   276         return 0;
       
   277     }
       
   278 
       
   279     return 1;
       
   280 }
       
   281 
       
   282 /* read some mp3 stream data and convert it for output */
       
   283 static
       
   284 int
       
   285 getsome(mpg_data* m)
       
   286 {
       
   287     int code;
       
   288     size_t len;
       
   289     Uint8* data = m->buf;
       
   290     size_t cbdata = sizeof(m->buf);
       
   291     SDL_AudioCVT* cvt = &m->cvt;
       
   292 
       
   293     do
       
   294     {
       
   295         code = mpg123_read(m->handle, data, sizeof(data), &len);
       
   296         switch (code)
       
   297         {
       
   298             case MPG123_NEW_FORMAT:
       
   299                 if (!update_format(m)) {
       
   300                     return 0;
       
   301                 }
       
   302                 break;
       
   303 
       
   304             case MPG123_DONE:
       
   305                 mpg_stop(m);
       
   306             case MPG123_OK:
       
   307                 break;
       
   308 
       
   309             default:
       
   310                 SDL_SetError("mpg123_read: %s", mpg_err(m->handle, code));
       
   311                 return 0;
       
   312         }
       
   313     }
       
   314     while (len && code != MPG123_OK);
       
   315 
       
   316     SDL_memcpy(cvt->buf, data, cbdata);
       
   317 
       
   318     if (cvt->needed) {
       
   319         /* we need to convert the audio to SDL's format */
       
   320         cvt->len = len;
       
   321         SDL_ConvertAudio(cvt);
       
   322     }
       
   323 
       
   324     else {
       
   325         /* no conversion needed, just copy */
       
   326         cvt->len_cvt = len;
       
   327     }
       
   328 
       
   329     m->len_available = cvt->len_cvt;
       
   330     m->snd_available = cvt->buf;
       
   331 
       
   332     return 1;
       
   333 }
       
   334 
       
   335 int
       
   336 mpg_get_samples(mpg_data* m, Uint8 *stream, int len)
       
   337 {
       
   338     int mixable;
       
   339 
       
   340     while (len > 0 && m->playing)
       
   341     {
       
   342         if (!m->len_available)
       
   343         {
       
   344             if (!getsome(m)) {
       
   345                 m->playing = 0;
       
   346                 return len;
       
   347             }
       
   348         }
       
   349 
       
   350         mixable = len;
       
   351 
       
   352         if (mixable > m->len_available) {
       
   353             mixable = m->len_available;
       
   354         }
       
   355 
       
   356         if (m->volume == MIX_MAX_VOLUME) {
       
   357             SDL_memcpy(stream, m->snd_available, mixable);
       
   358         }
       
   359 
       
   360         else
       
   361         {
       
   362             SDL_MixAudioFormat(
       
   363                 stream,
       
   364                 m->snd_available,
       
   365                 m->mixer.format,
       
   366                 mixable,
       
   367                 m->volume
       
   368             );
       
   369         }
       
   370 
       
   371         m->len_available -= mixable;
       
   372         m->snd_available += mixable;
       
   373         len -= mixable;
       
   374         stream += mixable;
       
   375     }
       
   376 
       
   377     return len;
       
   378 }
       
   379 
       
   380 void
       
   381 mpg_seek(mpg_data* m, double secs)
       
   382 {
       
   383     off_t offset = m->mixer.freq * secs;
       
   384 
       
   385     if ((offset = mpg123_seek(m->handle, offset, SEEK_SET)) < 0) {
       
   386         SDL_SetError("mpg123_seek: %s", mpg_err(m->handle, -offset));
       
   387     }
       
   388 }
       
   389 
       
   390 void
       
   391 mpg_volume(mpg_data* m, int volume) {
       
   392     m->volume = volume;
       
   393 }
       
   394 
       
   395 
       
   396 #endif    /* MP3_MPG_MUSIC */