music_fluidsynth.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   James Le Cuirot
    22   chewi@aura-online.co.uk
    23 */
    24 
    25 #ifdef MUSIC_MID_FLUIDSYNTH
    26 
    27 #include <stdio.h>
    28 
    29 #include "SDL_loadso.h"
    30 
    31 #include "music_fluidsynth.h"
    32 
    33 #include <fluidsynth.h>
    34 
    35 
    36 typedef struct {
    37     int loaded;
    38     void *handle;
    39 
    40     int (*delete_fluid_player)(fluid_player_t*);
    41     void (*delete_fluid_settings)(fluid_settings_t*);
    42     int (*delete_fluid_synth)(fluid_synth_t*);
    43     int (*fluid_player_add)(fluid_player_t*, const char*);
    44     int (*fluid_player_add_mem)(fluid_player_t*, const void*, size_t);
    45     int (*fluid_player_get_status)(fluid_player_t*);
    46     int (*fluid_player_play)(fluid_player_t*);
    47     int (*fluid_player_set_loop)(fluid_player_t*, int);
    48     int (*fluid_player_stop)(fluid_player_t*);
    49     int (*fluid_settings_setnum)(fluid_settings_t*, const char*, double);
    50     fluid_settings_t* (*fluid_synth_get_settings)(fluid_synth_t*);
    51     void (*fluid_synth_set_gain)(fluid_synth_t*, float);
    52     int (*fluid_synth_sfload)(fluid_synth_t*, const char*, int);
    53     int (*fluid_synth_write_s16)(fluid_synth_t*, int, void*, int, int, void*, int, int);
    54     fluid_player_t* (*new_fluid_player)(fluid_synth_t*);
    55     fluid_settings_t* (*new_fluid_settings)(void);
    56     fluid_synth_t* (*new_fluid_synth)(fluid_settings_t*);
    57 } fluidsynth_loader;
    58 
    59 static fluidsynth_loader fluidsynth = {
    60     0, NULL
    61 };
    62 
    63 #ifdef FLUIDSYNTH_DYNAMIC
    64 #define FUNCTION_LOADER(FUNC, SIG) \
    65     fluidsynth.FUNC = (SIG) SDL_LoadFunction(fluidsynth.handle, #FUNC); \
    66     if (fluidsynth.FUNC == NULL) { SDL_UnloadObject(fluidsynth.handle); return -1; }
    67 #else
    68 #define FUNCTION_LOADER(FUNC, SIG) \
    69     fluidsynth.FUNC = FUNC;
    70 #endif
    71 
    72 static int FLUIDSYNTH_Load()
    73 {
    74     if (fluidsynth.loaded == 0) {
    75 #ifdef FLUIDSYNTH_DYNAMIC
    76         fluidsynth.handle = SDL_LoadObject(FLUIDSYNTH_DYNAMIC);
    77         if (fluidsynth.handle == NULL) {
    78             return -1;
    79         }
    80 #endif
    81         FUNCTION_LOADER(delete_fluid_player, int (*)(fluid_player_t*))
    82         FUNCTION_LOADER(delete_fluid_settings, void (*)(fluid_settings_t*))
    83         FUNCTION_LOADER(delete_fluid_synth, int (*)(fluid_synth_t*))
    84         FUNCTION_LOADER(fluid_player_add, int (*)(fluid_player_t*, const char*))
    85         FUNCTION_LOADER(fluid_player_add_mem, int (*)(fluid_player_t*, const void*, size_t))
    86         FUNCTION_LOADER(fluid_player_get_status, int (*)(fluid_player_t*))
    87         FUNCTION_LOADER(fluid_player_play, int (*)(fluid_player_t*))
    88         FUNCTION_LOADER(fluid_player_set_loop, int (*)(fluid_player_t*, int))
    89         FUNCTION_LOADER(fluid_player_stop, int (*)(fluid_player_t*))
    90         FUNCTION_LOADER(fluid_settings_setnum, int (*)(fluid_settings_t*, const char*, double))
    91         FUNCTION_LOADER(fluid_synth_get_settings, fluid_settings_t* (*)(fluid_synth_t*))
    92         FUNCTION_LOADER(fluid_synth_set_gain, void (*)(fluid_synth_t*, float))
    93         FUNCTION_LOADER(fluid_synth_sfload, int(*)(fluid_synth_t*, const char*, int))
    94         FUNCTION_LOADER(fluid_synth_write_s16, int(*)(fluid_synth_t*, int, void*, int, int, void*, int, int))
    95         FUNCTION_LOADER(new_fluid_player, fluid_player_t* (*)(fluid_synth_t*))
    96         FUNCTION_LOADER(new_fluid_settings, fluid_settings_t* (*)(void))
    97         FUNCTION_LOADER(new_fluid_synth, fluid_synth_t* (*)(fluid_settings_t*))
    98     }
    99     ++fluidsynth.loaded;
   100 
   101     return 0;
   102 }
   103 
   104 static void FLUIDSYNTH_Unload()
   105 {
   106     if (fluidsynth.loaded == 0) {
   107         return;
   108     }
   109     if (fluidsynth.loaded == 1) {
   110 #ifdef FLUIDSYNTH_DYNAMIC
   111         SDL_UnloadObject(fluidsynth.handle);
   112 #endif
   113     }
   114     --fluidsynth.loaded;
   115 }
   116 
   117 
   118 typedef struct {
   119     fluid_synth_t *synth;
   120     fluid_player_t *player;
   121     SDL_AudioStream *stream;
   122     void *buffer;
   123     int buffer_size;
   124 } FLUIDSYNTH_Music;
   125 
   126 
   127 static int SDLCALL fluidsynth_check_soundfont(const char *path, void *data)
   128 {
   129     FILE *file = fopen(path, "r");
   130 
   131     if (file) {
   132         fclose(file);
   133         return 1;
   134     } else {
   135         Mix_SetError("Failed to access the SoundFont %s", path);
   136         return 0;
   137     }
   138 }
   139 
   140 static int SDLCALL fluidsynth_load_soundfont(const char *path, void *data)
   141 {
   142     /* If this fails, it's too late to try Timidity so pray that at least one works. */
   143     fluidsynth.fluid_synth_sfload((fluid_synth_t*) data, path, 1);
   144     return 1;
   145 }
   146 
   147 static int FLUIDSYNTH_Open(const SDL_AudioSpec *spec)
   148 {
   149     if (!Mix_EachSoundFont(fluidsynth_check_soundfont, NULL)) {
   150         return -1;
   151     }
   152     return 0;
   153 }
   154 
   155 static FLUIDSYNTH_Music *FLUIDSYNTH_LoadMusic(void *data)
   156 {
   157     SDL_RWops *src = (SDL_RWops *)data;
   158     FLUIDSYNTH_Music *music;
   159     fluid_settings_t *settings;
   160 
   161     if ((music = SDL_calloc(1, sizeof(FLUIDSYNTH_Music)))) {
   162         int channels = 2;
   163         if ((music->stream = SDL_NewAudioStream(AUDIO_S16SYS, channels, music_spec.freq, music_spec.format, music_spec.channels, music_spec.freq))) {
   164             music->buffer_size = music_spec.samples * sizeof(Sint16) * channels;
   165             if ((music->buffer = SDL_malloc(music->buffer_size))) {
   166                 if ((settings = fluidsynth.new_fluid_settings())) {
   167                     fluidsynth.fluid_settings_setnum(settings, "synth.sample-rate", (double) music_spec.freq);
   168 
   169                     if ((music->synth = fluidsynth.new_fluid_synth(settings))) {
   170                         if (Mix_EachSoundFont(fluidsynth_load_soundfont, (void*) music->synth)) {
   171                             if ((music->player = fluidsynth.new_fluid_player(music->synth))) {
   172                                 void *buffer;
   173                                 size_t size;
   174 
   175                                 buffer = SDL_LoadFile_RW(src, &size, SDL_FALSE);
   176                                 if (buffer) {
   177                                     if (fluidsynth.fluid_player_add_mem(music->player, buffer, size) == FLUID_OK) {
   178                                         SDL_free(buffer);
   179                                         return music;
   180                                     } else {
   181                                         Mix_SetError("FluidSynth failed to load in-memory song");
   182                                     }
   183                                     SDL_free(buffer);
   184                                 } else {
   185                                     SDL_OutOfMemory();
   186                                 }
   187                                 fluidsynth.delete_fluid_player(music->player);
   188                             } else {
   189                                 Mix_SetError("Failed to create FluidSynth player");
   190                             }
   191                         }
   192                         fluidsynth.delete_fluid_synth(music->synth);
   193                     } else {
   194                         Mix_SetError("Failed to create FluidSynth synthesizer");
   195                     }
   196                     fluidsynth.delete_fluid_settings(settings);
   197                 } else {
   198                     Mix_SetError("Failed to create FluidSynth settings");
   199                 }
   200             } else {
   201                 SDL_OutOfMemory();
   202             }
   203         }
   204         SDL_free(music);
   205     } else {
   206         SDL_OutOfMemory();
   207     }
   208     return NULL;
   209 }
   210 
   211 static void *FLUIDSYNTH_CreateFromRW(SDL_RWops *src, int freesrc)
   212 {
   213     FLUIDSYNTH_Music *music;
   214 
   215     music = FLUIDSYNTH_LoadMusic(src);
   216     if (music && freesrc) {
   217         SDL_RWclose(src);
   218     }
   219     return music;
   220 }
   221 
   222 static void FLUIDSYNTH_SetVolume(void *context, int volume)
   223 {
   224     FLUIDSYNTH_Music *music = (FLUIDSYNTH_Music *)context;
   225     /* FluidSynth's default is 0.2. Make 1.2 the maximum. */
   226     fluidsynth.fluid_synth_set_gain(music->synth, (float) (volume * 1.2 / MIX_MAX_VOLUME));
   227 }
   228 
   229 static int FLUIDSYNTH_Play(void *context, int play_count)
   230 {
   231     FLUIDSYNTH_Music *music = (FLUIDSYNTH_Music *)context;
   232     fluidsynth.fluid_player_set_loop(music->player, play_count);
   233     fluidsynth.fluid_player_play(music->player);
   234     return 0;
   235 }
   236 
   237 static SDL_bool FLUIDSYNTH_IsPlaying(void *context)
   238 {
   239     FLUIDSYNTH_Music *music = (FLUIDSYNTH_Music *)context;
   240     return fluidsynth.fluid_player_get_status(music->player) == FLUID_PLAYER_PLAYING ? SDL_TRUE : SDL_FALSE;
   241 }
   242 
   243 static int FLUIDSYNTH_GetSome(void *context, void *data, int bytes, SDL_bool *done)
   244 {
   245     FLUIDSYNTH_Music *music = (FLUIDSYNTH_Music *)context;
   246     int filled;
   247 
   248     filled = SDL_AudioStreamGet(music->stream, data, bytes);
   249     if (filled != 0) {
   250         return filled;
   251     }
   252 
   253     if (fluidsynth.fluid_synth_write_s16(music->synth, music_spec.samples, music->buffer, 0, 2, music->buffer, 1, 2) != FLUID_OK) {
   254         Mix_SetError("Error generating FluidSynth audio");
   255         return -1;
   256     }
   257     if (SDL_AudioStreamPut(music->stream, music->buffer, music->buffer_size) < 0) {
   258         return -1;
   259     }
   260     return 0;
   261 }
   262 static int FLUIDSYNTH_GetAudio(void *context, void *data, int bytes)
   263 {
   264     return music_pcm_getaudio(context, data, bytes, MIX_MAX_VOLUME, FLUIDSYNTH_GetSome);
   265 }
   266 
   267 static void FLUIDSYNTH_Stop(void *context)
   268 {
   269     FLUIDSYNTH_Music *music = (FLUIDSYNTH_Music *)context;
   270     fluidsynth.fluid_player_stop(music->player);
   271 }
   272 
   273 static void FLUIDSYNTH_Delete(void *context)
   274 {
   275     FLUIDSYNTH_Music *music = (FLUIDSYNTH_Music *)context;
   276     fluidsynth.delete_fluid_player(music->player);
   277     fluidsynth.delete_fluid_settings(fluidsynth.fluid_synth_get_settings(music->synth));
   278     fluidsynth.delete_fluid_synth(music->synth);
   279     SDL_free(music);
   280 }
   281 
   282 Mix_MusicInterface Mix_MusicInterface_FLUIDSYNTH =
   283 {
   284     "FLUIDSYNTH",
   285     MIX_MUSIC_FLUIDSYNTH,
   286     MUS_MID,
   287     SDL_FALSE,
   288     SDL_FALSE,
   289 
   290     FLUIDSYNTH_Load,
   291     FLUIDSYNTH_Open,
   292     FLUIDSYNTH_CreateFromRW,
   293     NULL,   /* CreateFromFile */
   294     FLUIDSYNTH_SetVolume,
   295     FLUIDSYNTH_Play,
   296     FLUIDSYNTH_IsPlaying,
   297     FLUIDSYNTH_GetAudio,
   298     NULL,   /* Seek */
   299     NULL,   /* Pause */
   300     NULL,   /* Resume */
   301     FLUIDSYNTH_Stop,
   302     FLUIDSYNTH_Delete,
   303     NULL,   /* Close */
   304     FLUIDSYNTH_Unload,
   305 };
   306 
   307 #endif /* MUSIC_MID_FLUIDSYNTH */
   308 
   309 /* vi: set ts=4 sw=4 expandtab: */