fluidsynth.c
changeset 506 586ae09f8176
child 518 8bc9b5fd2aae
     1.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     1.2 +++ b/fluidsynth.c	Sun Mar 20 14:34:18 2011 +0000
     1.3 @@ -0,0 +1,222 @@
     1.4 +/*
     1.5 +    SDL_mixer:  An audio mixer library based on the SDL library
     1.6 +    Copyright (C) 1997-2011 Sam Lantinga
     1.7 +
     1.8 +    This library is free software; you can redistribute it and/or
     1.9 +    modify it under the terms of the GNU Library General Public
    1.10 +    License as published by the Free Software Foundation; either
    1.11 +    version 2 of the License, or (at your option) any later version.
    1.12 +
    1.13 +    This library is distributed in the hope that it will be useful,
    1.14 +    but WITHOUT ANY WARRANTY; without even the implied warranty of
    1.15 +    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
    1.16 +    Library General Public License for more details.
    1.17 +
    1.18 +    You should have received a copy of the GNU Library General Public
    1.19 +    License along with this library; if not, write to the Free
    1.20 +    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
    1.21 +
    1.22 +    James Le Cuirot
    1.23 +    chewi@aura-online.co.uk
    1.24 +*/
    1.25 +
    1.26 +#include "fluidsynth.h"
    1.27 +#include "SDL_mixer.h"
    1.28 +#include <stdio.h>
    1.29 +#include <sys/types.h>
    1.30 +
    1.31 +static Uint16 format;
    1.32 +static Uint8 channels;
    1.33 +static int freq;
    1.34 +
    1.35 +int fluidsynth_check_soundfont(const char *path, void *data)
    1.36 +{
    1.37 +	FILE *file = fopen(path, "r");
    1.38 +
    1.39 +	if (file) {
    1.40 +		fclose(file);
    1.41 +		return 1;
    1.42 +	} else {
    1.43 +		Mix_SetError("Failed to access the SoundFont %s", path);
    1.44 +		return 0;
    1.45 +	}
    1.46 +}
    1.47 +
    1.48 +int fluidsynth_load_soundfont(const char *path, void *data)
    1.49 +{
    1.50 +	/* If this fails, it's too late to try Timidity so pray that at least one works. */
    1.51 +	fluidsynth.fluid_synth_sfload((fluid_synth_t*) data, path, 1);
    1.52 +	return 1;
    1.53 +}
    1.54 +
    1.55 +int fluidsynth_init(SDL_AudioSpec *mixer)
    1.56 +{
    1.57 +	if (!Mix_EachSoundFont(fluidsynth_check_soundfont, NULL))
    1.58 +		return -1;
    1.59 +
    1.60 +	format = mixer->format;
    1.61 +	channels = mixer->channels;
    1.62 +	freq = mixer->freq;
    1.63 +
    1.64 +	return 0;
    1.65 +}
    1.66 +
    1.67 +FluidSynthMidiSong *fluidsynth_loadsong_common(int (*function)(FluidSynthMidiSong*, void*), void *data)
    1.68 +{
    1.69 +	FluidSynthMidiSong *song;
    1.70 +	fluid_settings_t *settings = NULL;
    1.71 +
    1.72 +	if ((song = malloc(sizeof(FluidSynthMidiSong)))) {
    1.73 +		memset(song, 0, sizeof(FluidSynthMidiSong));
    1.74 +
    1.75 +		if (SDL_BuildAudioCVT(&song->convert, AUDIO_S16, 2, freq, format, channels, freq) >= 0) {
    1.76 +			if ((settings = fluidsynth.new_fluid_settings())) {
    1.77 +				fluidsynth.fluid_settings_setnum(settings, "synth.sample-rate", (double) freq);
    1.78 +
    1.79 +				if ((song->synth = fluidsynth.new_fluid_synth(settings))) {
    1.80 +					if (Mix_EachSoundFont(fluidsynth_load_soundfont, (void*) song->synth)) {
    1.81 +						if ((song->player = fluidsynth.new_fluid_player(song->synth))) {
    1.82 +							if (function(song, data)) return song;
    1.83 +							fluidsynth.delete_fluid_player(song->player);
    1.84 +						} else {
    1.85 +							Mix_SetError("Failed to create FluidSynth player");
    1.86 +						}
    1.87 +					}
    1.88 +					fluidsynth.delete_fluid_synth(song->synth);
    1.89 +				} else {
    1.90 +					Mix_SetError("Failed to create FluidSynth synthesizer");
    1.91 +				}
    1.92 +				fluidsynth.delete_fluid_settings(settings);
    1.93 +			} else {
    1.94 +				Mix_SetError("Failed to create FluidSynth settings");
    1.95 +			}
    1.96 +		} else {
    1.97 +			Mix_SetError("Failed to set up audio conversion");
    1.98 +		}
    1.99 +		free(song);
   1.100 +	} else {
   1.101 +		Mix_SetError("Insufficient memory for song");
   1.102 +	}
   1.103 +	return NULL;
   1.104 +}
   1.105 +
   1.106 +int fluidsynth_loadsong_internal(FluidSynthMidiSong *song, void *data)
   1.107 +{
   1.108 +	const char* path = (const char*) data;
   1.109 +
   1.110 +	if (fluidsynth.fluid_player_add(song->player, path) == FLUID_OK) {
   1.111 +		return 1;
   1.112 +	} else {
   1.113 +		Mix_SetError("FluidSynth failed to load %s", path);
   1.114 +		return 0;
   1.115 +	}
   1.116 +}
   1.117 +
   1.118 +int fluidsynth_loadsong_RW_internal(FluidSynthMidiSong *song, void *data)
   1.119 +{
   1.120 +	off_t offset;
   1.121 +	size_t size;
   1.122 +	char *buffer;
   1.123 +	SDL_RWops *rw = (SDL_RWops*) data;
   1.124 +
   1.125 +	offset = SDL_RWtell(rw);
   1.126 +	SDL_RWseek(rw, 0, RW_SEEK_END);
   1.127 +	size = SDL_RWtell(rw) - offset;
   1.128 +	SDL_RWseek(rw, offset, RW_SEEK_SET);
   1.129 +
   1.130 +	if ((buffer = (char*) malloc(size))) {
   1.131 +		if(SDL_RWread(rw, buffer, size, 1) == 1) {
   1.132 +			if (fluidsynth.fluid_player_add_mem(song->player, buffer, size) == FLUID_OK) {
   1.133 +				return 1;
   1.134 +			} else {
   1.135 +				Mix_SetError("FluidSynth failed to load in-memory song");
   1.136 +			}
   1.137 +		} else {
   1.138 +			Mix_SetError("Failed to read in-memory song");
   1.139 +		}
   1.140 +		free(buffer);
   1.141 +	} else {
   1.142 +		Mix_SetError("Insufficient memory for song");
   1.143 +	}
   1.144 +	return 0;
   1.145 +}
   1.146 +
   1.147 +FluidSynthMidiSong *fluidsynth_loadsong(const char *midifile)
   1.148 +{
   1.149 +	return fluidsynth_loadsong_common(fluidsynth_loadsong_internal, (void*) midifile);
   1.150 +}
   1.151 +
   1.152 +FluidSynthMidiSong *fluidsynth_loadsong_RW(SDL_RWops *rw)
   1.153 +{
   1.154 +	return fluidsynth_loadsong_common(fluidsynth_loadsong_RW_internal, (void*) rw);
   1.155 +}
   1.156 +
   1.157 +void fluidsynth_freesong(FluidSynthMidiSong *song)
   1.158 +{
   1.159 +	if (!song) return;
   1.160 +	fluidsynth.delete_fluid_player(song->player);
   1.161 +	fluidsynth.delete_fluid_settings(fluidsynth.fluid_synth_get_settings(song->synth));
   1.162 +	fluidsynth.delete_fluid_synth(song->synth);
   1.163 +	free(song);
   1.164 +}
   1.165 +
   1.166 +void fluidsynth_start(FluidSynthMidiSong *song)
   1.167 +{
   1.168 +	fluidsynth.fluid_player_set_loop(song->player, 1);
   1.169 +	fluidsynth.fluid_player_play(song->player);
   1.170 +}
   1.171 +
   1.172 +void fluidsynth_stop(FluidSynthMidiSong *song)
   1.173 +{
   1.174 +	fluidsynth.fluid_player_stop(song->player);
   1.175 +}
   1.176 +
   1.177 +int fluidsynth_active(FluidSynthMidiSong *song)
   1.178 +{
   1.179 +	return fluidsynth.fluid_player_get_status(song->player) == FLUID_PLAYER_PLAYING ? 1 : 0;
   1.180 +}
   1.181 +
   1.182 +void fluidsynth_setvolume(FluidSynthMidiSong *song, int volume)
   1.183 +{
   1.184 +	/* FluidSynth's default is 0.2. Make 0.8 the maximum. */
   1.185 +	fluidsynth.fluid_synth_set_gain(song->synth, (float) (volume * 0.00625));
   1.186 +}
   1.187 +
   1.188 +int fluidsynth_playsome(FluidSynthMidiSong *song, void *dest, int dest_len)
   1.189 +{
   1.190 +	int result = -1;
   1.191 +	int frames = dest_len / channels / ((format & 0xFF) / 8);
   1.192 +	int src_len = frames * 4; /* 16-bit stereo */
   1.193 +	void *src = dest;
   1.194 +
   1.195 +	if (dest_len < src_len) {
   1.196 +		if (!(src = malloc(src_len))) {
   1.197 +			Mix_SetError("Insufficient memory for audio conversion");
   1.198 +			return result;
   1.199 +		}
   1.200 +	}
   1.201 +
   1.202 +	if (fluidsynth.fluid_synth_write_s16(song->synth, frames, src, 0, 2, src, 1, 2) != FLUID_OK) {
   1.203 +		Mix_SetError("Error generating FluidSynth audio");
   1.204 +		goto finish;
   1.205 +	}
   1.206 +
   1.207 +	song->convert.buf = src;
   1.208 +	song->convert.len = src_len;
   1.209 +
   1.210 +	if (SDL_ConvertAudio(&song->convert) < 0) {
   1.211 +		Mix_SetError("Error during audio conversion");
   1.212 +		goto finish;
   1.213 +	}
   1.214 +
   1.215 +	if (src != dest)
   1.216 +		memcpy(dest, src, dest_len);
   1.217 +
   1.218 +	result = 0;
   1.219 +
   1.220 +finish:
   1.221 +	if (src != dest)
   1.222 +		free(src);
   1.223 +
   1.224 +	return result;
   1.225 +}