Index: Makefile =================================================================== --- Makefile (revisión: 9596) +++ Makefile (copia de trabajo) @@ -224,6 +224,24 @@ endif endif +ifdef USE_FLUIDSYNTH_MIDI + ifeq ($(shell expr $(USE_FLUIDSYNTH_MIDI) \>= 1), 1) + # windows can have fluidsynth with any backend + ifeq ($(OSTYPE),mingw) + SOURCES += music/fluidsynth.cc + SOURCES += gui/loadsoundfont_frame.cc + LDFLAGS += -lfluidsynth -lglib-2.0 -lintl -liconv -ldsound -lole32 + CFLAGS += -DUSE_FLUIDSYNTH_MIDI + # but linux/mac will need sdl2 + else ifeq ($(BACKEND),sdl2) + SOURCES += music/fluidsynth.cc + SOURCES += gui/loadsoundfont_frame.cc + LDFLAGS += -lfluidsynth + CFLAGS += -DUSE_FLUIDSYNTH_MIDI + endif + endif +endif + CFLAGS += -Wall -Wextra -Wcast-qual -Wpointer-arith -Wcast-align $(FLAGS) CCFLAGS += -ansi -Wstrict-prototypes -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 @@ -568,7 +586,9 @@ ifeq ($(BACKEND),allegro) SOURCES += sys/simsys_d.cc SOURCES += sound/allegro_sound.cc - SOURCES += music/allegro_midi.cc + ifneq ($(shell expr $(USE_FLUIDSYNTH_MIDI) \>= 1), 1) + SOURCES += music/allegro_midi.cc + endif ifeq ($(ALLEGRO_CONFIG),) ALLEGRO_CFLAGS := ALLEGRO_LDFLAGS := -lalleg @@ -582,9 +602,11 @@ ifeq ($(BACKEND),gdi) SOURCES += sys/simsys_w.cc - SOURCES += music/w32_midi.cc SOURCES += sound/win32_sound_xa.cc - LDFLAGS += -lxaudio2_8 + LDFLAGS += -lxaudio2_8 + ifneq ($(shell expr $(USE_FLUIDSYNTH_MIDI) \>= 1), 1) + SOURCES += music/w32_midi.cc + endif endif ifeq ($(BACKEND),sdl) @@ -636,20 +658,28 @@ ifeq ($(shell expr $(AV_FOUNDATION) \>= 1), 1) # Core Audio (AVFoundation) base sound system routines SOURCES += sound/AVF_core-audio_sound.mm - SOURCES += music/AVF_core-audio_midi.mm LIBS += -framework Foundation -framework AVFoundation + ifneq ($(shell expr $(USE_FLUIDSYNTH_MIDI) \>= 1), 1) + SOURCES += music/AVF_core-audio_midi.mm + endif else # Core Audio (Quicktime) base sound system routines SOURCES += sound/core-audio_sound.mm - SOURCES += music/core-audio_midi.mm LIBS += -framework Foundation -framework QTKit + ifneq ($(shell expr $(USE_FLUIDSYNTH_MIDI) \>= 1), 1) + SOURCES += music/core-audio_midi.mm + endif endif else SOURCES += sound/sdl2_sound.cc ifneq ($(OSTYPE),mingw) - SOURCES += music/no_midi.cc + ifneq ($(shell expr $(USE_FLUIDSYNTH_MIDI) \>= 1), 1) + SOURCES += music/no_midi.cc + endif else - SOURCES += music/w32_midi.cc + ifneq ($(shell expr $(USE_FLUIDSYNTH_MIDI) \>= 1), 1) + SOURCES += music/w32_midi.cc + endif endif endif Index: config.default.in =================================================================== --- config.default.in (revisión: 9596) +++ config.default.in (copia de trabajo) @@ -52,6 +52,9 @@ # using zstd compression USE_ZSTD = @zstd@ +# using FluidSynth for MIDI playback (SDL2 backend needed for linux/macOS) +USE_FLUIDSYNTH_MIDI = @fluidsynth@ + # use static linking (to be at least somewhat portable) STATIC = 1 Index: config.template =================================================================== --- config.template (revisión: 9596) +++ config.template (copia de trabajo) @@ -50,6 +50,9 @@ # using zstd compression library #USE_ZSTD = 0 +# using FluidSynth for MIDI playback (SDL2 backend needed for linux/macOS) +#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: configure.ac =================================================================== --- configure.ac (revisión: 9596) +++ configure.ac (copia de trabajo) @@ -60,6 +60,11 @@ [AC_SUBST(freetype, 1)], [AC_SUBST(freetype, 0)], -lpng -lharfbuzz -lgraphite2 -lfreetype ) + # optional fluidsynth + AC_SEARCH_LIBS(new_fluid_settings, fluidsynth, + [AC_SUBST(fluidsynth, 1)], + [AC_SUBST(fluidsynth, 0)], + -lglib-2.0 -lintl -liconv -ldsound -lole32) else # optional upnp AC_SEARCH_LIBS(upnpDiscover, miniupnpc, @@ -70,6 +75,10 @@ [AC_SUBST(freetype, 1)], [AC_SUBST(freetype, 0)], -lpng ) + # optional fluidsynth + AC_SEARCH_LIBS(new_fluid_settings, fluidsynth, + [AC_SUBST(fluidsynth, 1)], + [AC_SUBST(fluidsynth, 0)] ) if uname | grep "Darwin" then AC_LANG_PUSH(Objective C++) Index: dataobj/environment.cc =================================================================== --- dataobj/environment.cc (revisión: 9596) +++ dataobj/environment.cc (copia de trabajo) @@ -72,6 +72,8 @@ uint32 env_t::sound_distance_scaling; sint16 env_t::midi_volume = 127; uint16 env_t::specific_volume[MAX_SOUND_TYPES]; +//Fluidsynth +std::string env_t::soundfont_filename; bool env_t::global_mute_sound = false; bool env_t::mute_midi = false; bool env_t::shuffle_midi = true; @@ -532,6 +534,13 @@ if( file->is_version_atleast( 122, 1 ) ) { file->rdwr_bool( env_t::numpad_always_moves_map ); } + if( file->is_version_atleast( 122, 2 ) ) { + plainstring str = soundfont_filename.c_str(); + file->rdwr_str( str ); + if (file->is_loading()) { + soundfont_filename = str ? str.c_str() : ""; + } + } // server settings are not saved, since they are server specific // and could be different on different servers on the same computers } Index: dataobj/environment.h =================================================================== --- dataobj/environment.h (revisión: 9596) +++ dataobj/environment.h (copia de trabajo) @@ -445,9 +445,11 @@ /// how dast are distant sounds fading (1: very fast 25: very little) static uint32 sound_distance_scaling; + // FluidSynth MIDI parameters + static std::string soundfont_filename; + /// @} - /// 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: 9596) +++ dataobj/settings.cc (copia de trabajo) @@ -1565,6 +1565,11 @@ // Default pak file path objfilename = ltrim(contents.get_string("pak_file_path", "" ) ); + // FluidSynth MIDI parameters + if( *contents.get("soundfont_filename") ) { + env_t::soundfont_filename = ltrim(contents.get("soundfont_filename")); + } + printf("Reading simuconf.tab successful!\n" ); } Index: gui/loadfont_frame.cc =================================================================== --- gui/loadfont_frame.cc (revisión: 9596) +++ gui/loadfont_frame.cc (copia de trabajo) @@ -101,7 +101,7 @@ /** * CHECK FILE - * Check if a file name qualifies to be added tot he item list. + * Check if a file name qualifies to be added to the item list. */ bool loadfont_frame_t::check_file(const char *filename, const char *) { Index: gui/loadsoundfont_frame.cc =================================================================== --- gui/loadsoundfont_frame.cc (nonexistent) +++ gui/loadsoundfont_frame.cc (copia de trabajo) @@ -0,0 +1,161 @@ +/* + * This file is part of the Simutrans project under the Artistic License. + * (see LICENSE.txt) + */ + +#include "../simdebug.h" + +#include + +#include "loadsoundfont_frame.h" + +#include "../pathes.h" + +#include "../dataobj/loadsave.h" +#include "../dataobj/translator.h" +#include "../dataobj/environment.h" + +#include "../music/music.h" +#include "../simsound.h" + +#include "gui_theme.h" + +#include "../utils/simstring.h" + +// static, since we keep them over reloading +std::string loadsoundfont_frame_t::old_soundfontname; + +/** + * Action that's started with a button click + */ +bool loadsoundfont_frame_t::item_action(const char *filename) +{ + if( dr_load_sf(filename) && midi_get_mute()){ + midi_set_mute(false); + midi_play( env_t::shuffle_midi ? -1 : 0 ); + } + return false; +} + + + +bool loadsoundfont_frame_t::ok_action(const char *filename) +{ + item_action(filename); + old_soundfontname.clear(); + return true; +} + + + +bool loadsoundfont_frame_t::cancel_action(const char *) +{ + dr_load_sf(old_soundfontname.c_str()); + old_soundfontname.clear(); + return true; +} + + + +loadsoundfont_frame_t::loadsoundfont_frame_t() : savegame_frame_t(NULL,false,NULL,false) +{ + + set_name(translator::translate("Select a soundfont")); + fnlabel.set_text( translator::translate("Soundfonts are searched on the music directory.") ); + top_frame.remove_component(&input); + delete_enabled = false; + //label_enabled = false; +} + + +const char *loadsoundfont_frame_t::get_info(const char *sfname) +{ + return sfname; +} + + +bool loadsoundfont_frame_t::compare_items ( const dir_entry_t & entry, const char *info, const char *) +{ + return (STRICMP(entry.info, info) > 0); +} + + +/** + * CHECK FILE + * Check if a file name qualifies to be added to the item list. + */ +bool loadsoundfont_frame_t::check_file(const char *filename, const char *) +{ + FILE *test = fopen( filename, "r" ); + if( test == NULL ) { + return false; + } + fclose(test); + + // just match textension for buildin soundfonts + const char *start_extension = strrchr(filename, '.' ); + if( start_extension && !STRICMP( start_extension, ".sf2" ) ) { + return true; + } + return false; +} + + +// parses the directory +void loadsoundfont_frame_t::fill_list() +{ + add_path( ((std::string)env_t::data_dir+"music/").c_str() ); + add_path( "/usr/share/soundfonts/" ); + add_path( "/usr/share/sounds/sf2/" ); + + if( old_soundfontname.empty() ) { + old_soundfontname = env_t::soundfont_filename; + } + + // do the search ... + savegame_frame_t::fill_list(); + + // mark current fonts + FOR(slist_tpl, const& i, entries) { + if (i.type == LI_HEADER) { + continue; + } + i.button->set_typ(button_t::roundbox_state | button_t::flexible); + } + + // force new resize after we have rearranged the gui + resize(scr_coord(0,0)); +} + + + +void loadsoundfont_frame_t::draw(scr_coord pos, scr_size size) +{ + // mark current fonts + FOR(slist_tpl, const& i, entries) { + if (i.type == LI_HEADER) { + continue; + } + i.button->pressed = strstr( env_t::soundfont_filename.c_str(), i.info ); + } + savegame_frame_t::draw(pos, size); +} + + + +void loadsoundfont_frame_t::rdwr( loadsave_t *file ) +{ + scr_size size = get_windowsize(); + size.rdwr( file ); + if( file->is_loading() ) { + set_windowsize( size ); + resize( scr_coord(0,0) ); + } +} + + +bool loadsoundfont_frame_t::action_triggered(gui_action_creator_t *component, value_t v) +{ + + return savegame_frame_t::action_triggered(component,v); +} Index: gui/loadsoundfont_frame.h =================================================================== --- gui/loadsoundfont_frame.h (nonexistent) +++ gui/loadsoundfont_frame.h (copia de trabajo) @@ -0,0 +1,54 @@ +/* + * This file is part of the Simutrans project under the Artistic License. + * (see LICENSE.txt) + */ + +#include "simwin.h" +#include "savegame_frame.h" + +#include "components/action_listener.h" +#include "components/gui_button.h" + +#include "../tpl/stringhashtable_tpl.h" +#include + + +class loadsoundfont_frame_t : public savegame_frame_t +{ + +protected: + static std::string old_soundfontname; + + /** + * Action that's started with a button click + */ + bool item_action (const char *filename) OVERRIDE; + bool ok_action (const char *fullpath) OVERRIDE; + bool cancel_action(const char *) OVERRIDE; + + // returns extra file info + const char *get_info(const char *fname) OVERRIDE; + + // sort with respect to info, which is date + bool compare_items ( const dir_entry_t & entry, const char *info, const char *) OVERRIDE; + + bool check_file( const char *filename, const char *suffix ) OVERRIDE; + + void fill_list() OVERRIDE; + +public: + /** + * Set the window associated helptext + * @return the filename for the helptext, or NULL + */ + const char *get_help_filename() const OVERRIDE { return "load_soundfont.txt"; } + + loadsoundfont_frame_t(); + + void draw(scr_coord pos, scr_size size) OVERRIDE; + + uint32 get_rdwr_id( void ) OVERRIDE { return magic_soundfont; } + void rdwr( loadsave_t *file ) OVERRIDE; + + bool action_triggered(gui_action_creator_t *, value_t v) OVERRIDE; +}; Index: gui/simwin.cc =================================================================== --- gui/simwin.cc (revisión: 9596) +++ gui/simwin.cc (copia de trabajo) @@ -58,6 +58,9 @@ #include "themeselector.h" #include "goods_frame_t.h" #include "loadfont_frame.h" +#ifdef USE_FLUIDSYNTH_MIDI +#include "loadsoundfont_frame.h" +#endif #include "scenario_info.h" #include "depot_frame.h" #include "depotlist_frame.h" @@ -573,6 +576,9 @@ case magic_factory_info: w = new fabrik_info_t(); break; case magic_goodslist: w = new goods_frame_t(); break; case magic_font: w = new loadfont_frame_t(); break; +#ifdef USE_FLUIDSYNTH_MIDI + case magic_soundfont: w = new loadsoundfont_frame_t(); break; +#endif case magic_scenario_info: w = new scenario_info_t(); break; case magic_depot: w = new depot_frame_t(); break; case magic_convoi_list: w = new convoi_frame_t(); break; Index: gui/simwin.h =================================================================== --- gui/simwin.h (revisión: 9596) +++ gui/simwin.h (copia de trabajo) @@ -104,6 +104,9 @@ magic_motd, magic_factory_info, // only used to load/save magic_font, +#ifdef USE_FLUIDSYNTH_MIDI + magic_soundfont, +#endif magic_edit_groundobj, // magic numbers with big jumps between them Index: gui/sound_frame.cc =================================================================== --- gui/sound_frame.cc (revisión: 9596) +++ gui/sound_frame.cc (copia de trabajo) @@ -11,6 +11,9 @@ #include "../dataobj/translator.h" #include "../dataobj/environment.h" #include "components/gui_divider.h" +#ifdef USE_FLUIDSYNTH_MIDI +#include "loadsoundfont_frame.h" +#endif #define L_KNOB_SIZE (32) @@ -17,15 +20,23 @@ void sound_frame_t::update_song_name() { const int current_midi = get_current_midi(); - - if(current_midi >= 0) { - song_name_label.buf().printf("%d - %s", current_midi+1, sound_get_midi_title(current_midi)); + if(current_midi < 0) { + song_name_label.buf().printf( translator::translate("Music playing disabled/not available") ); } +#ifdef USE_FLUIDSYNTH_MIDI + else if( strcmp(env_t::soundfont_filename.c_str(), "Error") == 0 ){ + song_name_label.buf().printf( translator::translate("Soundfont not found. Please select a soundfont below") ); + } +#endif else { - song_name_label.buf().printf("Music playing disabled/not available" ); + song_name_label.buf().printf("%d - %s", current_midi+1, sound_get_midi_title(current_midi)); } song_name_label.update(); song_name_label.set_size( song_name_label.get_min_size() ); + //Loadsounfont dialog may unmute us, update mute status + music_mute_button.pressed = midi_get_mute(); + previous_song_button.enable(!music_mute_button.pressed); + next_song_button.enable(!music_mute_button.pressed); } @@ -89,6 +100,11 @@ music_mute_button.init( button_t::square_state, "disable midi"); music_mute_button.pressed = midi_get_mute(); music_mute_button.add_listener( this ); +#ifdef USE_FLUIDSYNTH_MIDI + if(strcmp(env_t::soundfont_filename.c_str(), "Error") == 0){ + music_mute_button.enable(!music_mute_button.pressed); + } +#endif add_component(&music_mute_button); add_table(2,0); @@ -110,10 +126,12 @@ { previous_song_button.set_typ( button_t::arrowleft ); previous_song_button.add_listener( this ); + previous_song_button.enable(!music_mute_button.pressed); add_component( &previous_song_button ); next_song_button.set_typ( button_t::arrowright ); next_song_button.add_listener( this ); + next_song_button.enable(!music_mute_button.pressed); add_component( &next_song_button ); add_component( &song_name_label ); @@ -125,6 +143,13 @@ shuffle_song_button.pressed = sound_get_shuffle_midi(); shuffle_song_button.add_listener(this); add_component(&shuffle_song_button); + +#ifdef USE_FLUIDSYNTH_MIDI + // Soundfont selection + soundfont_button.init( button_t::roundbox_state | button_t::flexible, translator::translate("Select a soundfont") ); + soundfont_button.add_listener(this); + add_component( &soundfont_button ); +#endif set_resizemode(diagonal_resize); reset_min_windowsize(); @@ -157,6 +182,7 @@ midi_set_mute( !music_mute_button.pressed ); music_mute_button.pressed = midi_get_mute(); previous_song_button.enable(!music_mute_button.pressed); + next_song_button.enable(!music_mute_button.pressed); } else if (comp == &sound_volume_scrollbar) { sound_set_global_volume(p.i); @@ -167,6 +193,11 @@ else if (comp == &sound_range) { env_t::sound_distance_scaling = p.i; } +#ifdef USE_FLUIDSYNTH_MIDI + else if (comp == &soundfont_button){ + create_win( new loadsoundfont_frame_t(), w_info, magic_soundfont ); + } +#endif else { for( int i = 0; i < MAX_SOUND_TYPES; i++ ) { if( comp == specific_volume_scrollbar[ i ] ) { @@ -187,6 +218,11 @@ { // update song name label update_song_name(); +#ifdef USE_FLUIDSYNTH_MIDI + if(!strcmp(env_t::soundfont_filename.c_str(), "Error") == 0){ + music_mute_button.enable(true); + } +#endif gui_frame_t::draw(pos, size); } Index: gui/sound_frame.h =================================================================== --- gui/sound_frame.h (revisión: 9596) +++ gui/sound_frame.h (copia de trabajo) @@ -30,6 +30,9 @@ button_t next_song_button; button_t previous_song_button; button_t shuffle_song_button; +#ifdef USE_FLUIDSYNTH_MIDI + button_t soundfont_button; +#endif gui_label_buf_t song_name_label; void update_song_name(); Index: music/fluidsynth.cc =================================================================== --- music/fluidsynth.cc (nonexistent) +++ music/fluidsynth.cc (copia de trabajo) @@ -0,0 +1,196 @@ +/* + * This file is part of the Simutrans project under the Artistic License. + * (see LICENSE.txt) + */ +#include + +#include "../simdebug.h" +#include "../utils/plainstring.h" +#include "../dataobj/environment.h" +#include "music.h" +#ifndef _WIN32 + #include +#endif + +// fluidsynth music routine interfaces +static int midi_number = -1; +static plainstring midi_filenames[MAX_MIDI]; +int previous_id = -1; +bool midi_initialized = false; + +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[] = { + /* RedHat/Fedora/Arch preferred */ + "/usr/share/soundfonts/sf2/default.sf2", + "/usr/share/soundfonts/sf2/freepats-general-midi.sf2", + "/usr/share/soundfonts/FluidR3_GM.sf2", + + /* Debian/Ubuntu/OpenSUSE preferred */ + "/usr/share/sounds/sf2/default.sf2", + "/usr/share/sounds/sf2/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) +{ + 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) +{ + // Check if player has been initialized before + if(dr_midi_pos() != -1) { + fluid_player_stop(player); + fluid_synth_all_sounds_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. Create the audio driver +* 5. Load a soundfont +*/ + +bool dr_load_sf(const char * filename){ + + if( midi_initialized && fluid_is_soundfont(filename) ) + { + int next_id = fluid_synth_sfload(synth, filename, 1); + if (next_id != FLUID_FAILED){ + if (previous_id != -1){ + fluid_synth_sfunload(synth,previous_id,1); + } + previous_id = next_id; + env_t::soundfont_filename = filename; + return true; + } + } + return false; +} + +bool dr_init_midi() +{ + settings = new_fluid_settings(); +#ifdef _WIN32 + fluid_settings_setstr(settings, "audio.driver", "dsound"); +#else + // if audio subsys is ok + if(SDL_InitSubSystem(SDL_INIT_AUDIO) != -1) { + fluid_settings_setstr(settings, "audio.driver", "sdl2"); +#endif + if( ( synth = new_fluid_synth(settings) ) != NULL ) { + if ( ( player = new_fluid_player(synth) ) != NULL ) { + if( ( adriver = new_fluid_audio_driver(settings, synth) ) != NULL ) { + // MIDI system has been initialed even if no soundfont was loaded. A user can load a soundfont after. + midi_initialized = true; + // We try user defined font first + bool error = false; + if( !dr_load_sf( env_t::soundfont_filename.c_str() ) && + !dr_load_sf( ((std::string)env_t::data_dir+"music/"+env_t::soundfont_filename).c_str() )) + { + // We try the predefined list of soundfonts + error = true; + for (int i = 0; default_sf[i]; i++) { + if( dr_load_sf(default_sf[i]) ) { + error = false; + } + } + if( error ) { + env_t::soundfont_filename = "Error"; + 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" ); +#ifndef _WIN32 + } else dbg->warning( "dr_init_midi()", "Could not init SDL Audio" ); +#endif + return midi_initialized; +} Index: music/music.h =================================================================== --- music/music.h (revisión: 9596) +++ music/music.h (copia de trabajo) @@ -55,4 +55,11 @@ */ void dr_destroy_midi(); +/** + * Load a soundfont. Only available if we are using fluidsynth. + */ +#ifdef USE_FLUIDSYNTH_MIDI +bool dr_load_sf(const char * filename); #endif + +#endif Index: simmain.cc =================================================================== --- simmain.cc (revisión: 9596) +++ simmain.cc (copia de trabajo) @@ -22,6 +22,7 @@ #include "display/simview.h" #include "gui/simwin.h" #include "gui/gui_theme.h" +#include "gui/messagebox.h" #include "simhalt.h" #include "display/simimg.h" #include "simcolor.h" @@ -696,9 +697,14 @@ if(simuconf.open(path_to_simuconf)) { // we do not allow to change the global font name std::string old_fontname = env_t::fontname; + std::string old_soundfont_filename = env_t::soundfont_filename; printf("parse_simuconf() at config/simuconf.tab: "); env_t::default_settings.parse_simuconf( simuconf, disp_width, disp_height, fullscreen, env_t::objfilename ); simuconf.close(); + if ( (old_soundfont_filename.length() > 0) && (strcmp(old_soundfont_filename.c_str() , "Error") != 0) ) { + // We had a valid soundfont saved by the user, let's restore it + env_t::soundfont_filename = old_soundfont_filename; + } env_t::fontname = old_fontname; } } @@ -1293,20 +1299,25 @@ dr_chdir( env_t::user_dir ); // init midi before loading sounds - if( dr_init_midi() ) { + if( dr_init_midi() ) { dbg->message("simu_main()","Reading midi data ..."); char pak_dir[PATH_MAX]; sprintf( pak_dir, "%s%s", env_t::data_dir, env_t::objfilename.c_str() ); - if( !midi_init(pak_dir) ) { - if( !midi_init(env_t::user_dir) ) { - if( !midi_init(env_t::data_dir) ) { - dbg->message("simu_main()","Midi disabled ..."); - } - } - } + if( midi_init(pak_dir) || midi_init(env_t::user_dir) || midi_init(env_t::data_dir) ) { + midi_set_mute(false); + } else { + midi_set_mute(true); + dbg->message("simu_main()","Midi disabled ..."); + } if(gimme_arg(argc, argv, "-nomidi", 0)) { midi_set_mute(true); } +#ifdef USE_FLUIDSYNTH_MIDI + // Audio is ok, but we failed to find a soundfont + if( strcmp(env_t::soundfont_filename.c_str(), "Error") == 0 ){ + midi_set_mute(true); + } +#endif } else { dbg->message("simu_main()","Midi disabled ..."); @@ -1484,6 +1495,11 @@ if( !env_t::networkmode && !env_t::server && new_world ) { welt->get_message()->clear(); } +#ifdef USE_FLUIDSYNTH_MIDI + if( strcmp(env_t::soundfont_filename.c_str(), "Error") == 0 ) { + create_win( new news_img(translator::translate("No soundfont found!\n\nMusic won't play until you load a soundfont from the sound options menu.")), w_info, magic_none); + } +#endif while( !env_t::quit_simutrans ) { // play next tune? check_midi(); Index: simutrans/config/simuconf.tab =================================================================== --- simutrans/config/simuconf.tab (revisión: 9596) +++ simutrans/config/simuconf.tab (copia de trabajo) @@ -599,6 +599,14 @@ #################################system stuff################################# +# Set this for playing MIDI music with your preferred soundfont. +# Need Fluidsynth support. +# A recommended lightweight (30 MB) soundfont is PCLite: +# https://src.fedoraproject.org/repo/pkgs/PersonalCopy-Lite-soundfont/PCLite.sf2/629732b7552c12a8fae5b046d306273a/ +# But there are many more, including greater quality ones. +# Set either the full path or the name of the .sf2 soundfont saved into the "music" directory +soundfont_filename = PCLite.sf2 + # File format for saved games # Uncompressed formats: # - binary Uncompressed binary data