Index: Makefile =================================================================== --- Makefile (revisión: 9201) +++ Makefile (copia de trabajo) @@ -620,6 +620,10 @@ SOURCES += sound/AVF_core-audio_sound.mm SOURCES += music/AVF_core-audio_midi.mm LIBS += -framework Foundation -framework AVFoundation + else ifeq ($(shell expr $(USE_FLUIDSYNTH_MIDI) \>= 1), 1) + SOURCES += music/fluidsynth.cc + LIBS += -lfluidsynth + CFLAGS += -DUSE_FLUIDSYNTH_MIDI else # Core Audio (Quicktime) base sound system routines SOURCES += sound/core-audio_sound.mm @@ -629,9 +633,21 @@ else SOURCES += sound/sdl2_sound.cc ifneq ($(OSTYPE),mingw) - SOURCES += music/no_midi.cc + ifeq ($(shell expr $(USE_FLUIDSYNTH_MIDI) \>= 1), 1) + SOURCES += music/fluidsynth.cc + LDFLAGS += -lfluidsynth + CFLAGS += -DUSE_FLUIDSYNTH_MIDI + else + SOURCES += music/no_midi.cc + endif else - SOURCES += music/w32_midi.cc + ifeq ($(shell expr $(USE_FLUIDSYNTH_MIDI) \>= 1), 1) + SOURCES += music/fluidsynth.cc + LIBS += -lfluidsynth + CFLAGS += -DUSE_FLUIDSYNTH_MIDI + else + SOURCES += music/w32_midi.cc + endif endif endif Index: config.template =================================================================== --- config.template (revisión: 9201) +++ config.template (copia de trabajo) @@ -50,6 +50,9 @@ # using zstd compression library #USE_ZSTD = 0 +# using FluidSynth for MIDI playback if available (SDL2 backend required) +#USE_FLUIDSYNTH_MIDI = 1 + # Define these as empty strings, if you don't have the respective config program #ALLEGRO_CONFIG = allegro-config #PNG_CONFIG = pkg-config libpng Index: dataobj/environment.cc =================================================================== --- dataobj/environment.cc (revisión: 9201) +++ dataobj/environment.cc (copia de trabajo) @@ -71,6 +71,9 @@ uint32 env_t::sound_distance_scaling; sint16 env_t::midi_volume = 127; uint16 env_t::specific_volume[MAX_SOUND_TYPES]; +#ifdef USE_FLUIDSYNTH_MIDI +std::string env_t::soundfont_filename; +#endif bool env_t::global_mute_sound = false; bool env_t::mute_midi = false; bool env_t::shuffle_midi = true; Index: dataobj/environment.h =================================================================== --- dataobj/environment.h (revisión: 9201) +++ dataobj/environment.h (copia de trabajo) @@ -433,9 +433,13 @@ /// how dast are distant sounds fading (1: very fast 25: very little) static uint32 sound_distance_scaling; + // FluidSynth MIDI parameters + #ifdef USE_FLUIDSYNTH_MIDI + static std::string soundfont_filename; + #endif + /// @} - /// if true this will show a softkeyboard only when editing text /// default is off static bool hide_keyboard; Index: dataobj/settings.cc =================================================================== --- dataobj/settings.cc (revisión: 9201) +++ dataobj/settings.cc (copia de trabajo) @@ -1543,6 +1543,13 @@ // Default pak file path objfilename = ltrim(contents.get_string("pak_file_path", "" ) ); + // FluidSynth MIDI parameters + #ifdef USE_FLUIDSYNTH_MIDI + if( *contents.get("soundfont_filename") ) { + env_t::soundfont_filename = ltrim(contents.get("soundfont_filename")); + } + #endif + printf("Reading simuconf.tab successful!\n" ); } Index: music/fluidsynth.cc =================================================================== --- music/fluidsynth.cc (nonexistent) +++ music/fluidsynth.cc (copia de trabajo) @@ -0,0 +1,158 @@ +/* + * This file is part of the Simutrans project under the Artistic License. + * (see LICENSE.txt) + */ + +#include +#include + +#include "../simdebug.h" +#include "../utils/plainstring.h" +#include "../dataobj/environment.h" +#include "music.h" + +// fluidsynth music routine interfaces +static int midi_number = -1; +static plainstring midi_filenames[MAX_MIDI]; + +fluid_settings_t* settings; +fluid_synth_t* synth; +fluid_audio_driver_t* adriver; +fluid_player_t* player; + +// Predefined list of paths to search for soundfonts +static const char * default_sf[] = { + /* Debian/Ubuntu/OpenSUSE preferred */ + "/usr/share/sounds/sf2/FluidR3_GM.sf2", + + /* RedHat/Fedora/Arch preferred */ + "/usr/share/soundfonts/FluidR3_GM.sf2", + + /* Debian/Ubuntu/OpenSUSE alternatives */ + "/usr/share/sounds/sf2/TimGM6mb.sf2", + "/usr/share/sounds/sf2/FluidR3_GS.sf2", + + nullptr +}; + +/** + * sets midi playback volume + */ +void dr_set_midi_volume(int vol) +{ + /* Allowed range of synth.gain is 0.0 to 10.0 */ + /* fluidsynth's default gain is 0.2, so use this as "full + * volume". Set gain using Simutrans's volume, as a number between 0 + * and 0.2. */ + double gain = 0.8 * vol / 256.0; + if (fluid_settings_setnum(settings, "synth.gain", gain) != FLUID_OK) { + dbg->warning( "dr_set_midi_volume()", "Could not set volume" ); + } +} + +/** + * Loads a MIDI file + */ +int dr_load_midi(const char * filename) +{ + if(midi_number < MAX_MIDI - 1) { + const int i = midi_number + 1; + + if(i >= 0 && i < MAX_MIDI) { + if (fluid_is_midifile(filename)) { + midi_number = i; + midi_filenames[i] = filename; + } + else { + dbg->warning( "dr_load_midi()", "Failed to load MIDI %s", filename ); + } + } + } + return midi_number; +} + +/** + * Plays a MIDI file + */ +void dr_play_midi(int key) +{ + if(dr_midi_pos() != -1) { + dr_stop_midi(); + } + if ( ( player = new_fluid_player(synth) ) != NULL ){ + fluid_player_add(player, midi_filenames[key]); + fluid_player_play(player); + } else dbg->warning( "dr_play_midi()", "Could not create music player" ); +} + +/** + * Stops playing MIDI file + */ +void dr_stop_midi(void) +{ + fluid_player_stop(player); + fluid_synth_all_notes_off(synth,-1); + delete_fluid_player(player); +} + +/** + * Returns the midi_pos variable <- doesn't actually do this + * Simutrans only needs to know whether file has finished (so that it can start the next music) + * Returns -1 if current music has finished, else 0 + */ +sint32 dr_midi_pos(void) +{ + if(fluid_player_get_status(player) != FLUID_PLAYER_PLAYING) { + return -1; + } + else { + return 0; + } +} + +/** + * Midi shutdown/cleanup + */ +void dr_destroy_midi(void) +{ + dr_stop_midi(); + delete_fluid_audio_driver(adriver); + delete_fluid_synth(synth); + delete_fluid_settings(settings); + midi_number = -1; +} + +/* +* 1. Create the settings object +* 2. Create the synthesizer +* 3. Create the player +* 4. Load a soundfont +* 5. Create the audio driver +*/ +bool dr_init_midi() { + // if audio subsys is ok + if(SDL_InitSubSystem(SDL_INIT_AUDIO) != -1) { + settings = new_fluid_settings(); + fluid_settings_setstr(settings, "audio.driver", "sdl2"); + if( ( synth = new_fluid_synth(settings) ) != NULL ) { + if ( ( player = new_fluid_player(synth) ) != NULL ){ + if( ( adriver = new_fluid_audio_driver(settings, synth) ) != NULL ) { + // User defined font first + if( fluid_is_soundfont(env_t::soundfont_filename.c_str()) && + fluid_synth_sfload(synth, env_t::soundfont_filename.c_str(), 1) != FLUID_FAILED ) { + return true; + } else { // We try the predefined list of soundfonts + for (int i = 0; default_sf[i]; i++) { + if( fluid_is_soundfont(default_sf[i]) && + fluid_synth_sfload(synth, default_sf[i], 1) != FLUID_FAILED ) { + return true; + } + } + } + dbg->warning( "dr_init_midi()", "No soundfont was found" ); + } else dbg->warning( "dr_init_midi()", "Could not create audio driver" ); + } else dbg->warning( "dr_init_midi()", "Could not create music player" ); + } else dbg->warning( "dr_init_midi()", "Could not create synthesizer" ); + } else dbg->warning( "dr_init_midi()", "Could not init SDL Audio" ); + return false; +} Index: simutrans/config/simuconf.tab =================================================================== --- simutrans/config/simuconf.tab (revisión: 9201) +++ simutrans/config/simuconf.tab (copia de trabajo) @@ -595,6 +595,8 @@ #################################system stuff################################# +# soundfont_filename = /usr/share/sounds/sf2/FluidR3_GM.sf2 + # compress savegames? # "binary" means uncompressed, "zipped" means compressed # "bzip2" uses another compression algorithm