OpenTTD
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 
19 static struct {
20  fluid_settings_t* settings;
21  fluid_synth_t* synth;
22  fluid_player_t* player;
23 } _midi;
24 
27 
29 static const char *default_sf[] = {
30  /* Debian/Ubuntu/OpenSUSE preferred */
31  "/usr/share/sounds/sf2/FluidR3_GM.sf2",
32 
33  /* RedHat/Fedora/Arch preferred */
34  "/usr/share/soundfonts/FluidR3_GM.sf2",
35 
36  /* Debian/Ubuntu/OpenSUSE alternatives */
37  "/usr/share/sounds/sf2/TimGM6mb.sf2",
38  "/usr/share/sounds/sf2/FluidR3_GS.sf2",
39 
40  nullptr
41 };
42 
43 static void RenderMusicStream(int16 *buffer, size_t samples)
44 {
45  if (!_midi.synth || !_midi.player) return;
46  fluid_synth_write_s16(_midi.synth, samples, buffer, 0, 2, buffer, 1, 2);
47 }
48 
49 const char *MusicDriver_FluidSynth::Start(const char * const *param)
50 {
51  const char *sfont_name = GetDriverParam(param, "soundfont");
52  int sfont_id;
53 
54  DEBUG(driver, 1, "Fluidsynth: sf %s", sfont_name);
55 
56  /* Create the settings. */
57  _midi.settings = new_fluid_settings();
58  if (!_midi.settings) return "Could not create midi settings";
59  /* Don't try to lock sample data in memory, OTTD usually does not run with privileges allowing that */
60  fluid_settings_setint(_midi.settings, "synth.lock-memory", 0);
61 
62  /* Create the synthesizer. */
63  _midi.synth = new_fluid_synth(_midi.settings);
64  if (!_midi.synth) return "Could not open synth";
65 
66  /* Load a SoundFont and reset presets (so that new instruments
67  * get used from the SoundFont) */
68  if (!sfont_name) {
69  int i;
70  sfont_id = FLUID_FAILED;
71  for (i = 0; default_sf[i]; i++) {
72  if (!fluid_is_soundfont(default_sf[i])) continue;
73  sfont_id = fluid_synth_sfload(_midi.synth, default_sf[i], 1);
74  if (sfont_id != FLUID_FAILED) break;
75  }
76  if (sfont_id == FLUID_FAILED) return "Could not open any sound font";
77  } else {
78  sfont_id = fluid_synth_sfload(_midi.synth, sfont_name, 1);
79  if (sfont_id == FLUID_FAILED) return "Could not open sound font";
80  }
81 
82  _midi.player = nullptr;
83 
84  uint32 samplerate = MxSetMusicSource(RenderMusicStream);
85  fluid_synth_set_sample_rate(_midi.synth, samplerate);
86  DEBUG(driver, 1, "Fluidsynth: samplerate %.0f", (float)samplerate);
87 
88  return nullptr;
89 }
90 
92 {
93  MxSetMusicSource(nullptr);
94  this->StopSong();
95  delete_fluid_synth(_midi.synth);
96  delete_fluid_settings(_midi.settings);
97 }
98 
100 {
101  std::string filename = MidiFile::GetSMFFile(song);
102 
103  this->StopSong();
104 
105  if (filename.empty()) {
106  return;
107  }
108 
109  _midi.player = new_fluid_player(_midi.synth);
110  if (!_midi.player) {
111  DEBUG(driver, 0, "Could not create midi player");
112  return;
113  }
114 
115  if (fluid_player_add(_midi.player, filename.c_str()) != FLUID_OK) {
116  DEBUG(driver, 0, "Could not open music file");
117  delete_fluid_player(_midi.player);
118  _midi.player = nullptr;
119  return;
120  }
121  if (fluid_player_play(_midi.player) != FLUID_OK) {
122  DEBUG(driver, 0, "Could not start midi player");
123  delete_fluid_player(_midi.player);
124  _midi.player = nullptr;
125  return;
126  }
127 }
128 
130 {
131  if (!_midi.player) return;
132 
133  fluid_player_stop(_midi.player);
134  if (fluid_player_join(_midi.player) != FLUID_OK) {
135  DEBUG(driver, 0, "Could not join player");
136  }
137  delete_fluid_player(_midi.player);
138  fluid_synth_system_reset(_midi.synth);
139  _midi.player = nullptr;
140 }
141 
143 {
144  if (!_midi.player) return false;
145 
146  return fluid_player_get_status(_midi.player) == FLUID_PLAYER_PLAYING;
147 }
148 
150 {
151  /* Allowed range of synth.gain is 0.0 to 10.0 */
152  /* fluidsynth's default gain is 0.2, so use this as "full
153  * volume". Set gain using OpenTTD's volume, as a number between 0
154  * and 0.2. */
155  double gain = (1.0 * vol) / (128.0 * 5.0);
156  if (fluid_settings_setnum(_midi.settings, "synth.gain", gain) != 1) {
157  DEBUG(driver, 0, "Could not set volume");
158  }
159 }
const char * GetDriverParam(const char *const *parm, const char *name)
Get a string parameter the list of parameters.
Definition: driver.cpp:37
Metadata about a music track.
bool IsSongPlaying() override
Are we currently playing a song?
Definition: fluidsynth.cpp:142
void StopSong() override
Stop playing the current song.
Definition: fluidsynth.cpp:129
fluid_settings_t * settings
FluidSynth settings handle.
Definition: fluidsynth.cpp:20
const char * Start(const char *const *param) override
Start this driver.
Definition: fluidsynth.cpp:49
void PlaySong(const MusicSongInfo &song) override
Play a particular song.
Definition: fluidsynth.cpp:99
Base for FluidSynth music playback.
uint32 MxSetMusicSource(MxStreamCallback music_callback)
Set source of PCM music.
Definition: mixer.cpp:228
#define DEBUG(name, level,...)
Output a line of debugging information.
Definition: debug.h:35
fluid_synth_t * synth
FluidSynth synthesizer handle.
Definition: fluidsynth.cpp:21
static FMusicDriver_FluidSynth iFMusicDriver_FluidSynth
Factory for the FluidSynth driver.
Definition: fluidsynth.cpp:26
static std::string GetSMFFile(const MusicSongInfo &song)
Get the name of a Standard MIDI File for a given song.
Definition: midifile.cpp:1048
static struct @24 _midi
Metadata about the midi we&#39;re playing.
void Stop() override
Stop this driver.
Definition: fluidsynth.cpp:91
static const char * default_sf[]
List of sound fonts to try by default.
Definition: fluidsynth.cpp:29
Factory for the fluidsynth driver.
Definition: fluidsynth.h:33
fluid_player_t * player
FluidSynth MIDI player handle.
Definition: fluidsynth.cpp:22
void SetVolume(byte vol) override
Set the volume, if possible.
Definition: fluidsynth.cpp:149