a855d62025
This ports Fabien Sanglard's Chocolate Duke to run on a version of SDL for Rockbox. Change-Id: I8f2c4c78af19de10c1633ed7bb7a997b43256dd9
219 lines
5.8 KiB
C
219 lines
5.8 KiB
C
/*
|
|
SDL_mixer: An audio mixer library based on the SDL library
|
|
Copyright (C) 1997-2012 Sam Lantinga <slouken@libsdl.org>
|
|
|
|
This software is provided 'as-is', without any express or implied
|
|
warranty. In no event will the authors be held liable for any damages
|
|
arising from the use of this software.
|
|
|
|
Permission is granted to anyone to use this software for any purpose,
|
|
including commercial applications, and to alter it and redistribute it
|
|
freely, subject to the following restrictions:
|
|
|
|
1. The origin of this software must not be misrepresented; you must not
|
|
claim that you wrote the original software. If you use this software
|
|
in a product, an acknowledgment in the product documentation would be
|
|
appreciated but is not required.
|
|
2. Altered source versions must be plainly marked as such, and must not be
|
|
misrepresented as being the original software.
|
|
3. This notice may not be removed or altered from any source distribution.
|
|
|
|
James Le Cuirot
|
|
chewi@aura-online.co.uk
|
|
*/
|
|
|
|
#ifdef USE_FLUIDSYNTH_MIDI
|
|
|
|
#include "SDL_mixer.h"
|
|
#include "fluidsynth.h"
|
|
|
|
static Uint16 format;
|
|
static Uint8 channels;
|
|
static int freq;
|
|
|
|
int fluidsynth_check_soundfont(const char *path, void *data)
|
|
{
|
|
FILE *file = fopen(path, "r");
|
|
|
|
if (file) {
|
|
fclose(file);
|
|
return 1;
|
|
} else {
|
|
Mix_SetError("Failed to access the SoundFont %s", path);
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
int fluidsynth_load_soundfont(const char *path, void *data)
|
|
{
|
|
/* If this fails, it's too late to try Timidity so pray that at least one works. */
|
|
fluidsynth.fluid_synth_sfload((fluid_synth_t*) data, path, 1);
|
|
return 1;
|
|
}
|
|
|
|
int fluidsynth_init(SDL_AudioSpec *mixer)
|
|
{
|
|
if (!Mix_EachSoundFont(fluidsynth_check_soundfont, NULL))
|
|
return -1;
|
|
|
|
format = mixer->format;
|
|
channels = mixer->channels;
|
|
freq = mixer->freq;
|
|
|
|
return 0;
|
|
}
|
|
|
|
static FluidSynthMidiSong *fluidsynth_loadsong_common(int (*function)(FluidSynthMidiSong*, void*), void *data)
|
|
{
|
|
FluidSynthMidiSong *song;
|
|
fluid_settings_t *settings = NULL;
|
|
|
|
if (!Mix_Init(MIX_INIT_FLUIDSYNTH)) {
|
|
return NULL;
|
|
}
|
|
|
|
if ((song = SDL_malloc(sizeof(FluidSynthMidiSong)))) {
|
|
memset(song, 0, sizeof(FluidSynthMidiSong));
|
|
|
|
if (SDL_BuildAudioCVT(&song->convert, AUDIO_S16, 2, freq, format, channels, freq) >= 0) {
|
|
if ((settings = fluidsynth.new_fluid_settings())) {
|
|
fluidsynth.fluid_settings_setnum(settings, "synth.sample-rate", (double) freq);
|
|
|
|
if ((song->synth = fluidsynth.new_fluid_synth(settings))) {
|
|
if (Mix_EachSoundFont(fluidsynth_load_soundfont, (void*) song->synth)) {
|
|
if ((song->player = fluidsynth.new_fluid_player(song->synth))) {
|
|
if (function(song, data)) return song;
|
|
fluidsynth.delete_fluid_player(song->player);
|
|
} else {
|
|
Mix_SetError("Failed to create FluidSynth player");
|
|
}
|
|
}
|
|
fluidsynth.delete_fluid_synth(song->synth);
|
|
} else {
|
|
Mix_SetError("Failed to create FluidSynth synthesizer");
|
|
}
|
|
fluidsynth.delete_fluid_settings(settings);
|
|
} else {
|
|
Mix_SetError("Failed to create FluidSynth settings");
|
|
}
|
|
} else {
|
|
Mix_SetError("Failed to set up audio conversion");
|
|
}
|
|
SDL_free(song);
|
|
} else {
|
|
Mix_SetError("Insufficient memory for song");
|
|
}
|
|
return NULL;
|
|
}
|
|
|
|
static int fluidsynth_loadsong_RW_internal(FluidSynthMidiSong *song, void *data)
|
|
{
|
|
off_t offset;
|
|
size_t size;
|
|
char *buffer;
|
|
SDL_RWops *rw = (SDL_RWops*) data;
|
|
|
|
offset = SDL_RWtell(rw);
|
|
SDL_RWseek(rw, 0, RW_SEEK_END);
|
|
size = SDL_RWtell(rw) - offset;
|
|
SDL_RWseek(rw, offset, RW_SEEK_SET);
|
|
|
|
if ((buffer = (char*) SDL_malloc(size))) {
|
|
if(SDL_RWread(rw, buffer, size, 1) == 1) {
|
|
if (fluidsynth.fluid_player_add_mem(song->player, buffer, size) == FLUID_OK) {
|
|
return 1;
|
|
} else {
|
|
Mix_SetError("FluidSynth failed to load in-memory song");
|
|
}
|
|
} else {
|
|
Mix_SetError("Failed to read in-memory song");
|
|
}
|
|
SDL_free(buffer);
|
|
} else {
|
|
Mix_SetError("Insufficient memory for song");
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
FluidSynthMidiSong *fluidsynth_loadsong_RW(SDL_RWops *rw, int freerw)
|
|
{
|
|
FluidSynthMidiSong *song;
|
|
|
|
song = fluidsynth_loadsong_common(fluidsynth_loadsong_RW_internal, (void*) rw);
|
|
if (freerw) {
|
|
SDL_RWclose(rw);
|
|
}
|
|
return song;
|
|
}
|
|
|
|
void fluidsynth_freesong(FluidSynthMidiSong *song)
|
|
{
|
|
if (!song) return;
|
|
fluidsynth.delete_fluid_player(song->player);
|
|
fluidsynth.delete_fluid_settings(fluidsynth.fluid_synth_get_settings(song->synth));
|
|
fluidsynth.delete_fluid_synth(song->synth);
|
|
SDL_free(song);
|
|
}
|
|
|
|
void fluidsynth_start(FluidSynthMidiSong *song)
|
|
{
|
|
fluidsynth.fluid_player_set_loop(song->player, 1);
|
|
fluidsynth.fluid_player_play(song->player);
|
|
}
|
|
|
|
void fluidsynth_stop(FluidSynthMidiSong *song)
|
|
{
|
|
fluidsynth.fluid_player_stop(song->player);
|
|
}
|
|
|
|
int fluidsynth_active(FluidSynthMidiSong *song)
|
|
{
|
|
return fluidsynth.fluid_player_get_status(song->player) == FLUID_PLAYER_PLAYING ? 1 : 0;
|
|
}
|
|
|
|
void fluidsynth_setvolume(FluidSynthMidiSong *song, int volume)
|
|
{
|
|
/* FluidSynth's default is 0.2. Make 0.8 the maximum. */
|
|
fluidsynth.fluid_synth_set_gain(song->synth, (float) (volume * 0.00625));
|
|
}
|
|
|
|
int fluidsynth_playsome(FluidSynthMidiSong *song, void *dest, int dest_len)
|
|
{
|
|
int result = -1;
|
|
int frames = dest_len / channels / ((format & 0xFF) / 8);
|
|
int src_len = frames * 4; /* 16-bit stereo */
|
|
void *src = dest;
|
|
|
|
if (dest_len < src_len) {
|
|
if (!(src = SDL_malloc(src_len))) {
|
|
Mix_SetError("Insufficient memory for audio conversion");
|
|
return result;
|
|
}
|
|
}
|
|
|
|
if (fluidsynth.fluid_synth_write_s16(song->synth, frames, src, 0, 2, src, 1, 2) != FLUID_OK) {
|
|
Mix_SetError("Error generating FluidSynth audio");
|
|
goto finish;
|
|
}
|
|
|
|
song->convert.buf = src;
|
|
song->convert.len = src_len;
|
|
|
|
if (SDL_ConvertAudio(&song->convert) < 0) {
|
|
Mix_SetError("Error during audio conversion");
|
|
goto finish;
|
|
}
|
|
|
|
if (src != dest)
|
|
memcpy(dest, src, dest_len);
|
|
|
|
result = 0;
|
|
|
|
finish:
|
|
if (src != dest)
|
|
SDL_free(src);
|
|
|
|
return result;
|
|
}
|
|
|
|
#endif /* USE_FLUIDSYNTH_MIDI */
|