music_smpeg.c
author Sam Lantinga <slouken@libsdl.org>
Sat, 21 Oct 2017 14:40:31 -0700
changeset 823 bcd59adacdcc
parent 798 9b6d7d1b3a23
child 848 3907db698eb5
permissions -rw-r--r--
Fixed linker order so -lmingw32 comes before -lSDL2main
     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 MUSIC_MP3_SMPEG
    23 
    24 #include "SDL_loadso.h"
    25 
    26 #include "music_smpeg.h"
    27 
    28 #if SDL_VERSION_ATLEAST(2, 0, 0)
    29 /* Forward declaration for SDL 2.0  because struct is not available there but
    30    still used in a file included with smpeg.h. May not compile if missing. */
    31 typedef struct SDL_Overlay SDL_Overlay;
    32 #endif
    33 
    34 #include "smpeg.h"
    35 
    36 typedef struct {
    37     int loaded;
    38     void *handle;
    39     void (*SMPEG_actualSpec)(SMPEG *mpeg, SDL_AudioSpec *spec);
    40     void (*SMPEG_delete)(SMPEG* mpeg);
    41     void (*SMPEG_enableaudio)(SMPEG* mpeg, int enable);
    42     void (*SMPEG_enablevideo)(SMPEG* mpeg, int enable);
    43     SMPEG* (*SMPEG_new_rwops)(SDL_RWops *src, SMPEG_Info* info, int freesrc, int sdl_audio);
    44     void (*SMPEG_play)(SMPEG* mpeg);
    45     int (*SMPEG_playAudio)(SMPEG *mpeg, Uint8 *stream, int len);
    46     void (*SMPEG_rewind)(SMPEG* mpeg);
    47     void (*SMPEG_setvolume)(SMPEG* mpeg, int volume);
    48     void (*SMPEG_skip)(SMPEG* mpeg, float seconds);
    49     SMPEGstatus (*SMPEG_status)(SMPEG* mpeg);
    50     void (*SMPEG_stop)(SMPEG* mpeg);
    51 } smpeg_loader;
    52 
    53 static smpeg_loader smpeg = {
    54     0, NULL
    55 };
    56 
    57 #ifdef SMPEG_DYNAMIC
    58 #define FUNCTION_LOADER(FUNC, SIG) \
    59     smpeg.FUNC = (SIG) SDL_LoadFunction(smpeg.handle, #FUNC); \
    60     if (smpeg.FUNC == NULL) { SDL_UnloadObject(smpeg.handle); return -1; }
    61 #else
    62 #define FUNCTION_LOADER(FUNC, SIG) \
    63     smpeg.FUNC = FUNC;
    64 #endif
    65 
    66 static int SMPEG_Load(void)
    67 {
    68     if (smpeg.loaded == 0) {
    69 #ifdef SMPEG_DYNAMIC
    70         smpeg.handle = SDL_LoadObject(SMPEG_DYNAMIC);
    71         if (smpeg.handle == NULL) {
    72             return -1;
    73         }
    74 #elif defined(__MACOSX__)
    75         extern SMPEG* SMPEG_new_rwops(SDL_RWops*, SMPEG_Info*, int, int) __attribute__((weak_import));
    76         if (SMPEG_new_rwops == NULL)
    77         {
    78             /* Missing weakly linked framework */
    79             Mix_SetError("Missing smpeg2.framework");
    80             return -1;
    81         }
    82 #endif
    83         FUNCTION_LOADER(SMPEG_actualSpec, void (*)(SMPEG *, SDL_AudioSpec *))
    84         FUNCTION_LOADER(SMPEG_delete, void (*)(SMPEG*))
    85         FUNCTION_LOADER(SMPEG_enableaudio, void (*)(SMPEG*, int))
    86         FUNCTION_LOADER(SMPEG_enablevideo, void (*)(SMPEG*, int))
    87         FUNCTION_LOADER(SMPEG_new_rwops, SMPEG* (*)(SDL_RWops *, SMPEG_Info*, int, int))
    88         FUNCTION_LOADER(SMPEG_play, void (*)(SMPEG*))
    89         FUNCTION_LOADER(SMPEG_playAudio, int (*)(SMPEG *, Uint8 *, int))
    90         FUNCTION_LOADER(SMPEG_rewind, void (*)(SMPEG*))
    91         FUNCTION_LOADER(SMPEG_setvolume, void (*)(SMPEG*, int))
    92         FUNCTION_LOADER(SMPEG_skip, void (*)(SMPEG*, float))
    93         FUNCTION_LOADER(SMPEG_status, SMPEGstatus (*)(SMPEG*))
    94         FUNCTION_LOADER(SMPEG_stop, void (*)(SMPEG*))
    95     }
    96     ++smpeg.loaded;
    97 
    98     return 0;
    99 }
   100 
   101 static void SMPEG_Unload(void)
   102 {
   103     if (smpeg.loaded == 0) {
   104         return;
   105     }
   106     if (smpeg.loaded == 1) {
   107 #ifdef SMPEG_DYNAMIC
   108         SDL_UnloadObject(smpeg.handle);
   109 #endif
   110     }
   111     --smpeg.loaded;
   112 }
   113 
   114 
   115 typedef struct
   116 {
   117     SMPEG *mp3;
   118     SDL_RWops *src;
   119     int freesrc;
   120 } SMPEG_Music;
   121 
   122 static void *SMPEG_CreateFromRW(SDL_RWops *src, int freesrc)
   123 {
   124     SMPEG_Music *music;
   125     SMPEG_Info info;
   126 
   127     music = (SMPEG_Music *)SDL_calloc(1, sizeof(*music));
   128     if (!music) {
   129         SDL_OutOfMemory();
   130         return NULL;
   131     }
   132     music->src = src;
   133 
   134     music->mp3 = smpeg.SMPEG_new_rwops(src, &info, SDL_FALSE, 0);
   135     if (!info.has_audio) {
   136         Mix_SetError("MPEG file does not have any audio stream.");
   137         smpeg.SMPEG_delete(music->mp3);
   138         SDL_free(music);
   139         return NULL;
   140     }
   141     smpeg.SMPEG_actualSpec(mp3, &music_spec);
   142 
   143     music->freesrc = freesrc;
   144     return music;
   145 }
   146 
   147 static void SMPEG_SetVolume(void *context, int volume)
   148 {
   149     SMPEG_Music *music = (SMPEG_Music *)context;
   150     smpeg.SMPEG_setvolume(music->mp3,(int)(((float)volume/(float)MIX_MAX_VOLUME)*100.0));
   151 }
   152 
   153 static int SMPEG_Play(void *context)
   154 {
   155     SMPEG_Music *music = (SMPEG_Music *)context;
   156     smpeg.SMPEG_enableaudio(music->mp3, 1);
   157     smpeg.SMPEG_enablevideo(music->mp3, 0);
   158     smpeg.SMPEG_rewind(music->mp3);
   159     smpeg.SMPEG_play(music->mp3);
   160     return 0;
   161 }
   162 
   163 static SDL_bool SMPEG_IsPlaying(void *context)
   164 {
   165     SMPEG_Music *music = (SMPEG_Music *)context;
   166     return smpeg.SMPEG_status(music->mp3) == SMPEG_PLAYING ? SDL_TRUE : SDL_FALSE;
   167 }
   168 
   169 static int SMPEG_GetAudio(void *context, void *data, int bytes)
   170 {
   171     SMPEG_Music *music = (SMPEG_Music *)context;
   172     Uint8 *stream = (Uint8 *)data;
   173     int len = bytes;
   174     int left = (len - smpeg.SMPEG_playAudio(music->mp3, stream, len));
   175     if (left > 0) {
   176         stream += (len - left);
   177     return left;
   178 }
   179 
   180 static int SMPEG_Seek(void *context, double position)
   181 {
   182     SMPEG_Music *music = (SMPEG_Music *)context;
   183     smpeg.SMPEG_rewind(music->mp3);
   184     smpeg.SMPEG_play(music->mp3);
   185     if (position > 0.0) {
   186         smpeg.SMPEG_skip(music->mp3, (float)position);
   187     }
   188     return 0;
   189 }
   190 
   191 static void SMPEG_Stop(void *context)
   192 {
   193     SMPEG_Music *music = (SMPEG_Music *)context;
   194     smpeg.SMPEG_stop(music->mp3);
   195 }
   196 
   197 static void SMPEG_Delete(void *context)
   198 {
   199     SMPEG_Music *music = (SMPEG_Music *)context;
   200 
   201     smpeg.SMPEG_delete(music->mp3);
   202 
   203     if (music->freesrc) {
   204         SDL_RWclose(music->src);
   205     }
   206     SDL_free(music);
   207 }
   208 
   209 Mix_MusicInterface Mix_MusicInterface_SMPEG =
   210 {
   211     "SMPEG",
   212     MIX_MUSIC_SMPEG,
   213     MUS_MP3,
   214     SDL_FALSE,
   215     SDL_FALSE,
   216 
   217     SMPEG_Load,
   218     NULL,   /* Open */
   219     SMPEG_CreateFromRW,
   220     NULL,   /* CreateFromFile */
   221     SMPEG_SetVolume,
   222     SMPEG_Play,
   223     SMPEG_IsPlaying,
   224     SMPEG_GetAudio,
   225     SMPEG_Seek,
   226     NULL,   /* Pause */
   227     NULL,   /* Resume */
   228     SMPEG_Stop,
   229     SMPEG_Delete,
   230     NULL,   /* Close */
   231     SMPEG_Unload,
   232 };
   233 
   234 #endif /* MUSIC_MP3_SMPEG */
   235 
   236 /* vi: set ts=4 sw=4 expandtab: */