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
FLUIDSYNTH_Load()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
FLUIDSYNTH_Unload()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
fluidsynth_check_soundfont(const char * path,void * data)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
fluidsynth_load_soundfont(const char * path,void * data)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
FLUIDSYNTH_Open(const SDL_AudioSpec * spec)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
FLUIDSYNTH_LoadMusic(void * data)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
FLUIDSYNTH_CreateFromRW(SDL_RWops * src,int freesrc)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
FLUIDSYNTH_SetVolume(void * context,int volume)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
FLUIDSYNTH_Play(void * context,int play_count)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
FLUIDSYNTH_IsPlaying(void * context)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
FLUIDSYNTH_GetSome(void * context,void * data,int bytes,SDL_bool * done)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 }
FLUIDSYNTH_GetAudio(void * context,void * data,int bytes)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
FLUIDSYNTH_Stop(void * context)267 static void FLUIDSYNTH_Stop(void *context)
268 {
269 FLUIDSYNTH_Music *music = (FLUIDSYNTH_Music *)context;
270 fluidsynth.fluid_player_stop(music->player);
271 }
272
FLUIDSYNTH_Delete(void * context)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: */
310