diff --git a/src/music/fluidsynth.cpp b/src/music/fluidsynth.cpp --- a/src/music/fluidsynth.cpp +++ b/src/music/fluidsynth.cpp @@ -15,11 +15,13 @@ #include "midifile.hpp" #include #include "../mixer.h" +#include static struct { fluid_settings_t* settings; ///< FluidSynth settings handle fluid_synth_t* synth; ///< FluidSynth synthesizer handle fluid_player_t* player; ///< FluidSynth MIDI player handle + std::mutex synth_mutex; ///< Guard mutex for synth access } _midi; ///< Metadata about the midi we're playing. /** Factory for the FluidSynth driver. */ @@ -42,12 +44,16 @@ static const char *default_sf[] = { static void RenderMusicStream(int16 *buffer, size_t samples) { - if (!_midi.synth || !_midi.player) return; + std::unique_lock lock{ _midi.synth_mutex, std::try_to_lock }; + + if (!lock.owns_lock() || !_midi.synth || !_midi.player) return; fluid_synth_write_s16(_midi.synth, samples, buffer, 0, 2, buffer, 1, 2); } const char *MusicDriver_FluidSynth::Start(const char * const *param) { + std::lock_guard lock{ _midi.synth_mutex }; + const char *sfont_name = GetDriverParam(param, "soundfont"); int sfont_id; @@ -59,6 +65,11 @@ const char *MusicDriver_FluidSynth::Star /* Don't try to lock sample data in memory, OTTD usually does not run with privileges allowing that */ fluid_settings_setint(_midi.settings, "synth.lock-memory", 0); + /* Install the music render routine and set up the samplerate */ + uint32 samplerate = MxSetMusicSource(RenderMusicStream); + fluid_settings_setnum(_midi.settings, "synth.sample-rate", samplerate); + DEBUG(driver, 1, "Fluidsynth: samplerate %.0f", (float)samplerate); + /* Create the synthesizer. */ _midi.synth = new_fluid_synth(_midi.settings); if (!_midi.synth) return "Could not open synth"; @@ -81,19 +92,23 @@ const char *MusicDriver_FluidSynth::Star _midi.player = nullptr; - uint32 samplerate = MxSetMusicSource(RenderMusicStream); - fluid_synth_set_sample_rate(_midi.synth, samplerate); - DEBUG(driver, 1, "Fluidsynth: samplerate %.0f", (float)samplerate); - return nullptr; } void MusicDriver_FluidSynth::Stop() { MxSetMusicSource(nullptr); - this->StopSong(); - delete_fluid_synth(_midi.synth); - delete_fluid_settings(_midi.settings); + + std::lock_guard lock{ _midi.synth_mutex }; + + if (_midi.player != nullptr) delete_fluid_player(_midi.player); + _midi.player = nullptr; + + if (_midi.synth != nullptr) delete_fluid_synth(_midi.synth); + _midi.synth = nullptr; + + if (_midi.settings != nullptr) delete_fluid_settings(_midi.settings); + _midi.settings = nullptr; } void MusicDriver_FluidSynth::PlaySong(const MusicSongInfo &song) @@ -106,6 +121,8 @@ void MusicDriver_FluidSynth::PlaySong(co return; } + std::lock_guard lock{ _midi.synth_mutex }; + _midi.player = new_fluid_player(_midi.synth); if (!_midi.player) { DEBUG(driver, 0, "Could not create midi player"); @@ -128,6 +145,8 @@ void MusicDriver_FluidSynth::PlaySong(co void MusicDriver_FluidSynth::StopSong() { + std::lock_guard lock{ _midi.synth_mutex }; + if (!_midi.player) return; fluid_player_stop(_midi.player); @@ -142,6 +161,7 @@ void MusicDriver_FluidSynth::StopSong() bool MusicDriver_FluidSynth::IsSongPlaying() { + std::lock_guard lock{ _midi.synth_mutex }; if (!_midi.player) return false; return fluid_player_get_status(_midi.player) == FLUID_PLAYER_PLAYING; @@ -149,6 +169,9 @@ bool MusicDriver_FluidSynth::IsSongPlayi void MusicDriver_FluidSynth::SetVolume(byte vol) { + std::lock_guard lock{ _midi.synth_mutex }; + if (_midi.settings == nullptr) return; + /* 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 OpenTTD's volume, as a number between 0