music_fluidsynth.c
changeset 797 b4b6adff699a
parent 786 12a659c8b902
child 798 9b6d7d1b3a23
     1.1 --- a/music_fluidsynth.c	Fri Oct 20 21:55:03 2017 -0700
     1.2 +++ b/music_fluidsynth.c	Fri Oct 20 23:39:04 2017 -0700
     1.3 @@ -117,14 +117,13 @@
     1.4  
     1.5  
     1.6  typedef struct {
     1.7 -    SDL_AudioCVT convert;
     1.8      fluid_synth_t *synth;
     1.9 -    fluid_player_t* player;
    1.10 -} FluidSynthMidiSong;
    1.11 +    fluid_player_t *player;
    1.12 +    SDL_AudioStream *stream;
    1.13 +    void *buffer;
    1.14 +    int buffer_size;
    1.15 +} FLUIDSYNTH_Music;
    1.16  
    1.17 -static Uint16 format;
    1.18 -static Uint8 channels;
    1.19 -static int freq;
    1.20  
    1.21  static int fluidsynth_check_soundfont(const char *path, void *data)
    1.22  {
    1.23 @@ -151,165 +150,134 @@
    1.24      if (!Mix_EachSoundFont(fluidsynth_check_soundfont, NULL)) {
    1.25          return -1;
    1.26      }
    1.27 -
    1.28 -    format = spec->format;
    1.29 -    channels = spec->channels;
    1.30 -    freq = spec->freq;
    1.31 -
    1.32      return 0;
    1.33  }
    1.34  
    1.35 -static FluidSynthMidiSong *fluidsynth_loadsong_common(int (*function)(FluidSynthMidiSong*, void*), void *data)
    1.36 +static FLUIDSYNTH_Music *FLUIDSYNTH_LoadMusic(void *data)
    1.37  {
    1.38 -    FluidSynthMidiSong *song;
    1.39 -    fluid_settings_t *settings = NULL;
    1.40 +    SDL_RWops *src = (SDL_RWops *)data;
    1.41 +    FLUIDSYNTH_Music *music;
    1.42 +    fluid_settings_t *settings;
    1.43  
    1.44 -    if ((song = SDL_calloc(1, sizeof(FluidSynthMidiSong)))) {
    1.45 -        if (SDL_BuildAudioCVT(&song->convert, AUDIO_S16, 2, freq, format, channels, freq) >= 0) {
    1.46 -            if ((settings = fluidsynth.new_fluid_settings())) {
    1.47 -                fluidsynth.fluid_settings_setnum(settings, "synth.sample-rate", (double) freq);
    1.48 +    if ((music = SDL_calloc(1, sizeof(FLUIDSYNTH_Music)))) {
    1.49 +        int channels = 2;
    1.50 +        if ((music->stream = SDL_NewAudioStream(AUDIO_S16SYS, channels, music_spec.freq, music_spec.format, music_spec.channels, music_spec.freq))) {
    1.51 +            music->buffer_size = music_spec.samples * sizeof(Sint16) * channels;
    1.52 +            if ((music->buffer = SDL_malloc(music->buffer_size))) {
    1.53 +                if ((settings = fluidsynth.new_fluid_settings())) {
    1.54 +                    fluidsynth.fluid_settings_setnum(settings, "synth.sample-rate", (double) music_spec.freq);
    1.55  
    1.56 -                if ((song->synth = fluidsynth.new_fluid_synth(settings))) {
    1.57 -                    if (Mix_EachSoundFont(fluidsynth_load_soundfont, (void*) song->synth)) {
    1.58 -                        if ((song->player = fluidsynth.new_fluid_player(song->synth))) {
    1.59 -                            if (function(song, data)) return song;
    1.60 -                            fluidsynth.delete_fluid_player(song->player);
    1.61 -                        } else {
    1.62 -                            Mix_SetError("Failed to create FluidSynth player");
    1.63 +                    if ((music->synth = fluidsynth.new_fluid_synth(settings))) {
    1.64 +                        if (Mix_EachSoundFont(fluidsynth_load_soundfont, (void*) music->synth)) {
    1.65 +                            if ((music->player = fluidsynth.new_fluid_player(music->synth))) {
    1.66 +                                void *buffer;
    1.67 +                                size_t size;
    1.68 +
    1.69 +                                buffer = SDL_LoadFile_RW(src, &size, SDL_FALSE);
    1.70 +                                if (buffer) {
    1.71 +                                    if (fluidsynth.fluid_player_add_mem(music->player, buffer, size) == FLUID_OK) {
    1.72 +                                        SDL_free(buffer);
    1.73 +                                        return music;
    1.74 +                                    } else {
    1.75 +                                        Mix_SetError("FluidSynth failed to load in-memory song");
    1.76 +                                    }
    1.77 +                                    SDL_free(buffer);
    1.78 +                                } else {
    1.79 +                                    SDL_OutOfMemory();
    1.80 +                                }
    1.81 +                                fluidsynth.delete_fluid_player(music->player);
    1.82 +                            } else {
    1.83 +                                Mix_SetError("Failed to create FluidSynth player");
    1.84 +                            }
    1.85                          }
    1.86 +                        fluidsynth.delete_fluid_synth(music->synth);
    1.87 +                    } else {
    1.88 +                        Mix_SetError("Failed to create FluidSynth synthesizer");
    1.89                      }
    1.90 -                    fluidsynth.delete_fluid_synth(song->synth);
    1.91 +                    fluidsynth.delete_fluid_settings(settings);
    1.92                  } else {
    1.93 -                    Mix_SetError("Failed to create FluidSynth synthesizer");
    1.94 +                    Mix_SetError("Failed to create FluidSynth settings");
    1.95                  }
    1.96 -                fluidsynth.delete_fluid_settings(settings);
    1.97              } else {
    1.98 -                Mix_SetError("Failed to create FluidSynth settings");
    1.99 +                SDL_OutOfMemory();
   1.100              }
   1.101 -        } else {
   1.102 -            Mix_SetError("Failed to set up audio conversion");
   1.103          }
   1.104 -        SDL_free(song);
   1.105 +        SDL_free(music);
   1.106      } else {
   1.107 -        Mix_SetError("Insufficient memory for song");
   1.108 +        SDL_OutOfMemory();
   1.109      }
   1.110      return NULL;
   1.111  }
   1.112  
   1.113 -static int fluidsynth_loadsong_RW_internal(FluidSynthMidiSong *song, void *data)
   1.114 -{
   1.115 -    Sint64 offset;
   1.116 -    size_t size;
   1.117 -    char *buffer;
   1.118 -    SDL_RWops *src = (SDL_RWops*) data;
   1.119 -
   1.120 -    offset = SDL_RWtell(src);
   1.121 -    SDL_RWseek(src, 0, RW_SEEK_END);
   1.122 -    size = (size_t)(SDL_RWtell(src) - offset);
   1.123 -    SDL_RWseek(src, offset, RW_SEEK_SET);
   1.124 -
   1.125 -    if ((buffer = (char*) SDL_malloc(size))) {
   1.126 -        if(SDL_RWread(src, buffer, size, 1) == 1) {
   1.127 -            if (fluidsynth.fluid_player_add_mem(song->player, buffer, size) == FLUID_OK) {
   1.128 -                SDL_free(buffer);
   1.129 -                return 1;
   1.130 -            } else {
   1.131 -                Mix_SetError("FluidSynth failed to load in-memory song");
   1.132 -            }
   1.133 -        } else {
   1.134 -            Mix_SetError("Failed to read in-memory song");
   1.135 -        }
   1.136 -        SDL_free(buffer);
   1.137 -    } else {
   1.138 -        Mix_SetError("Insufficient memory for song");
   1.139 -    }
   1.140 -    return 0;
   1.141 -}
   1.142 -
   1.143  static void *FLUIDSYNTH_CreateFromRW(SDL_RWops *src, int freesrc)
   1.144  {
   1.145 -    FluidSynthMidiSong *song;
   1.146 +    FLUIDSYNTH_Music *music;
   1.147  
   1.148 -    song = fluidsynth_loadsong_common(fluidsynth_loadsong_RW_internal, (void*) src);
   1.149 -    if (song && freesrc) {
   1.150 +    music = FLUIDSYNTH_LoadMusic(src);
   1.151 +    if (music && freesrc) {
   1.152          SDL_RWclose(src);
   1.153      }
   1.154 -    return song;
   1.155 +    return music;
   1.156  }
   1.157  
   1.158  static void FLUIDSYNTH_SetVolume(void *context, int volume)
   1.159  {
   1.160 -    FluidSynthMidiSong *song = (FluidSynthMidiSong *)context;
   1.161 +    FLUIDSYNTH_Music *music = (FLUIDSYNTH_Music *)context;
   1.162      /* FluidSynth's default is 0.2. Make 1.2 the maximum. */
   1.163 -    fluidsynth.fluid_synth_set_gain(song->synth, (float) (volume * 1.2 / MIX_MAX_VOLUME));
   1.164 +    fluidsynth.fluid_synth_set_gain(music->synth, (float) (volume * 1.2 / MIX_MAX_VOLUME));
   1.165  }
   1.166  
   1.167 -static int FLUIDSYNTH_Play(void *context)
   1.168 +static int FLUIDSYNTH_Play(void *context, int play_count)
   1.169  {
   1.170 -    FluidSynthMidiSong *song = (FluidSynthMidiSong *)context;
   1.171 -    fluidsynth.fluid_player_set_loop(song->player, 1);
   1.172 -    fluidsynth.fluid_player_play(song->player);
   1.173 +    FLUIDSYNTH_Music *music = (FLUIDSYNTH_Music *)context;
   1.174 +    fluidsynth.fluid_player_set_loop(music->player, play_count);
   1.175 +    fluidsynth.fluid_player_play(music->player);
   1.176      return 0;
   1.177  }
   1.178  
   1.179  static SDL_bool FLUIDSYNTH_IsPlaying(void *context)
   1.180  {
   1.181 -    FluidSynthMidiSong *song = (FluidSynthMidiSong *)context;
   1.182 -    return fluidsynth.fluid_player_get_status(song->player) == FLUID_PLAYER_PLAYING ? SDL_TRUE : SDL_FALSE;
   1.183 +    FLUIDSYNTH_Music *music = (FLUIDSYNTH_Music *)context;
   1.184 +    return fluidsynth.fluid_player_get_status(music->player) == FLUID_PLAYER_PLAYING ? SDL_TRUE : SDL_FALSE;
   1.185  }
   1.186  
   1.187 +static int FLUIDSYNTH_GetSome(void *context, void *data, int bytes, SDL_bool *done)
   1.188 +{
   1.189 +    int filled;
   1.190 +
   1.191 +    filled = SDL_AudioStreamGet(music->stream, data, bytes);
   1.192 +    if (filled != 0) {
   1.193 +        return filled;
   1.194 +    }
   1.195 +
   1.196 +    /* FIXME: What happens at end of song? */
   1.197 +    if (fluidsynth.fluid_synth_write_s16(music->synth, mixer_spec.samples, music->buffer, 0, 2, music->buffer, 1, 2) != FLUID_OK) {
   1.198 +        Mix_SetError("Error generating FluidSynth audio");
   1.199 +        return -1;
   1.200 +    }
   1.201 +    if (SDL_AudioStreamPut(music->stream, music->buffer, music->buffer_size) < 0) {
   1.202 +        return -1;
   1.203 +    }
   1.204 +    return 0;
   1.205 +}
   1.206  static int FLUIDSYNTH_GetAudio(void *context, void *data, int bytes)
   1.207  {
   1.208 -    int result = -1;
   1.209 -    int frames = bytes / channels / ((format & 0xFF) / 8);
   1.210 -    int src_len = frames * 4; /* 16-bit stereo */
   1.211 -    void *src = dest;
   1.212 -
   1.213 -    if (bytes < src_len) {
   1.214 -        if (!(src = SDL_malloc(src_len))) {
   1.215 -            Mix_SetError("Insufficient memory for audio conversion");
   1.216 -            return result;
   1.217 -        }
   1.218 -    }
   1.219 -
   1.220 -    if (fluidsynth.fluid_synth_write_s16(song->synth, frames, src, 0, 2, src, 1, 2) != FLUID_OK) {
   1.221 -        Mix_SetError("Error generating FluidSynth audio");
   1.222 -        goto finish;
   1.223 -    }
   1.224 -
   1.225 -    song->convert.buf = src;
   1.226 -    song->convert.len = src_len;
   1.227 -
   1.228 -    if (SDL_ConvertAudio(&song->convert) < 0) {
   1.229 -        Mix_SetError("Error during audio conversion");
   1.230 -        goto finish;
   1.231 -    }
   1.232 -
   1.233 -    if (src != dest)
   1.234 -        SDL_memcpy(dest, src, bytes);
   1.235 -
   1.236 -    result = 0;
   1.237 -
   1.238 -finish:
   1.239 -    if (src != dest)
   1.240 -        SDL_free(src);
   1.241 -
   1.242 -    return result;
   1.243 +    return music_pcm_getaudio(context, data, bytes, MIX_MAX_VOLUME, FLUIDSYNTH_GetSome);
   1.244  }
   1.245  
   1.246  static void FLUIDSYNTH_Stop(void *context)
   1.247  {
   1.248 -    FluidSynthMidiSong *song = (FluidSynthMidiSong *)context;
   1.249 -    fluidsynth.fluid_player_stop(song->player);
   1.250 +    FLUIDSYNTH_Music *music = (FLUIDSYNTH_Music *)context;
   1.251 +    fluidsynth.fluid_player_stop(music->player);
   1.252  }
   1.253  
   1.254  static void FLUIDSYNTH_Delete(void *context)
   1.255  {
   1.256 -    FluidSynthMidiSong *song = (FluidSynthMidiSong *)context;
   1.257 -    fluidsynth.delete_fluid_player(song->player);
   1.258 -    fluidsynth.delete_fluid_settings(fluidsynth.fluid_synth_get_settings(song->synth));
   1.259 -    fluidsynth.delete_fluid_synth(song->synth);
   1.260 -    SDL_free(song);
   1.261 +    FLUIDSYNTH_Music *music = (FLUIDSYNTH_Music *)context;
   1.262 +    fluidsynth.delete_fluid_player(music->player);
   1.263 +    fluidsynth.delete_fluid_settings(fluidsynth.fluid_synth_get_settings(music->synth));
   1.264 +    fluidsynth.delete_fluid_synth(music->synth);
   1.265 +    SDL_free(music);
   1.266  }
   1.267  
   1.268  Mix_MusicInterface Mix_MusicInterface_FLUIDSYNTH =