music_fluidsynth.c
changeset 797 b4b6adff699a
parent 786 12a659c8b902
child 798 9b6d7d1b3a23
equal deleted inserted replaced
796:6287bc83c1b3 797:b4b6adff699a
   115     --fluidsynth.loaded;
   115     --fluidsynth.loaded;
   116 }
   116 }
   117 
   117 
   118 
   118 
   119 typedef struct {
   119 typedef struct {
   120     SDL_AudioCVT convert;
       
   121     fluid_synth_t *synth;
   120     fluid_synth_t *synth;
   122     fluid_player_t* player;
   121     fluid_player_t *player;
   123 } FluidSynthMidiSong;
   122     SDL_AudioStream *stream;
   124 
   123     void *buffer;
   125 static Uint16 format;
   124     int buffer_size;
   126 static Uint8 channels;
   125 } FLUIDSYNTH_Music;
   127 static int freq;
   126 
   128 
   127 
   129 static int fluidsynth_check_soundfont(const char *path, void *data)
   128 static int fluidsynth_check_soundfont(const char *path, void *data)
   130 {
   129 {
   131     FILE *file = fopen(path, "r");
   130     FILE *file = fopen(path, "r");
   132 
   131 
   149 static int FLUIDSYNTH_Open(const SDL_AudioSpec *spec)
   148 static int FLUIDSYNTH_Open(const SDL_AudioSpec *spec)
   150 {
   149 {
   151     if (!Mix_EachSoundFont(fluidsynth_check_soundfont, NULL)) {
   150     if (!Mix_EachSoundFont(fluidsynth_check_soundfont, NULL)) {
   152         return -1;
   151         return -1;
   153     }
   152     }
   154 
       
   155     format = spec->format;
       
   156     channels = spec->channels;
       
   157     freq = spec->freq;
       
   158 
       
   159     return 0;
   153     return 0;
   160 }
   154 }
   161 
   155 
   162 static FluidSynthMidiSong *fluidsynth_loadsong_common(int (*function)(FluidSynthMidiSong*, void*), void *data)
   156 static FLUIDSYNTH_Music *FLUIDSYNTH_LoadMusic(void *data)
   163 {
   157 {
   164     FluidSynthMidiSong *song;
   158     SDL_RWops *src = (SDL_RWops *)data;
   165     fluid_settings_t *settings = NULL;
   159     FLUIDSYNTH_Music *music;
   166 
   160     fluid_settings_t *settings;
   167     if ((song = SDL_calloc(1, sizeof(FluidSynthMidiSong)))) {
   161 
   168         if (SDL_BuildAudioCVT(&song->convert, AUDIO_S16, 2, freq, format, channels, freq) >= 0) {
   162     if ((music = SDL_calloc(1, sizeof(FLUIDSYNTH_Music)))) {
   169             if ((settings = fluidsynth.new_fluid_settings())) {
   163         int channels = 2;
   170                 fluidsynth.fluid_settings_setnum(settings, "synth.sample-rate", (double) freq);
   164         if ((music->stream = SDL_NewAudioStream(AUDIO_S16SYS, channels, music_spec.freq, music_spec.format, music_spec.channels, music_spec.freq))) {
   171 
   165             music->buffer_size = music_spec.samples * sizeof(Sint16) * channels;
   172                 if ((song->synth = fluidsynth.new_fluid_synth(settings))) {
   166             if ((music->buffer = SDL_malloc(music->buffer_size))) {
   173                     if (Mix_EachSoundFont(fluidsynth_load_soundfont, (void*) song->synth)) {
   167                 if ((settings = fluidsynth.new_fluid_settings())) {
   174                         if ((song->player = fluidsynth.new_fluid_player(song->synth))) {
   168                     fluidsynth.fluid_settings_setnum(settings, "synth.sample-rate", (double) music_spec.freq);
   175                             if (function(song, data)) return song;
   169 
   176                             fluidsynth.delete_fluid_player(song->player);
   170                     if ((music->synth = fluidsynth.new_fluid_synth(settings))) {
   177                         } else {
   171                         if (Mix_EachSoundFont(fluidsynth_load_soundfont, (void*) music->synth)) {
   178                             Mix_SetError("Failed to create FluidSynth player");
   172                             if ((music->player = fluidsynth.new_fluid_player(music->synth))) {
       
   173                                 void *buffer;
       
   174                                 size_t size;
       
   175 
       
   176                                 buffer = SDL_LoadFile_RW(src, &size, SDL_FALSE);
       
   177                                 if (buffer) {
       
   178                                     if (fluidsynth.fluid_player_add_mem(music->player, buffer, size) == FLUID_OK) {
       
   179                                         SDL_free(buffer);
       
   180                                         return music;
       
   181                                     } else {
       
   182                                         Mix_SetError("FluidSynth failed to load in-memory song");
       
   183                                     }
       
   184                                     SDL_free(buffer);
       
   185                                 } else {
       
   186                                     SDL_OutOfMemory();
       
   187                                 }
       
   188                                 fluidsynth.delete_fluid_player(music->player);
       
   189                             } else {
       
   190                                 Mix_SetError("Failed to create FluidSynth player");
       
   191                             }
   179                         }
   192                         }
       
   193                         fluidsynth.delete_fluid_synth(music->synth);
       
   194                     } else {
       
   195                         Mix_SetError("Failed to create FluidSynth synthesizer");
   180                     }
   196                     }
   181                     fluidsynth.delete_fluid_synth(song->synth);
   197                     fluidsynth.delete_fluid_settings(settings);
   182                 } else {
   198                 } else {
   183                     Mix_SetError("Failed to create FluidSynth synthesizer");
   199                     Mix_SetError("Failed to create FluidSynth settings");
   184                 }
   200                 }
   185                 fluidsynth.delete_fluid_settings(settings);
       
   186             } else {
   201             } else {
   187                 Mix_SetError("Failed to create FluidSynth settings");
   202                 SDL_OutOfMemory();
   188             }
   203             }
   189         } else {
       
   190             Mix_SetError("Failed to set up audio conversion");
       
   191         }
   204         }
   192         SDL_free(song);
   205         SDL_free(music);
   193     } else {
   206     } else {
   194         Mix_SetError("Insufficient memory for song");
   207         SDL_OutOfMemory();
   195     }
   208     }
   196     return NULL;
   209     return NULL;
   197 }
   210 }
   198 
   211 
   199 static int fluidsynth_loadsong_RW_internal(FluidSynthMidiSong *song, void *data)
   212 static void *FLUIDSYNTH_CreateFromRW(SDL_RWops *src, int freesrc)
   200 {
   213 {
   201     Sint64 offset;
   214     FLUIDSYNTH_Music *music;
   202     size_t size;
   215 
   203     char *buffer;
   216     music = FLUIDSYNTH_LoadMusic(src);
   204     SDL_RWops *src = (SDL_RWops*) data;
   217     if (music && freesrc) {
   205 
   218         SDL_RWclose(src);
   206     offset = SDL_RWtell(src);
   219     }
   207     SDL_RWseek(src, 0, RW_SEEK_END);
   220     return music;
   208     size = (size_t)(SDL_RWtell(src) - offset);
   221 }
   209     SDL_RWseek(src, offset, RW_SEEK_SET);
   222 
   210 
   223 static void FLUIDSYNTH_SetVolume(void *context, int volume)
   211     if ((buffer = (char*) SDL_malloc(size))) {
   224 {
   212         if(SDL_RWread(src, buffer, size, 1) == 1) {
   225     FLUIDSYNTH_Music *music = (FLUIDSYNTH_Music *)context;
   213             if (fluidsynth.fluid_player_add_mem(song->player, buffer, size) == FLUID_OK) {
   226     /* FluidSynth's default is 0.2. Make 1.2 the maximum. */
   214                 SDL_free(buffer);
   227     fluidsynth.fluid_synth_set_gain(music->synth, (float) (volume * 1.2 / MIX_MAX_VOLUME));
   215                 return 1;
   228 }
   216             } else {
   229 
   217                 Mix_SetError("FluidSynth failed to load in-memory song");
   230 static int FLUIDSYNTH_Play(void *context, int play_count)
   218             }
   231 {
   219         } else {
   232     FLUIDSYNTH_Music *music = (FLUIDSYNTH_Music *)context;
   220             Mix_SetError("Failed to read in-memory song");
   233     fluidsynth.fluid_player_set_loop(music->player, play_count);
   221         }
   234     fluidsynth.fluid_player_play(music->player);
   222         SDL_free(buffer);
       
   223     } else {
       
   224         Mix_SetError("Insufficient memory for song");
       
   225     }
       
   226     return 0;
   235     return 0;
   227 }
   236 }
   228 
   237 
   229 static void *FLUIDSYNTH_CreateFromRW(SDL_RWops *src, int freesrc)
   238 static SDL_bool FLUIDSYNTH_IsPlaying(void *context)
   230 {
   239 {
   231     FluidSynthMidiSong *song;
   240     FLUIDSYNTH_Music *music = (FLUIDSYNTH_Music *)context;
   232 
   241     return fluidsynth.fluid_player_get_status(music->player) == FLUID_PLAYER_PLAYING ? SDL_TRUE : SDL_FALSE;
   233     song = fluidsynth_loadsong_common(fluidsynth_loadsong_RW_internal, (void*) src);
   242 }
   234     if (song && freesrc) {
   243 
   235         SDL_RWclose(src);
   244 static int FLUIDSYNTH_GetSome(void *context, void *data, int bytes, SDL_bool *done)
   236     }
   245 {
   237     return song;
   246     int filled;
   238 }
   247 
   239 
   248     filled = SDL_AudioStreamGet(music->stream, data, bytes);
   240 static void FLUIDSYNTH_SetVolume(void *context, int volume)
   249     if (filled != 0) {
   241 {
   250         return filled;
   242     FluidSynthMidiSong *song = (FluidSynthMidiSong *)context;
   251     }
   243     /* FluidSynth's default is 0.2. Make 1.2 the maximum. */
   252 
   244     fluidsynth.fluid_synth_set_gain(song->synth, (float) (volume * 1.2 / MIX_MAX_VOLUME));
   253     /* FIXME: What happens at end of song? */
   245 }
   254     if (fluidsynth.fluid_synth_write_s16(music->synth, mixer_spec.samples, music->buffer, 0, 2, music->buffer, 1, 2) != FLUID_OK) {
   246 
   255         Mix_SetError("Error generating FluidSynth audio");
   247 static int FLUIDSYNTH_Play(void *context)
   256         return -1;
   248 {
   257     }
   249     FluidSynthMidiSong *song = (FluidSynthMidiSong *)context;
   258     if (SDL_AudioStreamPut(music->stream, music->buffer, music->buffer_size) < 0) {
   250     fluidsynth.fluid_player_set_loop(song->player, 1);
   259         return -1;
   251     fluidsynth.fluid_player_play(song->player);
   260     }
   252     return 0;
   261     return 0;
   253 }
   262 }
   254 
       
   255 static SDL_bool FLUIDSYNTH_IsPlaying(void *context)
       
   256 {
       
   257     FluidSynthMidiSong *song = (FluidSynthMidiSong *)context;
       
   258     return fluidsynth.fluid_player_get_status(song->player) == FLUID_PLAYER_PLAYING ? SDL_TRUE : SDL_FALSE;
       
   259 }
       
   260 
       
   261 static int FLUIDSYNTH_GetAudio(void *context, void *data, int bytes)
   263 static int FLUIDSYNTH_GetAudio(void *context, void *data, int bytes)
   262 {
   264 {
   263     int result = -1;
   265     return music_pcm_getaudio(context, data, bytes, MIX_MAX_VOLUME, FLUIDSYNTH_GetSome);
   264     int frames = bytes / channels / ((format & 0xFF) / 8);
       
   265     int src_len = frames * 4; /* 16-bit stereo */
       
   266     void *src = dest;
       
   267 
       
   268     if (bytes < src_len) {
       
   269         if (!(src = SDL_malloc(src_len))) {
       
   270             Mix_SetError("Insufficient memory for audio conversion");
       
   271             return result;
       
   272         }
       
   273     }
       
   274 
       
   275     if (fluidsynth.fluid_synth_write_s16(song->synth, frames, src, 0, 2, src, 1, 2) != FLUID_OK) {
       
   276         Mix_SetError("Error generating FluidSynth audio");
       
   277         goto finish;
       
   278     }
       
   279 
       
   280     song->convert.buf = src;
       
   281     song->convert.len = src_len;
       
   282 
       
   283     if (SDL_ConvertAudio(&song->convert) < 0) {
       
   284         Mix_SetError("Error during audio conversion");
       
   285         goto finish;
       
   286     }
       
   287 
       
   288     if (src != dest)
       
   289         SDL_memcpy(dest, src, bytes);
       
   290 
       
   291     result = 0;
       
   292 
       
   293 finish:
       
   294     if (src != dest)
       
   295         SDL_free(src);
       
   296 
       
   297     return result;
       
   298 }
   266 }
   299 
   267 
   300 static void FLUIDSYNTH_Stop(void *context)
   268 static void FLUIDSYNTH_Stop(void *context)
   301 {
   269 {
   302     FluidSynthMidiSong *song = (FluidSynthMidiSong *)context;
   270     FLUIDSYNTH_Music *music = (FLUIDSYNTH_Music *)context;
   303     fluidsynth.fluid_player_stop(song->player);
   271     fluidsynth.fluid_player_stop(music->player);
   304 }
   272 }
   305 
   273 
   306 static void FLUIDSYNTH_Delete(void *context)
   274 static void FLUIDSYNTH_Delete(void *context)
   307 {
   275 {
   308     FluidSynthMidiSong *song = (FluidSynthMidiSong *)context;
   276     FLUIDSYNTH_Music *music = (FLUIDSYNTH_Music *)context;
   309     fluidsynth.delete_fluid_player(song->player);
   277     fluidsynth.delete_fluid_player(music->player);
   310     fluidsynth.delete_fluid_settings(fluidsynth.fluid_synth_get_settings(song->synth));
   278     fluidsynth.delete_fluid_settings(fluidsynth.fluid_synth_get_settings(music->synth));
   311     fluidsynth.delete_fluid_synth(song->synth);
   279     fluidsynth.delete_fluid_synth(music->synth);
   312     SDL_free(song);
   280     SDL_free(music);
   313 }
   281 }
   314 
   282 
   315 Mix_MusicInterface Mix_MusicInterface_FLUIDSYNTH =
   283 Mix_MusicInterface Mix_MusicInterface_FLUIDSYNTH =
   316 {
   284 {
   317     "FLUIDSYNTH",
   285     "FLUIDSYNTH",