Skip to content

Commit

Permalink
Add: Fluidsynth music driver support (jmak)
Browse files Browse the repository at this point in the history
  • Loading branch information
LordAro authored and nielsmh committed Nov 1, 2018
1 parent 1e68b9b commit 0c619b7
Show file tree
Hide file tree
Showing 5 changed files with 219 additions and 0 deletions.
16 changes: 16 additions & 0 deletions config.lib
Expand Up @@ -83,6 +83,7 @@ set_default() {
with_midi=""
with_midi_arg=""
with_libtimidity="1"
with_fluidsynth="1"
with_freetype="1"
with_fontconfig="1"
with_icu_layout="1"
Expand Down Expand Up @@ -160,6 +161,7 @@ set_default() {
with_midi
with_midi_arg
with_libtimidity
with_fluidsynth
with_freetype
with_fontconfig
with_icu_layout
Expand Down Expand Up @@ -372,6 +374,9 @@ detect_params() {
--without-libtimidity) with_libtimidity="0";;
--with-libtimidity=*) with_libtimidity="$optarg";;

--with-fluidsynth) with_fluidsynth="2";;
--without-fluidsynth) with_fluidsynth="0";;

--with-freetype) with_freetype="2";;
--without-freetype) with_freetype="0";;
--with-freetype=*) with_freetype="$optarg";;
Expand Down Expand Up @@ -890,6 +895,7 @@ check_params() {
detect_icu_layout
detect_icu_sort
detect_libtimidity
detect_fluidsynth

if [ "$with_direct_music" != "0" ]; then
if [ "$os" != "MINGW" ] && [ "$os" != "CYGWIN" ]; then
Expand Down Expand Up @@ -1839,6 +1845,11 @@ make_cflags_and_ldflags() {
fi
fi

if [ -n "$fluidsynth" ]; then
LIBS="$LIBS -lfluidsynth"
CFLAGS="$CFLAGS -DFLUIDSYNTH"
fi

if [ "$with_iconv" != "0" ]; then
CFLAGS="$CFLAGS -DWITH_ICONV"
if [ "$link_to_iconv" = "yes" ]; then
Expand Down Expand Up @@ -2775,6 +2786,10 @@ detect_libtimidity() {
detect_pkg_config "$with_libtimidity" "libtimidity" "libtimidity_config" "0.1" "1"
}

detect_fluidsynth() {
detect_library "$with_fluidsynth" "fluidsynth" "" "" "fluidsynth.h"
}

detect_pkg_config() {
# $1 - config-param ($with_lzma value)
# $2 - package name ('liblzma')
Expand Down Expand Up @@ -3543,6 +3558,7 @@ showhelp() {
echo " midi-player"
echo " --with-libtimidity[=\"pkg-config libtimidity\"]"
echo " enables libtimidity support"
echo " --with-fluidsynth enables fluidsynth support"
echo " --with-allegro[=\"pkg-config allegro\"]"
echo " enables Allegro video driver support"
echo " --with-cocoa enables COCOA video driver (OSX ONLY)"
Expand Down
1 change: 1 addition & 0 deletions configure
Expand Up @@ -125,6 +125,7 @@ AWKCOMMAND='
if ($0 == "MSVC" && "'$os'" != "MSVC") { next; }
if ($0 == "DIRECTMUSIC" && "'$with_direct_music'" == "0") { next; }
if ($0 == "LIBTIMIDITY" && "'$libtimidity'" == "" ) { next; }
if ($0 == "FLUIDSYNTH" && "'$fluidsynth'" == "" ) { next; }
if ($0 == "HAVE_THREAD" && "'$with_threads'" == "0") { next; }
if ($0 == "SSE" && "'$with_sse'" != "1") { next; }
Expand Down
4 changes: 4 additions & 0 deletions source.list
Expand Up @@ -407,6 +407,7 @@ music/bemidi.h
music/cocoa_m.h
music/extmidi.h
music/libtimidity.h
music/fluidsynth.h
music/os2_m.h
music/qtmidi.h
os/macosx/macos.h
Expand Down Expand Up @@ -1127,6 +1128,9 @@ music/midifile.cpp
#if LIBTIMIDITY
music/libtimidity.cpp
#end
#if FLUIDSYNTH
music/fluidsynth.cpp
#end
#end

# Sound
Expand Down
157 changes: 157 additions & 0 deletions src/music/fluidsynth.cpp
@@ -0,0 +1,157 @@
/* $Id$ */

/*
* This file is part of OpenTTD.
* 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.
* 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.
* 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/>.
*/

/** @file fluidsynth.cpp Playing music via the fluidsynth library. */

#include "../stdafx.h"
#include "../openttd.h"
#include "../sound_type.h"
#include "../debug.h"
#include "fluidsynth.h"
#include "midifile.hpp"
#include <fluidsynth.h>

static struct {
fluid_settings_t* settings; ///< FluidSynth settings handle
fluid_synth_t* synth; ///< FluidSynth synthesizer handle
fluid_audio_driver_t* adriver; ///< FluidSynth audio driver handle
fluid_player_t* player; ///< FluidSynth MIDI player handle
} _midi; ///< Metadata about the midi we're playing.

/** Factory for the FluidSynth driver. */
static FMusicDriver_FluidSynth iFMusicDriver_FluidSynth;

/** List of sound fonts to try by default. */
static const char *default_sf[] = {
/* Debian/Ubuntu/OpenSUSE preferred */
"/usr/share/sounds/sf2/FluidR3_GM.sf2",

/* RedHat/Fedora/Arch preferred */
"/usr/share/soundfonts/FluidR3_GM.sf2",

/* Debian/Ubuntu/OpenSUSE alternatives */
"/usr/share/sounds/sf2/TimGM6mb.sf2",
"/usr/share/sounds/sf2/FluidR3_GS.sf2",

NULL
};

const char *MusicDriver_FluidSynth::Start(const char * const *param)
{
const char *driver_name = GetDriverParam(param, "driver");
const char *sfont_name = GetDriverParam(param, "soundfont");
int sfont_id;

if (!driver_name) driver_name = "alsa";

DEBUG(driver, 1, "Fluidsynth: driver %s, sf %s", driver_name, sfont_name);

/* Create the settings. */
_midi.settings = new_fluid_settings();
if (!_midi.settings) return "Could not create midi settings";

if (fluid_settings_setstr(_midi.settings, "audio.driver", driver_name) != 1) {
return "Could not set audio driver name";
}

/* Create the synthesizer. */
_midi.synth = new_fluid_synth(_midi.settings);
if (!_midi.synth) return "Could not open synth";

/* Create the audio driver. The synthesizer starts playing as soon
as the driver is created. */
_midi.adriver = new_fluid_audio_driver(_midi.settings, _midi.synth);
if (!_midi.adriver) return "Could not open audio driver";

/* Load a SoundFont and reset presets (so that new instruments
* get used from the SoundFont) */
if (!sfont_name) {
int i;
sfont_id = FLUID_FAILED;
for (i = 0; default_sf[i]; i++) {
if (!fluid_is_soundfont(default_sf[i])) continue;
sfont_id = fluid_synth_sfload(_midi.synth, default_sf[i], 1);
if (sfont_id != FLUID_FAILED) break;
}
if (sfont_id == FLUID_FAILED) return "Could not open any sound font";
} else {
sfont_id = fluid_synth_sfload(_midi.synth, sfont_name, 1);
if (sfont_id == FLUID_FAILED) return "Could not open sound font";
}

_midi.player = NULL;

return NULL;
}

void MusicDriver_FluidSynth::Stop()
{
this->StopSong();
delete_fluid_audio_driver(_midi.adriver);
delete_fluid_synth(_midi.synth);
delete_fluid_settings(_midi.settings);
}

void MusicDriver_FluidSynth::PlaySong(const MusicSongInfo &song)
{
std::string filename = MidiFile::GetSMFFile(song);

this->StopSong();

if (filename.empty()) {
return;
}

_midi.player = new_fluid_player(_midi.synth);
if (!_midi.player) {
DEBUG(driver, 0, "Could not create midi player");
return;
}

if (fluid_player_add(_midi.player, filename.c_str()) != FLUID_OK) {
DEBUG(driver, 0, "Could not open music file");
delete_fluid_player(_midi.player);
_midi.player = NULL;
return;
}
if (fluid_player_play(_midi.player) != FLUID_OK) {
DEBUG(driver, 0, "Could not start midi player");
delete_fluid_player(_midi.player);
_midi.player = NULL;
return;
}
}

void MusicDriver_FluidSynth::StopSong()
{
if (!_midi.player) return;

fluid_player_stop(_midi.player);
if (fluid_player_join(_midi.player) != FLUID_OK) {
DEBUG(driver, 0, "Could not join player");
}
delete_fluid_player(_midi.player);
fluid_synth_system_reset(_midi.synth);
_midi.player = NULL;
}

bool MusicDriver_FluidSynth::IsSongPlaying()
{
if (!_midi.player) return false;

return fluid_player_get_status(_midi.player) == FLUID_PLAYER_PLAYING;
}

void MusicDriver_FluidSynth::SetVolume(byte vol)
{
/* Allowed range of synth.gain is 0.0 to 10.0 */
if (fluid_settings_setnum(_midi.settings, "synth.gain", 1.0 * vol / 128.0) != 1) {
DEBUG(driver, 0, "Could not set volume");
}
}
41 changes: 41 additions & 0 deletions src/music/fluidsynth.h
@@ -0,0 +1,41 @@
/* $Id$ */

/*
* This file is part of OpenTTD.
* 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.
* 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.
* 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/>.
*/

/** @file fluidsynth.h Base for FluidSynth music playback. */

#ifndef MUSIC_FLUIDSYNTH_H
#define MUSIC_FLUIDSYNTH_H

#include "music_driver.hpp"

/** Music driver making use of FluidSynth. */
class MusicDriver_FluidSynth : public MusicDriver {
public:
/* virtual */ const char *Start(const char * const *param);

/* virtual */ void Stop();

/* virtual */ void PlaySong(const MusicSongInfo &song);

/* virtual */ void StopSong();

/* virtual */ bool IsSongPlaying();

/* virtual */ void SetVolume(byte vol);
/* virtual */ const char *GetName() const { return "fluidsynth"; }
};

/** Factory for the fluidsynth driver. */
class FMusicDriver_FluidSynth : public DriverFactoryBase {
public:
FMusicDriver_FluidSynth() : DriverFactoryBase(Driver::DT_MUSIC, 5, "fluidsynth", "FluidSynth MIDI Driver") {}
/* virtual */ Driver *CreateInstance() const { return new MusicDriver_FluidSynth(); }
};

#endif /* MUSIC_FLUIDSYNTH_H */

0 comments on commit 0c619b7

Please sign in to comment.