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