- Added FluidSynth support as snd_mididevice -5. Only tested with Linux. I will have

to try compiling it myself on Windows to see if it's really that slow or if
  Ubuntu just ships an unoptimized version, because performance is pretty pathetic
  when compared to the other options. (I understand that it's a complete SoundFont2
  renderer, so it is understandably slower than something like TiMidity++, but still.
  Does it really need to be around 10x slower? I played with the chorus, reverb, and
  interpolation settings, and none of them seemed to make much difference in
  performance.)



SVN r2545 (trunk)
This commit is contained in:
Randy Heit 2010-08-15 19:54:59 +00:00
parent 0657121847
commit 1fa4bbf69c
9 changed files with 239 additions and 18 deletions

23
FindFluidSynth.cmake Normal file
View File

@ -0,0 +1,23 @@
# - Find fluidsynth
# Find the native fluidsynth includes and library
#
# FLUIDSYNTH_INCLUDE_DIR - where to find fluidsynth.h
# FLUIDSYNTH_LIBRARIES - List of libraries when using fluidsynth.
# FLUIDSYNTH_FOUND - True if fluidsynth found.
IF (FLUIDSYNTH_INCLUDE_DIR AND FLUIDSYNTH_LIBRARIES)
# Already in cache, be silent
SET(FluidSynth_FIND_QUIETLY TRUE)
ENDIF (FLUIDSYNTH_INCLUDE_DIR AND FLUIDSYNTH_LIBRARIES)
FIND_PATH(FLUIDSYNTH_INCLUDE_DIR fluidsynth.h)
FIND_LIBRARY(FLUIDSYNTH_LIBRARIES NAMES fluidsynth )
MARK_AS_ADVANCED( FLUIDSYNTH_LIBRARIES FLUIDSYNTH_INCLUDE_DIR )
# handle the QUIETLY and REQUIRED arguments and set FLUIDSYNTH_FOUND to TRUE if
# all listed variables are TRUE
INCLUDE(FindPackageHandleStandardArgs)
FIND_PACKAGE_HANDLE_STANDARD_ARGS(FluidSynth DEFAULT_MSG FLUIDSYNTH_LIBRARIES FLUIDSYNTH_INCLUDE_DIR)

View File

@ -31,6 +31,10 @@ endif( CMAKE_SIZEOF_VOID_P MATCHES "8" )
# fmodapi<version>linux[64] -or simply- fmod
# jpeg-6b
# ...
# The recommended method is to put it in the zdoom tree, since its
# headers are unversioned. Especially now that we can't work properly
# with anything newer than 4.26.xx, you probably don't want to use
# a system-wide version.
# Construct version numbers for searching for the FMOD library on Linux.
set( MINOR_VERSIONS "50" "49" "48" "47" "46" "45" "44" "43" "42" "41"
@ -236,6 +240,10 @@ else( FMOD_LIBRARY )
endif( FMOD_LIBRARY )
# Search for FluidSynth
include( ../FindFluidSynth.cmake )
# Search for NASM
if( NOT NO_ASM )
@ -370,7 +378,8 @@ endif( SSE_MATTERS )
if( CMAKE_COMPILER_IS_GNUCXX )
if( PROFILE )
set( CMAKE_C_FLAGS_DEBUG "${CMAKE_C_FLAGS_DEBUG} -pg" )
set( CMAKE_C_FLinclude( FindFluidSynth.cmake )
AGS_DEBUG "${CMAKE_C_FLAGS_DEBUG} -pg" )
set( CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} -pg" )
set( CMAKE_C_FLAGS_RELWITHDEBINFO "${CMAKE_C_FLAGS_RELWITHDEBINFO} -pg" )
set( CMAKE_CXX_FLAGS_RELWITHDEBINFO "${CMAKE_CXX_FLAGS_RELWITHDEBINFO} -pg" )
@ -476,8 +485,10 @@ add_custom_target( revision_check ALL
# Libraries ZDoom needs
set( ZDOOM_LIBS ${ZDOOM_LIBS} "${ZLIB_LIBRARIES}" "${JPEG_LIBRARIES}" "${BZIP2_LIBRARIES}" "${FMOD_LIBRARY}" )
include_directories( "${ZLIB_INCLUDE_DIR}" "${FMOD_INCLUDE_DIR}" "${BZIP2_INCLUDE_DIR}" "${LZMA_INCLUDE_DIR}" "${JPEG_INCLUDE_DIR}" )
message( STATUS "Fluid synth libs: ${FLUIDSYNTH_LIBRARIES}" )
set( ZDOOM_LIBS ${ZDOOM_LIBS} "${ZLIB_LIBRARIES}" "${JPEG_LIBRARIES}" "${BZIP2_LIBRARIES}" "${FMOD_LIBRARY}" "${FLUIDSYNTH_LIBRARIES}" )
include_directories( "${ZLIB_INCLUDE_DIR}" "${FMOD_INCLUDE_DIR}" "${BZIP2_INCLUDE_DIR}" "${LZMA_INCLUDE_DIR}" "${JPEG_INCLUDE_DIR}" "${FLUIDSYNTH_INCLUDE_DIR}" )
# Start defining source files for ZDoom
@ -572,6 +583,9 @@ else( SSE_MATTERS )
set( X86_SOURCES )
endif( SSE_MATTERS )
if( FLUIDSYNTH_FOUND )
add_definitions( -DHAVE_FLUIDSYNTH )
endif( FLUIDSYNTH_FOUND )
add_executable( zdoom WIN32
autostart.cpp
@ -793,6 +807,7 @@ add_executable( zdoom WIN32
sound/music_mus_midiout.cpp
sound/music_mus_opl.cpp
sound/music_stream.cpp
sound/music_fluidsynth_mididevice.cpp
sound/music_timidity_mididevice.cpp
sound/music_win_mididevice.cpp
textures/automaptexture.cpp

View File

@ -101,6 +101,7 @@ EXTERN_CVAR (Int, snd_buffersize)
EXTERN_CVAR (Int, snd_samplerate)
EXTERN_CVAR (Bool, snd_pitched)
EXTERN_CVAR (Int, snd_channels)
EXTERN_CVAR (String, snd_midipatchset)
extern int sfx_empty;
@ -115,7 +116,6 @@ CVAR (Bool, snd_waterreverb, true, CVAR_ARCHIVE|CVAR_GLOBALCONFIG)
CVAR (String, snd_resampler, "Linear", CVAR_ARCHIVE|CVAR_GLOBALCONFIG)
CVAR (String, snd_speakermode, "Auto", CVAR_ARCHIVE|CVAR_GLOBALCONFIG)
CVAR (String, snd_output_format, "PCM-16", CVAR_ARCHIVE|CVAR_GLOBALCONFIG)
CVAR (String, snd_midipatchset, "", CVAR_ARCHIVE|CVAR_GLOBALCONFIG)
CVAR (Bool, snd_profile, false, 0)
// Underwater low-pass filter cutoff frequency. Set to 0 to disable the filter.
@ -644,6 +644,7 @@ bool FMODSoundRenderer::Init()
ChannelGroupTargetUnit = NULL;
SfxReverbHooked = false;
SfxReverbPlaceholder = NULL;
SfxHeadMixer = NULL;
OutputPlugin = 0;
Printf("I_InitSound: Initializing FMOD\n");
@ -706,7 +707,8 @@ bool FMODSoundRenderer::Init()
if (!ShowedBanner)
{
Printf("FMOD Sound System, copyright © Firelight Technologies Pty, Ltd., 1994-2009.\n");
// '\xa9' is the copyright symbol in the Windows-1252 code page.
Printf("FMOD Sound System, copyright \xa9 Firelight Technologies Pty, Ltd., 1994-2009.\n");
Printf("Loaded FMOD version %x.%02x.%02x\n", version >> 16, (version >> 8) & 255, version & 255);
ShowedBanner = true;
}
@ -1014,6 +1016,12 @@ bool FMODSoundRenderer::Init()
result = Sys->createDSPByType(FMOD_DSP_TYPE_MIXER, &SfxReverbPlaceholder);
if (result == FMOD_OK)
{
result = Sys->createDSPByType(FMOD_DSP_TYPE_MIXER, &SfxHeadMixer);
result = sfx_head->addInput(SfxHeadMixer, &SfxConnection);
result = sfx_head->disconnectFrom(pausable_head);
sfx_head = SfxHeadMixer;
SfxHeadMixer->setActive(true);
SfxHeadMixer->setBypass(false);
// Replace the PausableSFX->SFX connection with
// PausableSFX->ReverbPlaceholder->SFX.
result = SfxReverbPlaceholder->addInput(pausable_head, NULL);
@ -1023,13 +1031,13 @@ bool FMODSoundRenderer::Init()
result = sfx_head->addInput(SfxReverbPlaceholder, &connection);
if (result == FMOD_OK)
{
sfx_head->disconnectFrom(pausable_head);
// sfx_head->disconnectFrom(pausable_head);
SfxReverbPlaceholder->setActive(true);
SfxReverbPlaceholder->setBypass(true);
// The placeholder now takes the place of the pausable_head
// for the following connections.
pausable_head = SfxReverbPlaceholder;
SfxConnection = connection;
// SfxConnection = connection;
}
}
else
@ -1038,6 +1046,7 @@ bool FMODSoundRenderer::Init()
SfxReverbPlaceholder = NULL;
}
}
#if 1
result = WaterLP->addInput(pausable_head, NULL);
WaterLP->setActive(false);
WaterLP->setParameter(FMOD_DSP_LOWPASS_CUTOFF, snd_waterlp);
@ -1069,6 +1078,7 @@ bool FMODSoundRenderer::Init()
{
result = sfx_head->addInput(WaterLP, NULL);
}
#endif
}
}
}
@ -1147,6 +1157,11 @@ void FMODSoundRenderer::Shutdown()
SfxReverbPlaceholder->release();
SfxReverbPlaceholder = NULL;
}
if (SfxHeadMixer != NULL)
{
SfxHeadMixer->release();
SfxHeadMixer = NULL;
}
Sys->close();
if (OutputPlugin != 0)
@ -1330,10 +1345,10 @@ FString FMODSoundRenderer::GatherStats()
#endif
out.Format ("%d channels,"TEXTCOLOR_YELLOW"%5.2f"TEXTCOLOR_NORMAL"%% CPU "
"(DSP:"TEXTCOLOR_YELLOW"%2.2f"TEXTCOLOR_NORMAL"%% "
"Stream:"TEXTCOLOR_YELLOW"%2.2f"TEXTCOLOR_NORMAL"%% "
"Geometry:"TEXTCOLOR_YELLOW"%2.2f"TEXTCOLOR_NORMAL"%% "
"Update:"TEXTCOLOR_YELLOW"%2.2f"TEXTCOLOR_NORMAL"%%)",
"(DSP:"TEXTCOLOR_YELLOW"%5.2f"TEXTCOLOR_NORMAL"%% "
"Stream:"TEXTCOLOR_YELLOW"%5.2f"TEXTCOLOR_NORMAL"%% "
"Geometry:"TEXTCOLOR_YELLOW"%5.2f"TEXTCOLOR_NORMAL"%% "
"Update:"TEXTCOLOR_YELLOW"%5.2f"TEXTCOLOR_NORMAL"%%)",
channels, total, dsp, stream, geometry, update);
return out;
}

View File

@ -103,7 +103,8 @@ private:
FMOD::DSP *WaterLP, *WaterReverb;
FMOD::DSPConnection *SfxConnection;
FMOD::DSP *ChannelGroupTargetUnit;
FMOD::DSP *SfxReverbPlaceholder;
FMOD::DSP *SfxReverbPlaceholder;
FMOD::DSP *SfxHeadMixer;
bool SfxReverbHooked;
float LastWaterLP;
unsigned int OutputPlugin;

View File

@ -162,6 +162,18 @@ void MusInfo::TimidityVolumeChanged()
{
}
void MusInfo::FluidSettingInt(const char *, int)
{
}
void MusInfo::FluidSettingNum(const char *, double)
{
}
void MusInfo::FluidSettingStr(const char *, const char *)
{
}
FString MusInfo::GetStats()
{
return "No stats available for this song";
@ -428,6 +440,12 @@ MusInfo *I_RegisterSong (const char *filename, BYTE *musiccache, int offset, int
{
info = new MUSSong2(file, musiccache, len, MIDI_Timidity);
}
#ifdef HAVE_FLUIDSYNTH
else if (snd_mididevice == -5 && device == MDEV_DEFAULT)
{
info = new MUSSong2(file, musiccache, len, MIDI_Fluid);
}
#endif
if (info != NULL && !info->IsValid())
{
delete info;

View File

@ -98,6 +98,9 @@ public:
virtual FString GetStats();
virtual MusInfo *GetOPLDumper(const char *filename);
virtual MusInfo *GetWaveDumper(const char *filename, int rate);
virtual void FluidSettingInt(const char *setting, int value); // FluidSynth settings
virtual void FluidSettingNum(const char *setting, double value); // "
virtual void FluidSettingStr(const char *setting, const char *value); // "
enum EState
{

View File

@ -95,6 +95,9 @@ public:
virtual bool NeedThreadedCallback() = 0;
virtual void PrecacheInstruments(const WORD *instruments, int count);
virtual void TimidityVolumeChanged();
virtual void FluidSettingInt(const char *setting, int value);
virtual void FluidSettingNum(const char *setting, double value);
virtual void FluidSettingStr(const char *setting, const char *value);
virtual FString GetStats();
};
@ -255,6 +258,64 @@ protected:
FILE *File;
};
// FluidSynth implementation of a MIDI device -------------------------------
#ifdef HAVE_FLUIDSYNTH
#include <fluidsynth.h>
class FluidSynthMIDIDevice : public MIDIDevice
{
public:
FluidSynthMIDIDevice();
~FluidSynthMIDIDevice();
int Open(void (*callback)(unsigned int, void *, DWORD, DWORD), void *userdata);
void Close();
bool IsOpen() const;
int GetTechnology() const;
int SetTempo(int tempo);
int SetTimeDiv(int timediv);
int StreamOut(MIDIHDR *data);
int StreamOutSync(MIDIHDR *data);
int Resume();
void Stop();
int PrepareHeader(MIDIHDR *data);
int UnprepareHeader(MIDIHDR *data);
bool FakeVolume();
bool Pause(bool paused);
bool NeedThreadedCallback();
void PrecacheInstruments(const WORD *instruments, int count);
FString GetStats();
void FluidSettingInt(const char *setting, int value);
void FluidSettingNum(const char *setting, double value);
void FluidSettingStr(const char *setting, const char *value);
protected:
static bool FillStream(SoundStream *stream, void *buff, int len, void *userdata);
bool ServiceStream(void *buff, int numbytes);
void HandleEvent(int status, int parm1, int parm2);
int LoadPatchSets(const char *patches);
void (*Callback)(unsigned int, void *, DWORD, DWORD);
void *CallbackData;
void CalcTickRate();
int PlayTick();
FCriticalSection CritSec;
SoundStream *Stream;
fluid_settings_t *FluidSettings;
fluid_synth_t *FluidSynth;
double Tempo;
double Division;
double SamplesPerTick;
double NextTickIn;
MIDIHDR *Events;
bool Started;
DWORD Position;
};
#endif
// Base class for streaming MUS and MIDI files ------------------------------
// MIDI device selection.
@ -262,7 +323,8 @@ enum EMIDIDevice
{
MIDI_Win,
MIDI_OPL,
MIDI_Timidity
MIDI_Timidity,
MIDI_Fluid
};
class MIDIStreamer : public MusInfo
@ -282,6 +344,9 @@ public:
bool IsValid() const;
void Update();
FString GetStats();
void FluidSettingInt(const char *setting, int value);
void FluidSettingNum(const char *setting, double value);
void FluidSettingStr(const char *setting, const char *value);
protected:
MIDIStreamer(const char *dumpname, EMIDIDevice type);

View File

@ -9,6 +9,9 @@
static DWORD nummididevices;
static bool nummididevicesset;
CVAR (String, snd_midipatchset, "", CVAR_ARCHIVE|CVAR_GLOBALCONFIG);
#ifdef _WIN32
UINT mididevice;
@ -19,7 +22,7 @@ CUSTOM_CVAR (Int, snd_mididevice, -1, CVAR_ARCHIVE|CVAR_GLOBALCONFIG)
if (!nummididevicesset)
return;
if ((self >= (signed)nummididevices) || (self < -4))
if ((self >= (signed)nummididevices) || (self < -5))
{
Printf ("ID out of range. Using default device.\n");
self = 0;
@ -177,8 +180,8 @@ CCMD (snd_listmididevices)
CUSTOM_CVAR(Int, snd_mididevice, -1, CVAR_ARCHIVE|CVAR_GLOBALCONFIG)
{
if (self < -3)
self = -3;
if (self < -5)
self = -5;
else if (self > -1)
self = -1;
}

View File

@ -215,6 +215,12 @@ void MIDIStreamer::Play(bool looping, int subsong)
assert(0);
// Intentional fall-through for non-Windows systems.
#ifdef HAVE_FLUIDSYNTH
case MIDI_Fluid:
MIDI = new FluidSynthMIDIDevice;
break;
#endif
case MIDI_Timidity:
MIDI = new TimidityMIDIDevice;
break;
@ -225,10 +231,10 @@ void MIDIStreamer::Play(bool looping, int subsong)
}
#ifndef _WIN32
assert(MIDI->NeedThreadedCallback() == false);
assert(MIDI == NULL || MIDI->NeedThreadedCallback() == false);
#endif
if (0 != MIDI->Open(Callback, this))
if (MIDI == NULL || 0 != MIDI->Open(Callback, this))
{
Printf(PRINT_BOLD, "Could not open MIDI out device\n");
return;
@ -435,6 +441,48 @@ void MIDIStreamer::TimidityVolumeChanged()
}
}
//==========================================================================
//
// MIDIStreamer :: FluidSettingInt
//
//==========================================================================
void MIDIStreamer::FluidSettingInt(const char *setting, int value)
{
if (MIDI != NULL)
{
MIDI->FluidSettingInt(setting, value);
}
}
//==========================================================================
//
// MIDIStreamer :: FluidSettingNum
//
//==========================================================================
void MIDIStreamer::FluidSettingNum(const char *setting, double value)
{
if (MIDI != NULL)
{
MIDI->FluidSettingNum(setting, value);
}
}
//==========================================================================
//
// MIDIDeviceStreamer :: FluidSettingStr
//
//==========================================================================
void MIDIStreamer::FluidSettingStr(const char *setting, const char *value)
{
if (MIDI != NULL)
{
MIDI->FluidSettingStr(setting, value);
}
}
//==========================================================================
//
@ -840,6 +888,36 @@ void MIDIDevice::TimidityVolumeChanged()
{
}
//==========================================================================
//
// MIDIDevice :: FluidSettingInt
//
//==========================================================================
void MIDIDevice::FluidSettingInt(const char *setting, int value)
{
}
//==========================================================================
//
// MIDIDevice :: FluidSettingNum
//
//==========================================================================
void MIDIDevice::FluidSettingNum(const char *setting, double value)
{
}
//==========================================================================
//
// MIDIDevice :: FluidSettingStr
//
//==========================================================================
void MIDIDevice::FluidSettingStr(const char *setting, const char *value)
{
}
//==========================================================================
//
// MIDIDevice :: GetStats