OpenTTD Source: src/music/fluidsynth.cpp Source File

OpenTTD Source 1.11.0-RC1

fluidsynth.cpp
Go to the documentation of this file.
1 /*
2 * This file is part of OpenTTD.
3 * OpenTTD is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, version 2.
4 * OpenTTD is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
5 * See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with OpenTTD. If not, see <http://www.gnu.org/licenses/>.
6 */
7
10 #include "../stdafx.h"
11 #include "../openttd.h"
12 #include "../sound_type.h"
13 #include "../debug.h"
14 #include "fluidsynth.h"
15 #include "midifile.hpp"
16 #include <fluidsynth.h>
17 #include "../mixer.h"
18 #include <mutex>
19
20 static struct {
21 fluid_settings_t* settings;
22 fluid_synth_t* synth;
23 fluid_player_t* player;
24 std::mutex synth_mutex;
25 } _midi;
26
28 static FMusicDriver_FluidSynth iFMusicDriver_FluidSynth;
29
31 static const char *default_sf[] = {
32 /* Debian/Ubuntu/OpenSUSE preferred */
33 "/usr/share/sounds/sf2/FluidR3_GM.sf2",
34
35 /* RedHat/Fedora/Arch preferred */
36 "/usr/share/soundfonts/FluidR3_GM.sf2",
37
38 /* Debian/Ubuntu/OpenSUSE alternatives */
39 "/usr/share/sounds/sf2/TimGM6mb.sf2",
40 "/usr/share/sounds/sf2/FluidR3_GS.sf2",
41
42 nullptr
43 };
44
45 static void RenderMusicStream(int16 *buffer, size_t samples)
46 {
47 std::unique_lock<std::mutex> lock{ _midi.synth_mutex, std::try_to_lock };
48
49 if (!lock.owns_lock() || !_midi.synth || !_midi.player) return;
50 fluid_synth_write_s16(_midi.synth, samples, buffer, 0, 2, buffer, 1, 2);
51 }
52
53 const char *MusicDriver_FluidSynth::Start(const StringList &param)
54 {
55 std::lock_guard<std::mutex> lock{ _midi.synth_mutex };
56
57 const char *sfont_name = GetDriverParam(param, "soundfont");
58 int sfont_id;
59
60 DEBUG(driver, 1, "Fluidsynth: sf %s", sfont_name);
61
62 /* Create the settings. */
63 _midi.settings = new_fluid_settings();
64 if (!_midi.settings) return "Could not create midi settings";
65 /* Don't try to lock sample data in memory, OTTD usually does not run with privileges allowing that */
66 fluid_settings_setint(_midi.settings, "synth.lock-memory", 0);
67
68 /* Install the music render routine and set up the samplerate */
69 uint32 samplerate = MxSetMusicSource(RenderMusicStream);
70 fluid_settings_setnum(_midi.settings, "synth.sample-rate", samplerate);
71 DEBUG(driver, 1, "Fluidsynth: samplerate %.0f", (float)samplerate);
72
73 /* Create the synthesizer. */
74 _midi.synth = new_fluid_synth(_midi.settings);
75 if (!_midi.synth) return "Could not open synth";
76
77 /* Load a SoundFont and reset presets (so that new instruments
78 * get used from the SoundFont) */
79 if (!sfont_name) {
80 int i;
81 sfont_id = FLUID_FAILED;
82 for (i = 0; default_sf[i]; i++) {
83 if (!fluid_is_soundfont(default_sf[i])) continue;
84 sfont_id = fluid_synth_sfload(_midi.synth, default_sf[i], 1);
85 if (sfont_id != FLUID_FAILED) break;
86 }
87 if (sfont_id == FLUID_FAILED) return "Could not open any sound font";
88 } else {
89 sfont_id = fluid_synth_sfload(_midi.synth, sfont_name, 1);
90 if (sfont_id == FLUID_FAILED) return "Could not open sound font";
91 }
92
93 _midi.player = nullptr;
94
95 return nullptr;
96 }
97
98 void MusicDriver_FluidSynth::Stop()
99 {
100 MxSetMusicSource(nullptr);
101
102 std::lock_guard<std::mutex> lock{ _midi.synth_mutex };
103
104 if (_midi.player != nullptr) delete_fluid_player(_midi.player);
105 _midi.player = nullptr;
106
107 if (_midi.synth != nullptr) delete_fluid_synth(_midi.synth);
108 _midi.synth = nullptr;
109
110 if (_midi.settings != nullptr) delete_fluid_settings(_midi.settings);
111 _midi.settings = nullptr;
112 }
113
114 void MusicDriver_FluidSynth::PlaySong(const MusicSongInfo &song)
115 {
116 std::string filename = MidiFile::GetSMFFile(song);
117
118 this->StopSong();
119
120 if (filename.empty()) {
121 return;
122 }
123
124 std::lock_guard<std::mutex> lock{ _midi.synth_mutex };
125
126 _midi.player = new_fluid_player(_midi.synth);
127 if (!_midi.player) {
128 DEBUG(driver, 0, "Could not create midi player");
129 return;
130 }
131
132 if (fluid_player_add(_midi.player, filename.c_str()) != FLUID_OK) {
133 DEBUG(driver, 0, "Could not open music file");
134 delete_fluid_player(_midi.player);
135 _midi.player = nullptr;
136 return;
137 }
138 if (fluid_player_play(_midi.player) != FLUID_OK) {
139 DEBUG(driver, 0, "Could not start midi player");
140 delete_fluid_player(_midi.player);
141 _midi.player = nullptr;
142 return;
143 }
144 }
145
146 void MusicDriver_FluidSynth::StopSong()
147 {
148 std::lock_guard<std::mutex> lock{ _midi.synth_mutex };
149
150 if (!_midi.player) return;
151
152 fluid_player_stop(_midi.player);
153 if (fluid_player_join(_midi.player) != FLUID_OK) {
154 DEBUG(driver, 0, "Could not join player");
155 }
156 delete_fluid_player(_midi.player);
157 fluid_synth_system_reset(_midi.synth);
158 fluid_synth_all_sounds_off(_midi.synth, -1);
159 _midi.player = nullptr;
160 }
161
162 bool MusicDriver_FluidSynth::IsSongPlaying()
163 {
164 std::lock_guard<std::mutex> lock{ _midi.synth_mutex };
165 if (!_midi.player) return false;
166
167 return fluid_player_get_status(_midi.player) == FLUID_PLAYER_PLAYING;
168 }
169
170 void MusicDriver_FluidSynth::SetVolume(byte vol)
171 {
172 std::lock_guard<std::mutex> lock{ _midi.synth_mutex };
173 if (_midi.settings == nullptr) return;
174
175 /* Allowed range of synth.gain is 0.0 to 10.0 */
176 /* fluidsynth's default gain is 0.2, so use this as "full
177 * volume". Set gain using OpenTTD's volume, as a number between 0
178 * and 0.2. */
179 double gain = (1.0 * vol) / (128.0 * 5.0);
180 if (fluid_settings_setnum(_midi.settings, "synth.gain", gain) != FLUID_OK) {
181 DEBUG(driver, 0, "Could not set volume");
182 }
183 }
MusicDriver_FluidSynth::IsSongPlaying
bool IsSongPlaying() override
Are we currently playing a song?
Definition: fluidsynth.cpp:162
MusicDriver_FluidSynth::SetVolume
void SetVolume(byte vol) override
Set the volume, if possible.
Definition: fluidsynth.cpp:170
MusicDriver_FluidSynth::Start
const char * Start(const StringList &param) override
Start this driver.
Definition: fluidsynth.cpp:53
fluidsynth.h
synth_mutex
std::mutex synth_mutex
Guard mutex for synth access.
Definition: fluidsynth.cpp:24
lock
std::mutex lock
synchronization for playback status fields
Definition: win32_m.cpp:34
synth
fluid_synth_t * synth
FluidSynth synthesizer handle.
Definition: fluidsynth.cpp:22
MusicDriver_FluidSynth::StopSong
void StopSong() override
Stop playing the current song.
Definition: fluidsynth.cpp:146
_midi
static struct @25 _midi
Metadata about the midi we're playing.
iFMusicDriver_FluidSynth
static FMusicDriver_FluidSynth iFMusicDriver_FluidSynth
Factory for the FluidSynth driver.
Definition: fluidsynth.cpp:28
MusicDriver_FluidSynth::PlaySong
void PlaySong(const MusicSongInfo &song) override
Play a particular song.
Definition: fluidsynth.cpp:114
GetDriverParam
const char * GetDriverParam(const StringList &parm, const char *name)
Get a string parameter the list of parameters.
Definition: driver.cpp:41
default_sf
static const char * default_sf[]
List of sound fonts to try by default.
Definition: fluidsynth.cpp:31
player
fluid_player_t * player
FluidSynth MIDI player handle.
Definition: fluidsynth.cpp:23
DEBUG
#define DEBUG(name, level,...)
Output a line of debugging information.
Definition: debug.h:35
MusicSongInfo
Metadata about a music track.
Definition: base_media_base.h:291
StringList
std::vector< std::string > StringList
Type for a list of strings.
Definition: string_type.h:58
FMusicDriver_FluidSynth
Factory for the fluidsynth driver.
Definition: fluidsynth.h:33
settings
fluid_settings_t * settings
FluidSynth settings handle.
Definition: fluidsynth.cpp:21
MidiFile::GetSMFFile
static std::string GetSMFFile(const MusicSongInfo &song)
Get the name of a Standard MIDI File for a given song.
Definition: midifile.cpp:1047
MxSetMusicSource
uint32 MxSetMusicSource(MxStreamCallback music_callback)
Set source of PCM music.
Definition: mixer.cpp:228
MusicDriver_FluidSynth::Stop
void Stop() override
Stop this driver.
Definition: fluidsynth.cpp:98