commit 9301c9dbd937c910b98f2dd5178350aed573f3cd
Author: Michael Day <contact@michaelcday.com>
AuthorDate: Sat Mar 11 14:50:11 2023 -0500
Commit: Michael Day <contact@michaelcday.com>
CommitDate: Tue Mar 21 13:54:59 2023 -0400
Introduce native FluidSynth support
---
configure.ac | 22 ++++-
src/Makefile.am | 1 +
src/i_flmusic.c | 266 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++
src/i_sound.c | 3 +
src/i_sound.h | 1 +
5 files changed, 291 insertions(+), 2 deletions(-)
diff --git a/configure.ac b/configure.ac
index 09175ee3..233aab93 100644
--- a/configure.ac
+++ b/configure.ac
@@ -138,10 +138,28 @@ AS_IF([test "x$with_libpng" != xno], [
])
])
+# Check for fluidsynth.
+AC_ARG_WITH([fluidsynth],
+AS_HELP_STRING([--without-fluidsynth],
+ [Build without fluidsynth @<:@default=check@:>@]),
+[],
+[
+ [with_fluidsynth=check]
+])
+AS_IF([test "x$with_fluidsynth" != xno], [
+ PKG_CHECK_MODULES(FLUIDSYNTH, fluidsynth >= 2.2.0, [
+ AC_DEFINE([HAVE_FLUIDSYNTH], [1], [fluidsynth installed])
+ ], [
+ AS_IF([test "x$with_fluidsynth" != xcheck], [AC_MSG_FAILURE(
+ [--with-fluidsynth was given, but test for fluidsynth failed])
+ ])
+ ])
+])
+
# TODO: We currently link everything against libraries that don't need it.
# Use the specific library CFLAGS/LIBS variables instead of setting them here.
-CFLAGS="$CFLAGS $SDL_CFLAGS ${SAMPLERATE_CFLAGS:-} ${PNG_CFLAGS:-}"
-LDFLAGS="$LDFLAGS $SDL_LIBS ${SAMPLERATE_LIBS:-} ${PNG_LIBS:-}"
+CFLAGS="$CFLAGS $SDL_CFLAGS ${SAMPLERATE_CFLAGS:-} ${PNG_CFLAGS:-} ${FLUIDSYNTH_CFLAGS:-}"
+LDFLAGS="$LDFLAGS $SDL_LIBS ${SAMPLERATE_LIBS:-} ${PNG_LIBS:-} ${FLUIDSYNTH_LIBS:-}"
case "$host" in
*-*-mingw* | *-*-cygwin* | *-*-msvc* )
LDFLAGS="$LDFLAGS -lwinmm"
diff --git a/src/Makefile.am b/src/Makefile.am
index 18b2455f..06f4827e 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -68,6 +68,7 @@ deh_str.c deh_str.h \
gusconf.c gusconf.h \
i_cdmus.c i_cdmus.h \
i_endoom.c i_endoom.h \
+i_flmusic.c \
i_glob.c i_glob.h \
i_input.c i_input.h \
i_joystick.c i_joystick.h \
diff --git a/src/i_flmusic.c b/src/i_flmusic.c
new file mode 100644
index 00000000..cd43bd04
--- /dev/null
+++ b/src/i_flmusic.c
@@ -0,0 +1,266 @@
+//
+// Copyright(C) 2022 Roman Fomin
+// Copyright(C) 2023 Michael Day
+//
+// This program 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; either version 2
+// of the License, or (at your option) any later version.
+//
+// This program 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.
+//
+// DESCRIPTION:
+// FluidSynth backend
+
+#include "config.h"
+
+#if HAVE_FLUIDSYNTH
+
+#include "fluidsynth.h"
+
+#if (FLUIDSYNTH_VERSION_MAJOR < 2 || \
+ (FLUIDSYNTH_VERSION_MAJOR == 2 && FLUIDSYNTH_VERSION_MINOR < 2))
+
+typedef int fluid_int_t;
+typedef long fluid_long_long_t;
+
+#else
+
+typedef fluid_long_long_t fluid_int_t;
+
+#endif
+
+#include "SDL_mixer.h"
+
+#include "doomtype.h"
+#include "i_system.h"
+#include "i_sound.h"
+#include "m_misc.h"
+#include "memio.h"
+#include "mus2mid.h"
+#include "w_wad.h"
+#include "z_zone.h"
+#include "i_glob.h"
+
+boolean mus_chorus = true;
+boolean mus_reverb = true;
+
+static fluid_synth_t *synth = NULL;
+static fluid_settings_t *settings = NULL;
+static fluid_player_t *player = NULL;
+
+#define SOUNDFONTS_INITIAL_SIZE 16
+
+static void FL_Mix_Callback(void *udata, Uint8 *stream, int len)
+{
+ int result;
+
+ result = fluid_synth_write_s16(synth, len / 4, stream, 0, 2, stream, 1, 2);
+
+ if (result != FLUID_OK)
+ {
+ fprintf(stderr, "FL_Mix_Callback: Error generating FluidSynth audio");
+ }
+}
+
+static boolean I_FL_InitMusic(void)
+{
+ int sf_id;
+
+ if (strlen(fluidsynth_sf_path) == 0)
+ {
+ return false;
+ }
+
+ // quiet FluidSynth
+ fluid_set_log_function(FLUID_ERR, NULL, NULL);
+ fluid_set_log_function(FLUID_WARN, NULL, NULL);
+
+ settings = new_fluid_settings();
+
+ fluid_settings_setnum(settings, "synth.sample-rate", snd_samplerate);
+
+ fluid_settings_setint(settings, "synth.chorus.active", mus_chorus);
+ fluid_settings_setint(settings, "synth.reverb.active", mus_reverb);
+
+ if (mus_reverb)
+ {
+ fluid_settings_setnum(settings, "synth.reverb.room-size", 0.6);
+ fluid_settings_setnum(settings, "synth.reverb.damp", 0.4);
+ fluid_settings_setnum(settings, "synth.reverb.width", 4);
+ fluid_settings_setnum(settings, "synth.reverb.level", 0.15);
+ }
+
+ if (mus_chorus)
+ {
+ fluid_settings_setnum(settings, "synth.chorus.level", 0.35);
+ fluid_settings_setnum(settings, "synth.chorus.depth", 5);
+ }
+
+ synth = new_fluid_synth(settings);
+
+ sf_id = fluid_synth_sfload(synth, fluidsynth_sf_path, true);
+ if (sf_id == FLUID_FAILED)
+ {
+ // deleting the synth also deletes sfloader
+ delete_fluid_synth(synth);
+ delete_fluid_settings(settings);
+ fprintf(stderr,
+ "I_FL_InitMusic: Error loading FluidSynth soundfont: '%s'\n",
+ fluidsynth_sf_path);
+ return false;
+ }
+
+ printf("I_FL_InitMusic: Using '%s'\n", fluidsynth_sf_path);
+
+ return true;
+}
+
+static void I_FL_SetMusicVolume(int volume)
+{
+ // FluidSynth's default is 0.2. Make 1.0 the maximum.
+ // 0 -- 0.2 -- 10.0
+ fluid_synth_set_gain(synth, (float) volume / 127);
+}
+
+static void I_FL_PauseSong(void)
+{
+ fluid_player_stop(player);
+}
+
+static void I_FL_ResumeSong(void)
+{
+ fluid_player_play(player);
+}
+
+static void I_FL_PlaySong(void *handle, boolean looping)
+{
+ fluid_player_set_loop(player, looping ? -1 : 1);
+ fluid_player_play(player);
+}
+
+static void I_FL_StopSong(void)
+{
+ if (player)
+ {
+ fluid_player_stop(player);
+ }
+}
+
+// Determine whether memory block is a .mid file
+
+static boolean IsMid(byte *mem, int len)
+{
+ return len > 4 && !memcmp(mem, "MThd", 4);
+}
+
+static void *I_FL_RegisterSong(void *data, int len)
+{
+ int result = 0;
+
+ player = new_fluid_player(synth);
+
+ if (IsMid(data, len))
+ {
+ result = fluid_player_add_mem(player, data, len);
+ }
+ else
+ {
+ // Assume a MUS file and try to convert
+ MEMFILE *instream;
+ MEMFILE *outstream;
+ void *outbuf;
+ size_t outbuf_len;
+
+ instream = mem_fopen_read(data, len);
+ outstream = mem_fopen_write();
+
+ if (mus2mid(instream, outstream) == 0)
+ {
+ mem_get_buf(outstream, &outbuf, &outbuf_len);
+ result = fluid_player_add_mem(player, outbuf, outbuf_len);
+ }
+
+ mem_fclose(instream);
+ mem_fclose(outstream);
+ }
+
+ if (result != FLUID_OK)
+ {
+ fprintf(stderr,
+ "I_FL_RegisterSong: FluidSynth failed to load in-memory song");
+ return NULL;
+ }
+
+ Mix_HookMusic(FL_Mix_Callback, NULL);
+ return player;
+}
+
+static void I_FL_UnRegisterSong(void *handle)
+{
+ if (player)
+ {
+ fluid_synth_program_reset(synth);
+ fluid_synth_system_reset(synth);
+
+ Mix_HookMusic(NULL, NULL);
+
+ delete_fluid_player(player);
+ player = NULL;
+ }
+}
+
+static void I_FL_ShutdownMusic(void)
+{
+ I_FL_StopSong();
+ I_FL_UnRegisterSong(NULL);
+
+ if (synth)
+ {
+ delete_fluid_synth(synth);
+ synth = NULL;
+ }
+
+ if (settings)
+ {
+ delete_fluid_settings(settings);
+ settings = NULL;
+ }
+}
+
+static boolean I_FL_MusicIsPlaying(void)
+{
+ if (player == NULL)
+ {
+ return false;
+ }
+
+ return (fluid_player_get_status(player) == FLUID_PLAYER_PLAYING);
+}
+
+static snddevice_t music_fl_devices[] =
+{
+ SNDDEVICE_GENMIDI,
+};
+
+music_module_t music_fl_module =
+{
+ music_fl_devices,
+ arrlen(music_fl_devices),
+ I_FL_InitMusic,
+ I_FL_ShutdownMusic,
+ I_FL_SetMusicVolume,
+ I_FL_PauseSong,
+ I_FL_ResumeSong,
+ I_FL_RegisterSong,
+ I_FL_UnRegisterSong,
+ I_FL_PlaySong,
+ I_FL_StopSong,
+ I_FL_MusicIsPlaying,
+ NULL // Poll
+};
+
+#endif
diff --git a/src/i_sound.c b/src/i_sound.c
index 7d2819bd..6232772b 100644
--- a/src/i_sound.c
+++ b/src/i_sound.c
@@ -94,6 +94,9 @@ static music_module_t *music_modules[] =
#ifdef _WIN32
&music_win_module,
#endif
+#if HAVE_FLUIDSYNTH
+ &music_fl_module,
+#endif // HAVE_FLUIDSYNTH
#ifndef DISABLE_SDL2MIXER
&music_sdl_module,
#endif // DISABLE_SDL2MIXER
diff --git a/src/i_sound.h b/src/i_sound.h
index a056a47c..d4bc9404 100644
--- a/src/i_sound.h
+++ b/src/i_sound.h
@@ -259,6 +259,7 @@ extern music_module_t music_sdl_module;
extern music_module_t music_opl_module;
extern music_module_t music_pack_module;
extern music_module_t music_win_module;
+extern music_module_t music_fl_module;
// For OPL module: