fluidsynth.c
author Sam Lantinga <slouken@libsdl.org>
Sun, 01 Jan 2012 14:40:22 -0500
changeset 532 b8e8ae4852b2
parent 521 565549e046b0
child 542 3de4970b36d4
permissions -rw-r--r--
Updated the Windows build to:
Visual Studio 2008
flac-1.2.1
libogg-1.3.0
libvorbis-1.3.2

All Windows binaries have been rebuilt with mingw-w32-1.0
     1 /*
     2   SDL_mixer:  An audio mixer library based on the SDL library
     3   Copyright (C) 1997-2012 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 USE_FLUIDSYNTH_MIDI
    26 
    27 #include <stdio.h>
    28 #include <sys/types.h>
    29 
    30 #include "SDL_mixer.h"
    31 #include "fluidsynth.h"
    32 
    33 static Uint16 format;
    34 static Uint8 channels;
    35 static int freq;
    36 
    37 int fluidsynth_check_soundfont(const char *path, void *data)
    38 {
    39 	FILE *file = fopen(path, "r");
    40 
    41 	if (file) {
    42 		fclose(file);
    43 		return 1;
    44 	} else {
    45 		Mix_SetError("Failed to access the SoundFont %s", path);
    46 		return 0;
    47 	}
    48 }
    49 
    50 int fluidsynth_load_soundfont(const char *path, void *data)
    51 {
    52 	/* If this fails, it's too late to try Timidity so pray that at least one works. */
    53 	fluidsynth.fluid_synth_sfload((fluid_synth_t*) data, path, 1);
    54 	return 1;
    55 }
    56 
    57 int fluidsynth_init(SDL_AudioSpec *mixer)
    58 {
    59 	if (!Mix_EachSoundFont(fluidsynth_check_soundfont, NULL))
    60 		return -1;
    61 
    62 	format = mixer->format;
    63 	channels = mixer->channels;
    64 	freq = mixer->freq;
    65 
    66 	return 0;
    67 }
    68 
    69 FluidSynthMidiSong *fluidsynth_loadsong_common(int (*function)(FluidSynthMidiSong*, void*), void *data)
    70 {
    71 	FluidSynthMidiSong *song;
    72 	fluid_settings_t *settings = NULL;
    73 
    74 	if ((song = malloc(sizeof(FluidSynthMidiSong)))) {
    75 		memset(song, 0, sizeof(FluidSynthMidiSong));
    76 
    77 		if (SDL_BuildAudioCVT(&song->convert, AUDIO_S16, 2, freq, format, channels, freq) >= 0) {
    78 			if ((settings = fluidsynth.new_fluid_settings())) {
    79 				fluidsynth.fluid_settings_setnum(settings, "synth.sample-rate", (double) freq);
    80 
    81 				if ((song->synth = fluidsynth.new_fluid_synth(settings))) {
    82 					if (Mix_EachSoundFont(fluidsynth_load_soundfont, (void*) song->synth)) {
    83 						if ((song->player = fluidsynth.new_fluid_player(song->synth))) {
    84 							if (function(song, data)) return song;
    85 							fluidsynth.delete_fluid_player(song->player);
    86 						} else {
    87 							Mix_SetError("Failed to create FluidSynth player");
    88 						}
    89 					}
    90 					fluidsynth.delete_fluid_synth(song->synth);
    91 				} else {
    92 					Mix_SetError("Failed to create FluidSynth synthesizer");
    93 				}
    94 				fluidsynth.delete_fluid_settings(settings);
    95 			} else {
    96 				Mix_SetError("Failed to create FluidSynth settings");
    97 			}
    98 		} else {
    99 			Mix_SetError("Failed to set up audio conversion");
   100 		}
   101 		free(song);
   102 	} else {
   103 		Mix_SetError("Insufficient memory for song");
   104 	}
   105 	return NULL;
   106 }
   107 
   108 int fluidsynth_loadsong_internal(FluidSynthMidiSong *song, void *data)
   109 {
   110 	const char* path = (const char*) data;
   111 
   112 	if (fluidsynth.fluid_player_add(song->player, path) == FLUID_OK) {
   113 		return 1;
   114 	} else {
   115 		Mix_SetError("FluidSynth failed to load %s", path);
   116 		return 0;
   117 	}
   118 }
   119 
   120 int fluidsynth_loadsong_RW_internal(FluidSynthMidiSong *song, void *data)
   121 {
   122 	off_t offset;
   123 	size_t size;
   124 	char *buffer;
   125 	SDL_RWops *rw = (SDL_RWops*) data;
   126 
   127 	offset = SDL_RWtell(rw);
   128 	SDL_RWseek(rw, 0, RW_SEEK_END);
   129 	size = SDL_RWtell(rw) - offset;
   130 	SDL_RWseek(rw, offset, RW_SEEK_SET);
   131 
   132 	if ((buffer = (char*) malloc(size))) {
   133 		if(SDL_RWread(rw, buffer, size, 1) == 1) {
   134 			if (fluidsynth.fluid_player_add_mem(song->player, buffer, size) == FLUID_OK) {
   135 				return 1;
   136 			} else {
   137 				Mix_SetError("FluidSynth failed to load in-memory song");
   138 			}
   139 		} else {
   140 			Mix_SetError("Failed to read in-memory song");
   141 		}
   142 		free(buffer);
   143 	} else {
   144 		Mix_SetError("Insufficient memory for song");
   145 	}
   146 	return 0;
   147 }
   148 
   149 FluidSynthMidiSong *fluidsynth_loadsong(const char *midifile)
   150 {
   151 	return fluidsynth_loadsong_common(fluidsynth_loadsong_internal, (void*) midifile);
   152 }
   153 
   154 FluidSynthMidiSong *fluidsynth_loadsong_RW(SDL_RWops *rw, int freerw)
   155 {
   156 	FluidSynthMidiSong *song;
   157 
   158 	song = fluidsynth_loadsong_common(fluidsynth_loadsong_RW_internal, (void*) rw);
   159 	if (freerw) {
   160 		SDL_RWclose(rw);
   161 	}
   162 	return song;
   163 }
   164 
   165 void fluidsynth_freesong(FluidSynthMidiSong *song)
   166 {
   167 	if (!song) return;
   168 	fluidsynth.delete_fluid_player(song->player);
   169 	fluidsynth.delete_fluid_settings(fluidsynth.fluid_synth_get_settings(song->synth));
   170 	fluidsynth.delete_fluid_synth(song->synth);
   171 	free(song);
   172 }
   173 
   174 void fluidsynth_start(FluidSynthMidiSong *song)
   175 {
   176 	fluidsynth.fluid_player_set_loop(song->player, 1);
   177 	fluidsynth.fluid_player_play(song->player);
   178 }
   179 
   180 void fluidsynth_stop(FluidSynthMidiSong *song)
   181 {
   182 	fluidsynth.fluid_player_stop(song->player);
   183 }
   184 
   185 int fluidsynth_active(FluidSynthMidiSong *song)
   186 {
   187 	return fluidsynth.fluid_player_get_status(song->player) == FLUID_PLAYER_PLAYING ? 1 : 0;
   188 }
   189 
   190 void fluidsynth_setvolume(FluidSynthMidiSong *song, int volume)
   191 {
   192 	/* FluidSynth's default is 0.2. Make 0.8 the maximum. */
   193 	fluidsynth.fluid_synth_set_gain(song->synth, (float) (volume * 0.00625));
   194 }
   195 
   196 int fluidsynth_playsome(FluidSynthMidiSong *song, void *dest, int dest_len)
   197 {
   198 	int result = -1;
   199 	int frames = dest_len / channels / ((format & 0xFF) / 8);
   200 	int src_len = frames * 4; /* 16-bit stereo */
   201 	void *src = dest;
   202 
   203 	if (dest_len < src_len) {
   204 		if (!(src = malloc(src_len))) {
   205 			Mix_SetError("Insufficient memory for audio conversion");
   206 			return result;
   207 		}
   208 	}
   209 
   210 	if (fluidsynth.fluid_synth_write_s16(song->synth, frames, src, 0, 2, src, 1, 2) != FLUID_OK) {
   211 		Mix_SetError("Error generating FluidSynth audio");
   212 		goto finish;
   213 	}
   214 
   215 	song->convert.buf = src;
   216 	song->convert.len = src_len;
   217 
   218 	if (SDL_ConvertAudio(&song->convert) < 0) {
   219 		Mix_SetError("Error during audio conversion");
   220 		goto finish;
   221 	}
   222 
   223 	if (src != dest)
   224 		memcpy(dest, src, dest_len);
   225 
   226 	result = 0;
   227 
   228 finish:
   229 	if (src != dest)
   230 		free(src);
   231 
   232 	return result;
   233 }
   234 
   235 #endif /* USE_FLUIDSYNTH_MIDI */