mirror of
https://github.com/ZDoom/qzdoom.git
synced 2024-12-01 16:41:09 +00:00
- cleared FluidSynthMIDIDevice of most ZDoom dependencies.
This commit is contained in:
parent
8d2c67fe95
commit
647abf040b
5 changed files with 488 additions and 324 deletions
|
@ -1,7 +1,45 @@
|
|||
|
||||
/*
|
||||
** music_config.cpp
|
||||
** All game side configuration settings for the various parts of the
|
||||
** music system
|
||||
**
|
||||
**---------------------------------------------------------------------------
|
||||
** Copyright 1999-2016 Randy Heit
|
||||
** Copyright 2005-2019 Christoph Oelckers
|
||||
** All rights reserved.
|
||||
**
|
||||
** Redistribution and use in source and binary forms, with or without
|
||||
** modification, are permitted provided that the following conditions
|
||||
** are met:
|
||||
**
|
||||
** 1. Redistributions of source code must retain the above copyright
|
||||
** notice, this list of conditions and the following disclaimer.
|
||||
** 2. Redistributions in binary form must reproduce the above copyright
|
||||
** notice, this list of conditions and the following disclaimer in the
|
||||
** documentation and/or other materials provided with the distribution.
|
||||
** 3. The name of the author may not be used to endorse or promote products
|
||||
** derived from this software without specific prior written permission.
|
||||
**
|
||||
** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
|
||||
** IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
|
||||
** OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
||||
** IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
** INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
|
||||
** NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
|
||||
** THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
**---------------------------------------------------------------------------
|
||||
**
|
||||
*/
|
||||
#include "i_musicinterns.h"
|
||||
#include "i_soundfont.h"
|
||||
#include "adlmidi.h"
|
||||
#include "cmdlib.h"
|
||||
|
||||
// do this without including windows.h for this one single prototype
|
||||
extern "C" unsigned __stdcall GetSystemDirectoryA(char* lpBuffer, unsigned uSize);
|
||||
|
||||
static void CheckRestart(int devtype)
|
||||
{
|
||||
|
@ -11,62 +49,367 @@ static void CheckRestart(int devtype)
|
|||
}
|
||||
}
|
||||
|
||||
// This is part of the config struct so that the device does not have to depend on the sound font manager and can work without it.
|
||||
static const char *ADL_FullPath(const char *bankfile)
|
||||
{
|
||||
auto info = sfmanager.FindSoundFont(bankfile, SF_WOPL);
|
||||
if(info == nullptr) return nullptr;
|
||||
return info->mFilename;
|
||||
}
|
||||
|
||||
ADLConfig adlConfig = { ADL_FullPath };
|
||||
ADLConfig adlConfig;
|
||||
FluidConfig fluidConfig;
|
||||
|
||||
|
||||
CUSTOM_CVAR(Int, adl_chips_count, 6, CVAR_ARCHIVE | CVAR_GLOBALCONFIG)
|
||||
{
|
||||
CheckRestart(MDEV_ADL);
|
||||
adlConfig.adl_chips_count = self;
|
||||
CheckRestart(MDEV_ADL);
|
||||
}
|
||||
|
||||
CUSTOM_CVAR(Int, adl_emulator_id, 0, CVAR_ARCHIVE | CVAR_GLOBALCONFIG)
|
||||
{
|
||||
CheckRestart(MDEV_ADL);
|
||||
adlConfig.adl_emulator_id = self;
|
||||
CheckRestart(MDEV_ADL);
|
||||
}
|
||||
|
||||
CUSTOM_CVAR(Bool, adl_run_at_pcm_rate, 0, CVAR_ARCHIVE | CVAR_GLOBALCONFIG)
|
||||
{
|
||||
CheckRestart(MDEV_ADL);
|
||||
adlConfig.adl_run_at_pcm_rate = self;
|
||||
CheckRestart(MDEV_ADL);
|
||||
}
|
||||
|
||||
CUSTOM_CVAR(Bool, adl_fullpan, 1, CVAR_ARCHIVE | CVAR_GLOBALCONFIG)
|
||||
{
|
||||
CheckRestart(MDEV_ADL);
|
||||
adlConfig.adl_fullpan = self;
|
||||
CheckRestart(MDEV_ADL);
|
||||
}
|
||||
|
||||
CUSTOM_CVAR(Int, adl_bank, 14, CVAR_ARCHIVE | CVAR_GLOBALCONFIG)
|
||||
{
|
||||
CheckRestart(MDEV_ADL);
|
||||
adlConfig.adl_bank = self;
|
||||
CheckRestart(MDEV_ADL);
|
||||
}
|
||||
|
||||
CUSTOM_CVAR(Bool, adl_use_custom_bank, 0, CVAR_ARCHIVE | CVAR_GLOBALCONFIG)
|
||||
{
|
||||
CheckRestart(MDEV_ADL);
|
||||
adlConfig.adl_use_custom_bank = self;
|
||||
CheckRestart(MDEV_ADL);
|
||||
}
|
||||
|
||||
CUSTOM_CVAR(String, adl_custom_bank, "", CVAR_ARCHIVE | CVAR_GLOBALCONFIG)
|
||||
{
|
||||
CheckRestart(MDEV_ADL);
|
||||
adlConfig.adl_custom_bank = self;
|
||||
|
||||
//Resolve the path here, so that the renderer does not have to do the work itself and only needs to process final names.
|
||||
auto info = sfmanager.FindSoundFont(self, SF_WOPL);
|
||||
if (info == nullptr) adlConfig.adl_custom_bank = nullptr;
|
||||
adlConfig.adl_custom_bank = info->mFilename;
|
||||
}
|
||||
|
||||
CUSTOM_CVAR(Int, adl_volume_model, ADLMIDI_VolumeModel_DMX, CVAR_ARCHIVE | CVAR_GLOBALCONFIG)
|
||||
{
|
||||
CheckRestart(MDEV_ADL);
|
||||
adlConfig.adl_volume_model = self;
|
||||
CheckRestart(MDEV_ADL);
|
||||
}
|
||||
|
||||
#define FLUID_CHORUS_MOD_SINE 0
|
||||
#define FLUID_CHORUS_MOD_TRIANGLE 1
|
||||
#define FLUID_CHORUS_DEFAULT_TYPE FLUID_CHORUS_MOD_SINE
|
||||
|
||||
|
||||
CUSTOM_CVAR(String, fluid_lib, "", CVAR_ARCHIVE|CVAR_GLOBALCONFIG)
|
||||
{
|
||||
fluidConfig.fluid_lib = self; // only takes effect for next song.
|
||||
}
|
||||
|
||||
int BuildFluidPatchSetList(const char* patches, bool systemfallback)
|
||||
{
|
||||
fluidConfig.fluid_patchset.clear();
|
||||
//Resolve the paths here, the renderer will only get a final list of file names.
|
||||
auto info = sfmanager.FindSoundFont(patches, SF_SF2);
|
||||
if (info != nullptr) patches = info->mFilename.GetChars();
|
||||
|
||||
int count;
|
||||
char* wpatches = strdup(patches);
|
||||
char* tok;
|
||||
#ifdef _WIN32
|
||||
const char* const delim = ";";
|
||||
#else
|
||||
const char* const delim = ":";
|
||||
#endif
|
||||
|
||||
if (wpatches == NULL)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
tok = strtok(wpatches, delim);
|
||||
count = 0;
|
||||
while (tok != NULL)
|
||||
{
|
||||
FString path;
|
||||
#ifdef _WIN32
|
||||
// If the path does not contain any path separators, automatically
|
||||
// prepend $PROGDIR to the path.
|
||||
if (strcspn(tok, ":/\\") == strlen(tok))
|
||||
{
|
||||
path << "$PROGDIR/" << tok;
|
||||
path = NicePath(path);
|
||||
}
|
||||
else
|
||||
#endif
|
||||
{
|
||||
path = NicePath(tok);
|
||||
}
|
||||
if (FileExists(path))
|
||||
{
|
||||
fluidConfig.fluid_patchset.push_back(path.GetChars());
|
||||
}
|
||||
else
|
||||
{
|
||||
Printf("Could not find patch set %s.\n", tok);
|
||||
}
|
||||
tok = strtok(NULL, delim);
|
||||
}
|
||||
free(wpatches);
|
||||
if (fluidConfig.fluid_patchset.size() > 0) return 1;
|
||||
|
||||
if (systemfallback)
|
||||
{
|
||||
// The following will only be used if no soundfont at all is provided, i.e. even the standard one coming with GZDoom is missing.
|
||||
#ifdef __unix__
|
||||
// This is the standard location on Ubuntu.
|
||||
return BuildFluidPatchSetList("/usr/share/sounds/sf2/FluidR3_GS.sf2:/usr/share/sounds/sf2/FluidR3_GM.sf2", false);
|
||||
#endif
|
||||
#ifdef _WIN32
|
||||
// On Windows, look for the 4 megabyte patch set installed by Creative's drivers as a default.
|
||||
char sysdir[PATH_MAX + sizeof("\\CT4MGM.SF2")];
|
||||
uint32_t filepart;
|
||||
if (0 != (filepart = GetSystemDirectoryA(sysdir, PATH_MAX)))
|
||||
{
|
||||
strcat(sysdir, "\\CT4MGM.SF2");
|
||||
if (FileExists(sysdir))
|
||||
{
|
||||
fluidConfig.fluid_patchset.push_back(sysdir);
|
||||
return 1;
|
||||
}
|
||||
// Try again with CT2MGM.SF2
|
||||
sysdir[filepart + 3] = '2';
|
||||
if (FileExists(sysdir))
|
||||
{
|
||||
fluidConfig.fluid_patchset.push_back(sysdir);
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
CUSTOM_CVAR(String, fluid_patchset, "gzdoom", CVAR_ARCHIVE | CVAR_GLOBALCONFIG)
|
||||
{
|
||||
CheckRestart(MDEV_FLUIDSYNTH);
|
||||
}
|
||||
|
||||
CUSTOM_CVAR(Float, fluid_gain, 0.5, CVAR_ARCHIVE|CVAR_GLOBALCONFIG)
|
||||
{
|
||||
if (self < 0)
|
||||
self = 0;
|
||||
else if (self > 10)
|
||||
self = 10;
|
||||
else
|
||||
{
|
||||
if (currSong != NULL)
|
||||
currSong->ChangeSettingNum("fluidsynth.synth.gain", self);
|
||||
fluidConfig.fluid_gain = self;
|
||||
}
|
||||
}
|
||||
|
||||
CUSTOM_CVAR(Bool, fluid_reverb, false, CVAR_ARCHIVE|CVAR_GLOBALCONFIG)
|
||||
{
|
||||
if (currSong != NULL)
|
||||
currSong->ChangeSettingInt("fluidsynth.synth.reverb.active", self);
|
||||
fluidConfig.fluid_reverb = self;
|
||||
}
|
||||
|
||||
CUSTOM_CVAR(Bool, fluid_chorus, false, CVAR_ARCHIVE|CVAR_GLOBALCONFIG)
|
||||
{
|
||||
if (currSong != NULL)
|
||||
currSong->ChangeSettingInt("fluidsynth.synth.chorus.active", self);
|
||||
fluidConfig.fluid_chorus = self;
|
||||
}
|
||||
|
||||
CUSTOM_CVAR(Int, fluid_voices, 128, CVAR_ARCHIVE|CVAR_GLOBALCONFIG)
|
||||
{
|
||||
if (self < 16)
|
||||
self = 16;
|
||||
else if (self > 4096)
|
||||
self = 4096;
|
||||
else
|
||||
{
|
||||
if (currSong != NULL)
|
||||
currSong->ChangeSettingInt("fluidsynth.synth.polyphony", self);
|
||||
fluidConfig.fluid_voices = self;
|
||||
}
|
||||
}
|
||||
|
||||
CUSTOM_CVAR(Int, fluid_interp, 1, CVAR_ARCHIVE|CVAR_GLOBALCONFIG)
|
||||
{
|
||||
// Values are: 0 = FLUID_INTERP_NONE
|
||||
// 1 = FLUID_INTERP_LINEAR
|
||||
// 4 = FLUID_INTERP_4THORDER (the FluidSynth default)
|
||||
// 7 = FLUID_INTERP_7THORDER
|
||||
// (And here I thought it was just a linear list.)
|
||||
// Round undefined values to the nearest valid one.
|
||||
if (self < 0)
|
||||
self = 0;
|
||||
else if (self == 2)
|
||||
self = 1;
|
||||
else if (self == 3 || self == 5)
|
||||
self = 4;
|
||||
else if (self == 6 || self > 7)
|
||||
self = 7;
|
||||
else
|
||||
{
|
||||
if (currSong != NULL)
|
||||
currSong->ChangeSettingInt("fluidsynth.synth.interpolation", self);
|
||||
fluidConfig.fluid_interp = self;
|
||||
}
|
||||
}
|
||||
|
||||
CUSTOM_CVAR(Int, fluid_samplerate, 0, CVAR_ARCHIVE|CVAR_GLOBALCONFIG)
|
||||
{
|
||||
fluidConfig.fluid_samplerate = std::max<int>(*self, 0);
|
||||
}
|
||||
|
||||
// I don't know if this setting even matters for us, since we aren't letting
|
||||
// FluidSynth drives its own output.
|
||||
CUSTOM_CVAR(Int, fluid_threads, 1, CVAR_ARCHIVE|CVAR_GLOBALCONFIG)
|
||||
{
|
||||
if (self < 1)
|
||||
self = 1;
|
||||
else if (self > 256)
|
||||
self = 256;
|
||||
else
|
||||
fluidConfig.fluid_threads = self;
|
||||
}
|
||||
|
||||
CUSTOM_CVAR(Float, fluid_reverb_roomsize, 0.61f, CVAR_ARCHIVE|CVAR_GLOBALCONFIG)
|
||||
{
|
||||
if (self < 0)
|
||||
self = 0;
|
||||
else if (self > 1.2f)
|
||||
self = 1.2f;
|
||||
else
|
||||
{
|
||||
if (currSong != NULL)
|
||||
currSong->ChangeSettingNum("fluidsynth.z.reverb-roomsize", self);
|
||||
fluidConfig.fluid_reverb_roomsize = self;
|
||||
}
|
||||
}
|
||||
|
||||
CUSTOM_CVAR(Float, fluid_reverb_damping, 0.23f, CVAR_ARCHIVE|CVAR_GLOBALCONFIG)
|
||||
{
|
||||
if (self < 0)
|
||||
self = 0;
|
||||
else if (self > 1)
|
||||
self = 1;
|
||||
else
|
||||
{
|
||||
if (currSong != NULL)
|
||||
currSong->ChangeSettingNum("fluidsynth.z.reverb-damping", self);
|
||||
fluidConfig.fluid_reverb_damping = self;
|
||||
}
|
||||
}
|
||||
|
||||
CUSTOM_CVAR(Float, fluid_reverb_width, 0.76f, CVAR_ARCHIVE|CVAR_GLOBALCONFIG)
|
||||
{
|
||||
if (self < 0)
|
||||
self = 0;
|
||||
else if (self > 100)
|
||||
self = 100;
|
||||
else
|
||||
{
|
||||
if (currSong != NULL)
|
||||
currSong->ChangeSettingNum("fluidsynth.z.reverb-width", self);
|
||||
fluidConfig.fluid_reverb_width = self;
|
||||
}
|
||||
}
|
||||
|
||||
CUSTOM_CVAR(Float, fluid_reverb_level, 0.57f, CVAR_ARCHIVE|CVAR_GLOBALCONFIG)
|
||||
{
|
||||
if (self < 0)
|
||||
self = 0;
|
||||
else if (self > 1)
|
||||
self = 1;
|
||||
else
|
||||
{
|
||||
if (currSong != NULL)
|
||||
currSong->ChangeSettingNum("fluidsynth.z.reverb-level", self);
|
||||
fluidConfig.fluid_reverb_level = self;
|
||||
}
|
||||
}
|
||||
|
||||
CUSTOM_CVAR(Int, fluid_chorus_voices, 3, CVAR_ARCHIVE|CVAR_GLOBALCONFIG)
|
||||
{
|
||||
if (self < 0)
|
||||
self = 0;
|
||||
else if (self > 99)
|
||||
self = 99;
|
||||
else
|
||||
{
|
||||
if (currSong != NULL)
|
||||
currSong->ChangeSettingNum("fluidsynth.z.chorus-voices", self);
|
||||
fluidConfig.fluid_chorus_voices = self;
|
||||
}
|
||||
}
|
||||
|
||||
CUSTOM_CVAR(Float, fluid_chorus_level, 1.2f, CVAR_ARCHIVE|CVAR_GLOBALCONFIG)
|
||||
{
|
||||
if (self < 0)
|
||||
self = 0;
|
||||
else if (self > 1)
|
||||
self = 1;
|
||||
else
|
||||
{
|
||||
if (currSong != NULL)
|
||||
currSong->ChangeSettingNum("fluidsynth.z.chorus-level", self);
|
||||
fluidConfig.fluid_chorus_level = self;
|
||||
}
|
||||
}
|
||||
|
||||
CUSTOM_CVAR(Float, fluid_chorus_speed, 0.3f, CVAR_ARCHIVE|CVAR_GLOBALCONFIG)
|
||||
{
|
||||
if (self < 0.29f)
|
||||
self = 0.29f;
|
||||
else if (self > 5)
|
||||
self = 5;
|
||||
else
|
||||
{
|
||||
if (currSong != NULL)
|
||||
currSong->ChangeSettingNum("fluidsynth.z.chorus-speed", self);
|
||||
fluidConfig.fluid_chorus_speed = self;
|
||||
}
|
||||
}
|
||||
|
||||
// depth is in ms and actual maximum depends on the sample rate
|
||||
CUSTOM_CVAR(Float, fluid_chorus_depth, 8, CVAR_ARCHIVE|CVAR_GLOBALCONFIG)
|
||||
{
|
||||
if (self < 0)
|
||||
self = 0;
|
||||
else if (self > 21)
|
||||
self = 21;
|
||||
else
|
||||
{
|
||||
if (currSong != NULL)
|
||||
currSong->ChangeSettingNum("fluidsynth.z.chorus-depth", self);
|
||||
fluidConfig.fluid_chorus_depth = self;
|
||||
}
|
||||
}
|
||||
|
||||
CUSTOM_CVAR(Int, fluid_chorus_type, FLUID_CHORUS_DEFAULT_TYPE, CVAR_ARCHIVE|CVAR_GLOBALCONFIG)
|
||||
{
|
||||
if (self != FLUID_CHORUS_MOD_SINE && self != FLUID_CHORUS_MOD_TRIANGLE)
|
||||
self = FLUID_CHORUS_DEFAULT_TYPE;
|
||||
else
|
||||
{
|
||||
if (currSong != NULL)
|
||||
currSong->ChangeSettingNum("fluidsynth.z.chorus-type", self); // Uses float to simplify the checking code in the renderer.
|
||||
fluidConfig.fluid_chorus_type = self;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -118,13 +118,8 @@ ADLMIDIDevice::~ADLMIDIDevice()
|
|||
|
||||
int ADLMIDIDevice::LoadCustomBank(const char *bankfile, const ADLConfig *config)
|
||||
{
|
||||
if(!config->adl_use_custom_bank)
|
||||
if(!config->adl_use_custom_bank || !bankfile || !*bankfile)
|
||||
return 0;
|
||||
if (config->adl_full_path)
|
||||
{
|
||||
bankfile = config->adl_full_path(bankfile);
|
||||
if(bankfile == nullptr) return 0;
|
||||
}
|
||||
return (adl_openBankFile(Renderer, bankfile) == 0);
|
||||
}
|
||||
|
||||
|
|
|
@ -35,11 +35,6 @@
|
|||
// HEADER FILES ------------------------------------------------------------
|
||||
|
||||
#include "i_musicinterns.h"
|
||||
#include "i_system.h"
|
||||
#include "v_text.h"
|
||||
#include "cmdlib.h"
|
||||
#include "i_soundfont.h"
|
||||
#include "doomerrors.h"
|
||||
|
||||
// FluidSynth implementation of a MIDI device -------------------------------
|
||||
|
||||
|
@ -56,7 +51,7 @@ struct fluid_synth_t;
|
|||
class FluidSynthMIDIDevice : public SoftSynthMIDIDevice
|
||||
{
|
||||
public:
|
||||
FluidSynthMIDIDevice(const char *args, int samplerate, int (*printfunc_)(const char *, ...));
|
||||
FluidSynthMIDIDevice(int samplerate, FluidConfig *config, int (*printfunc_)(const char *, ...));
|
||||
~FluidSynthMIDIDevice();
|
||||
|
||||
int Open(MidiCallback, void *userdata);
|
||||
|
@ -70,11 +65,17 @@ protected:
|
|||
void HandleEvent(int status, int parm1, int parm2);
|
||||
void HandleLongEvent(const uint8_t *data, int len);
|
||||
void ComputeOutput(float *buffer, int len);
|
||||
int LoadPatchSets(const char *patches);
|
||||
int LoadPatchSets(FluidConfig *config);
|
||||
|
||||
fluid_settings_t *FluidSettings;
|
||||
fluid_synth_t *FluidSynth;
|
||||
int (*printfunc)(const char*, ...);
|
||||
|
||||
// These are getting set together, so if we want to keep the renderer and the config data separate we need to store local copies to apply changes.
|
||||
float fluid_reverb_roomsize, fluid_reverb_damping, fluid_reverb_width, fluid_reverb_level;
|
||||
float fluid_chorus_level,fluid_chorus_speed, fluid_chorus_depth;
|
||||
int fluid_chorus_voices, fluid_chorus_type;
|
||||
|
||||
|
||||
#ifdef DYN_FLUIDSYNTH
|
||||
enum { FLUID_FAILED = -1, FLUID_OK = 0 };
|
||||
|
@ -106,7 +107,7 @@ protected:
|
|||
static TReqProc<FluidSynthModule, void (*)(fluid_synth_t *, int, double, double, double, int)> fluid_synth_set_chorus;
|
||||
static TReqProc<FluidSynthModule, int (*)(fluid_synth_t *, const char *, int, char *, int *, int *, int)> fluid_synth_sysex;
|
||||
|
||||
bool LoadFluidSynth();
|
||||
bool LoadFluidSynth(const char *fluid_lib);
|
||||
void UnloadFluidSynth();
|
||||
#endif
|
||||
};
|
||||
|
@ -117,9 +118,6 @@ protected:
|
|||
|
||||
#ifdef _WIN32
|
||||
|
||||
// do this without including windows.h for this one single prototype
|
||||
extern "C" unsigned __stdcall GetSystemDirectoryA(char *lpBuffer, unsigned uSize);
|
||||
|
||||
#ifndef _M_X64
|
||||
#define FLUIDSYNTHLIB1 "fluidsynth.dll"
|
||||
#define FLUIDSYNTHLIB2 "libfluidsynth.dll"
|
||||
|
@ -137,14 +135,8 @@ extern "C" unsigned __stdcall GetSystemDirectoryA(char *lpBuffer, unsigned uSize
|
|||
#endif // __APPLE__
|
||||
#endif
|
||||
|
||||
#define FLUID_CHORUS_MOD_SINE 0
|
||||
#define FLUID_CHORUS_MOD_TRIANGLE 1
|
||||
|
||||
#endif
|
||||
|
||||
#ifndef FLUID_CHORUS_DEFAULT_TYPE
|
||||
#define FLUID_CHORUS_DEFAULT_TYPE FLUID_CHORUS_MOD_SINE
|
||||
#endif
|
||||
|
||||
// TYPES -------------------------------------------------------------------
|
||||
|
||||
|
@ -162,169 +154,6 @@ const char *BaseFileSearch(const char *file, const char *ext, bool lookfirstinpr
|
|||
|
||||
// PUBLIC DATA DEFINITIONS -------------------------------------------------
|
||||
|
||||
CVAR(String, fluid_lib, "", CVAR_ARCHIVE|CVAR_GLOBALCONFIG)
|
||||
|
||||
CUSTOM_CVAR(String, fluid_patchset, "gzdoom", CVAR_ARCHIVE | CVAR_GLOBALCONFIG)
|
||||
{
|
||||
if (currSong != nullptr && currSong->GetDeviceType() == MDEV_FLUIDSYNTH)
|
||||
{
|
||||
MIDIDeviceChanged(-1, true);
|
||||
}
|
||||
}
|
||||
|
||||
CUSTOM_CVAR(Float, fluid_gain, 0.5, CVAR_ARCHIVE|CVAR_GLOBALCONFIG)
|
||||
{
|
||||
if (self < 0)
|
||||
self = 0;
|
||||
else if (self > 10)
|
||||
self = 10;
|
||||
else if (currSong != NULL)
|
||||
currSong->ChangeSettingNum("fluidsynth.synth.gain", self);
|
||||
}
|
||||
|
||||
CUSTOM_CVAR(Bool, fluid_reverb, false, CVAR_ARCHIVE|CVAR_GLOBALCONFIG)
|
||||
{
|
||||
if (currSong != NULL)
|
||||
currSong->ChangeSettingInt("fluidsynth.synth.reverb.active", self);
|
||||
}
|
||||
|
||||
CUSTOM_CVAR(Bool, fluid_chorus, false, CVAR_ARCHIVE|CVAR_GLOBALCONFIG)
|
||||
{
|
||||
if (currSong != NULL)
|
||||
currSong->ChangeSettingInt("fluidsynth.synth.chorus.active", self);
|
||||
}
|
||||
|
||||
CUSTOM_CVAR(Int, fluid_voices, 128, CVAR_ARCHIVE|CVAR_GLOBALCONFIG)
|
||||
{
|
||||
if (self < 16)
|
||||
self = 16;
|
||||
else if (self > 4096)
|
||||
self = 4096;
|
||||
else if (currSong != NULL)
|
||||
currSong->ChangeSettingInt("fluidsynth.synth.polyphony", self);
|
||||
}
|
||||
|
||||
CUSTOM_CVAR(Int, fluid_interp, 1, CVAR_ARCHIVE|CVAR_GLOBALCONFIG)
|
||||
{
|
||||
// Values are: 0 = FLUID_INTERP_NONE
|
||||
// 1 = FLUID_INTERP_LINEAR
|
||||
// 4 = FLUID_INTERP_4THORDER (the FluidSynth default)
|
||||
// 7 = FLUID_INTERP_7THORDER
|
||||
// (And here I thought it was just a linear list.)
|
||||
// Round undefined values to the nearest valid one.
|
||||
if (self < 0)
|
||||
self = 0;
|
||||
else if (self == 2)
|
||||
self = 1;
|
||||
else if (self == 3 || self == 5)
|
||||
self = 4;
|
||||
else if (self == 6 || self > 7)
|
||||
self = 7;
|
||||
else if (currSong != NULL)
|
||||
currSong->ChangeSettingInt("fluidsynth.synth.interpolation", self);
|
||||
}
|
||||
|
||||
CVAR(Int, fluid_samplerate, 0, CVAR_ARCHIVE|CVAR_GLOBALCONFIG)
|
||||
|
||||
// I don't know if this setting even matters for us, since we aren't letting
|
||||
// FluidSynth drives its own output.
|
||||
CUSTOM_CVAR(Int, fluid_threads, 1, CVAR_ARCHIVE|CVAR_GLOBALCONFIG)
|
||||
{
|
||||
if (self < 1)
|
||||
self = 1;
|
||||
else if (self > 256)
|
||||
self = 256;
|
||||
}
|
||||
|
||||
CUSTOM_CVAR(Float, fluid_reverb_roomsize, 0.61f, CVAR_ARCHIVE|CVAR_GLOBALCONFIG)
|
||||
{
|
||||
if (self < 0)
|
||||
self = 0;
|
||||
else if (self > 1.2f)
|
||||
self = 1.2f;
|
||||
else if (currSong != NULL)
|
||||
currSong->ChangeSettingInt("fluidsynth.z.reverb-changed", 0);
|
||||
}
|
||||
|
||||
CUSTOM_CVAR(Float, fluid_reverb_damping, 0.23f, CVAR_ARCHIVE|CVAR_GLOBALCONFIG)
|
||||
{
|
||||
if (self < 0)
|
||||
self = 0;
|
||||
else if (self > 1)
|
||||
self = 1;
|
||||
else if (currSong != NULL)
|
||||
currSong->ChangeSettingInt("fluidsynth.z.reverb-changed", 0);
|
||||
}
|
||||
|
||||
CUSTOM_CVAR(Float, fluid_reverb_width, 0.76f, CVAR_ARCHIVE|CVAR_GLOBALCONFIG)
|
||||
{
|
||||
if (self < 0)
|
||||
self = 0;
|
||||
else if (self > 100)
|
||||
self = 100;
|
||||
else if (currSong != NULL)
|
||||
currSong->ChangeSettingInt("fluidsynth.z.reverb-changed", 0);
|
||||
}
|
||||
|
||||
CUSTOM_CVAR(Float, fluid_reverb_level, 0.57f, CVAR_ARCHIVE|CVAR_GLOBALCONFIG)
|
||||
{
|
||||
if (self < 0)
|
||||
self = 0;
|
||||
else if (self > 1)
|
||||
self = 1;
|
||||
else if (currSong != NULL)
|
||||
currSong->ChangeSettingInt("fluidsynth.z.reverb-changed", 0);
|
||||
}
|
||||
|
||||
CUSTOM_CVAR(Int, fluid_chorus_voices, 3, CVAR_ARCHIVE|CVAR_GLOBALCONFIG)
|
||||
{
|
||||
if (self < 0)
|
||||
self = 0;
|
||||
else if (self > 99)
|
||||
self = 99;
|
||||
else if (currSong != NULL)
|
||||
currSong->ChangeSettingInt("fluidsynth.z.chorus-changed", 0);
|
||||
}
|
||||
|
||||
CUSTOM_CVAR(Float, fluid_chorus_level, 1.2f, CVAR_ARCHIVE|CVAR_GLOBALCONFIG)
|
||||
{
|
||||
if (self < 0)
|
||||
self = 0;
|
||||
else if (self > 1)
|
||||
self = 1;
|
||||
else if (currSong != NULL)
|
||||
currSong->ChangeSettingInt("fluidsynth.z.chorus-changed", 0);
|
||||
}
|
||||
|
||||
CUSTOM_CVAR(Float, fluid_chorus_speed, 0.3f, CVAR_ARCHIVE|CVAR_GLOBALCONFIG)
|
||||
{
|
||||
if (self < 0.29f)
|
||||
self = 0.29f;
|
||||
else if (self > 5)
|
||||
self = 5;
|
||||
else if (currSong != NULL)
|
||||
currSong->ChangeSettingInt("fluidsynth.z.chorus-changed", 0);
|
||||
}
|
||||
|
||||
// depth is in ms and actual maximum depends on the sample rate
|
||||
CUSTOM_CVAR(Float, fluid_chorus_depth, 8, CVAR_ARCHIVE|CVAR_GLOBALCONFIG)
|
||||
{
|
||||
if (self < 0)
|
||||
self = 0;
|
||||
else if (self > 21)
|
||||
self = 21;
|
||||
else if (currSong != NULL)
|
||||
currSong->ChangeSettingInt("fluidsynth.z.chorus-changed", 0);
|
||||
}
|
||||
|
||||
CUSTOM_CVAR(Int, fluid_chorus_type, FLUID_CHORUS_DEFAULT_TYPE, CVAR_ARCHIVE|CVAR_GLOBALCONFIG)
|
||||
{
|
||||
if (self != FLUID_CHORUS_MOD_SINE && self != FLUID_CHORUS_MOD_TRIANGLE)
|
||||
self = FLUID_CHORUS_DEFAULT_TYPE;
|
||||
else if (currSong != NULL)
|
||||
currSong->ChangeSettingInt("fluidsynth.z.chorus-changed", 0);
|
||||
}
|
||||
|
||||
// CODE --------------------------------------------------------------------
|
||||
|
||||
//==========================================================================
|
||||
|
@ -333,14 +162,25 @@ CUSTOM_CVAR(Int, fluid_chorus_type, FLUID_CHORUS_DEFAULT_TYPE, CVAR_ARCHIVE|CVAR
|
|||
//
|
||||
//==========================================================================
|
||||
|
||||
FluidSynthMIDIDevice::FluidSynthMIDIDevice(const char *args, int samplerate, int (*printfunc_)(const char*, ...) = nullptr)
|
||||
: SoftSynthMIDIDevice(samplerate <= 0? fluid_samplerate : samplerate, 22050, 96000)
|
||||
FluidSynthMIDIDevice::FluidSynthMIDIDevice(int samplerate, FluidConfig *config, int (*printfunc_)(const char*, ...) = nullptr)
|
||||
: SoftSynthMIDIDevice(samplerate <= 0? config->fluid_samplerate : samplerate, 22050, 96000)
|
||||
{
|
||||
// These are needed for changing the settings. If something posts a transient config in here we got no way to retrieve the values afterward.
|
||||
fluid_reverb_roomsize = config->fluid_reverb_roomsize;
|
||||
fluid_reverb_damping = config->fluid_reverb_damping;
|
||||
fluid_reverb_width = config->fluid_reverb_width;
|
||||
fluid_reverb_level = config->fluid_reverb_level;
|
||||
fluid_chorus_voices = config->fluid_chorus_voices;
|
||||
fluid_chorus_level = config->fluid_chorus_level;
|
||||
fluid_chorus_speed = config->fluid_chorus_speed;
|
||||
fluid_chorus_depth = config->fluid_chorus_depth;
|
||||
fluid_chorus_type = config->fluid_chorus_type;
|
||||
|
||||
printfunc = printfunc_;
|
||||
FluidSynth = NULL;
|
||||
FluidSettings = NULL;
|
||||
#ifdef DYN_FLUIDSYNTH
|
||||
LoadFluidSynth();
|
||||
if (!LoadFluidSynth(config->fluid_lib))
|
||||
{
|
||||
throw std::runtime_error("Failed to load FluidSynth.\n");
|
||||
}
|
||||
|
@ -351,18 +191,18 @@ FluidSynthMIDIDevice::FluidSynthMIDIDevice(const char *args, int samplerate, int
|
|||
throw std::runtime_error("Failed to create FluidSettings.\n");
|
||||
}
|
||||
fluid_settings_setnum(FluidSettings, "synth.sample-rate", SampleRate);
|
||||
fluid_settings_setnum(FluidSettings, "synth.gain", fluid_gain);
|
||||
fluid_settings_setint(FluidSettings, "synth.reverb.active", fluid_reverb);
|
||||
fluid_settings_setint(FluidSettings, "synth.chorus.active", fluid_chorus);
|
||||
fluid_settings_setint(FluidSettings, "synth.polyphony", fluid_voices);
|
||||
fluid_settings_setint(FluidSettings, "synth.cpu-cores", fluid_threads);
|
||||
fluid_settings_setnum(FluidSettings, "synth.gain", config->fluid_gain);
|
||||
fluid_settings_setint(FluidSettings, "synth.reverb.active", config->fluid_reverb);
|
||||
fluid_settings_setint(FluidSettings, "synth.chorus.active", config->fluid_chorus);
|
||||
fluid_settings_setint(FluidSettings, "synth.polyphony", config->fluid_voices);
|
||||
fluid_settings_setint(FluidSettings, "synth.cpu-cores", config->fluid_threads);
|
||||
FluidSynth = new_fluid_synth(FluidSettings);
|
||||
if (FluidSynth == NULL)
|
||||
{
|
||||
delete_fluid_settings(FluidSettings);
|
||||
throw std::runtime_error("Failed to create FluidSynth.\n");
|
||||
}
|
||||
fluid_synth_set_interp_method(FluidSynth, -1, fluid_interp);
|
||||
fluid_synth_set_interp_method(FluidSynth, -1, config->fluid_interp);
|
||||
fluid_synth_set_reverb(FluidSynth, fluid_reverb_roomsize, fluid_reverb_damping,
|
||||
fluid_reverb_width, fluid_reverb_level);
|
||||
fluid_synth_set_chorus(FluidSynth, fluid_chorus_voices, fluid_chorus_level,
|
||||
|
@ -370,45 +210,12 @@ FluidSynthMIDIDevice::FluidSynthMIDIDevice(const char *args, int samplerate, int
|
|||
|
||||
// try loading a patch set that got specified with $mididevice.
|
||||
int res = 0;
|
||||
if (args != NULL && *args != 0)
|
||||
{
|
||||
if (LoadPatchSets(args)) return;
|
||||
}
|
||||
|
||||
if (LoadPatchSets(fluid_patchset))
|
||||
if (LoadPatchSets(config))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
// The following will only be used if no soundfont at all is provided, i.e. even the standard one coming with GZDoom is missing.
|
||||
#ifdef __unix__
|
||||
// This is the standard location on Ubuntu.
|
||||
if (LoadPatchSets("/usr/share/sounds/sf2/FluidR3_GS.sf2:/usr/share/sounds/sf2/FluidR3_GM.sf2"))
|
||||
{
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
#ifdef _WIN32
|
||||
// On Windows, look for the 4 megabyte patch set installed by Creative's drivers as a default.
|
||||
char sysdir[MAX_PATH + sizeof("\\CT4MGM.SF2")];
|
||||
uint32_t filepart;
|
||||
if (0 != (filepart = GetSystemDirectoryA(sysdir, MAX_PATH)))
|
||||
{
|
||||
strcat(sysdir, "\\CT4MGM.SF2");
|
||||
if (LoadPatchSets(sysdir))
|
||||
{
|
||||
return;
|
||||
}
|
||||
// Try again with CT2MGM.SF2
|
||||
sysdir[filepart + 3] = '2';
|
||||
if (LoadPatchSets(sysdir))
|
||||
{
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
delete_fluid_settings(FluidSettings);
|
||||
delete_fluid_synth(FluidSynth);
|
||||
FluidSynth = nullptr;
|
||||
|
@ -539,67 +346,23 @@ void FluidSynthMIDIDevice::ComputeOutput(float *buffer, int len)
|
|||
//
|
||||
// FluidSynthMIDIDevice :: LoadPatchSets
|
||||
//
|
||||
// Loads a delimiter-separated list of patch sets. This delimiter matches
|
||||
// that of the PATH environment variable. On Windows, it is ';'. On other
|
||||
// systems, it is ':'. Returns the number of patch sets loaded.
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
int FluidSynthMIDIDevice::LoadPatchSets(const char *patches)
|
||||
int FluidSynthMIDIDevice::LoadPatchSets(FluidConfig *config)
|
||||
{
|
||||
auto info = sfmanager.FindSoundFont(patches, SF_SF2);
|
||||
if (info != nullptr) patches = info->mFilename.GetChars();
|
||||
|
||||
int count;
|
||||
char *wpatches = strdup(patches);
|
||||
char *tok;
|
||||
#ifdef _WIN32
|
||||
const char *const delim = ";";
|
||||
#else
|
||||
const char *const delim = ":";
|
||||
#endif
|
||||
|
||||
if (wpatches == NULL)
|
||||
int count = 0;
|
||||
for (auto& file : config->fluid_patchset)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
tok = strtok(wpatches, delim);
|
||||
count = 0;
|
||||
while (tok != NULL)
|
||||
{
|
||||
FString path;
|
||||
#ifdef _WIN32
|
||||
// If the path does not contain any path separators, automatically
|
||||
// prepend $PROGDIR to the path.
|
||||
if (strcspn(tok, ":/\\") == strlen(tok))
|
||||
if (FLUID_FAILED != fluid_synth_sfload(FluidSynth, file.c_str(), count == 0))
|
||||
{
|
||||
path << "$PROGDIR/" << tok;
|
||||
path = NicePath(path);
|
||||
}
|
||||
else
|
||||
#endif
|
||||
{
|
||||
path = NicePath(tok);
|
||||
}
|
||||
if (FileExists(path))
|
||||
{
|
||||
if (FLUID_FAILED != fluid_synth_sfload(FluidSynth, path, count == 0))
|
||||
{
|
||||
//DPrintf(DMSG_NOTIFY, "Loaded patch set %s.\n", tok);
|
||||
count++;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (printfunc) printfunc("Failed to load patch set %s.\n", tok);
|
||||
}
|
||||
//DPrintf(DMSG_NOTIFY, "Loaded patch set %s.\n", tok);
|
||||
count++;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (printfunc) printfunc("Could not find patch set %s.\n", tok);
|
||||
if (printfunc) printfunc("Failed to load patch set %s.\n", file.c_str());
|
||||
}
|
||||
tok = strtok(NULL, delim);
|
||||
}
|
||||
free(wpatches);
|
||||
return count;
|
||||
}
|
||||
|
||||
|
@ -633,16 +396,6 @@ void FluidSynthMIDIDevice::ChangeSettingInt(const char *setting, int value)
|
|||
if (printfunc) printfunc("Setting polyphony to %d failed.\n", value);
|
||||
}
|
||||
}
|
||||
else if (strcmp(setting, "z.reverb-changed") == 0)
|
||||
{
|
||||
fluid_synth_set_reverb(FluidSynth, fluid_reverb_roomsize, fluid_reverb_damping,
|
||||
fluid_reverb_width, fluid_reverb_level);
|
||||
}
|
||||
else if (strcmp(setting, "z.chorus-changed") == 0)
|
||||
{
|
||||
fluid_synth_set_chorus(FluidSynth, fluid_chorus_voices, fluid_chorus_level,
|
||||
fluid_chorus_speed, fluid_chorus_depth, fluid_chorus_type);
|
||||
}
|
||||
else if (0 == fluid_settings_setint(FluidSettings, setting, value))
|
||||
{
|
||||
if (printfunc) printfunc("Failed to set %s to %d.\n", setting, value);
|
||||
|
@ -674,10 +427,59 @@ void FluidSynthMIDIDevice::ChangeSettingNum(const char *setting, double value)
|
|||
}
|
||||
setting += 11;
|
||||
|
||||
if (0 == fluid_settings_setnum(FluidSettings, setting, value))
|
||||
bool reverbchanged = false, choruschanged = false;
|
||||
if (strcmp(setting, "z.reverb-roomsize") == 0)
|
||||
{
|
||||
fluid_reverb_roomsize = (float)value;
|
||||
reverbchanged = true;
|
||||
}
|
||||
else if (strcmp(setting, "z.reverb-damping") == 0)
|
||||
{
|
||||
fluid_reverb_damping = (float)value;
|
||||
reverbchanged = true;
|
||||
}
|
||||
else if (strcmp(setting, "z.reverb-width") == 0)
|
||||
{
|
||||
fluid_reverb_width = (float)value;
|
||||
reverbchanged = true;
|
||||
}
|
||||
else if (strcmp(setting, "z.reverb-level") == 0)
|
||||
{
|
||||
fluid_reverb_level = (float)value;
|
||||
reverbchanged = true;
|
||||
}
|
||||
else if (strcmp(setting, "z.chorus-voices") == 0)
|
||||
{
|
||||
fluid_chorus_voices = (int)value;
|
||||
choruschanged = true;
|
||||
}
|
||||
else if (strcmp(setting, "z.chorus-level") == 0)
|
||||
{
|
||||
fluid_chorus_level = (float)value;
|
||||
choruschanged = true;
|
||||
}
|
||||
else if (strcmp(setting, "z.chorus-speed") == 0)
|
||||
{
|
||||
fluid_chorus_speed = (float)value;
|
||||
choruschanged = true;
|
||||
}
|
||||
else if (strcmp(setting, "z.chorus-depth") == 0)
|
||||
{
|
||||
fluid_chorus_depth = (float)value;
|
||||
choruschanged = true;
|
||||
}
|
||||
else if (strcmp(setting, "z.chorus-type") == 0)
|
||||
{
|
||||
fluid_chorus_type = (int)value;
|
||||
choruschanged = true;
|
||||
}
|
||||
else if (0 == fluid_settings_setnum(FluidSettings, setting, value))
|
||||
{
|
||||
if (printfunc) printfunc("Failed to set %s to %g.\n", setting, value);
|
||||
}
|
||||
if (reverbchanged) fluid_synth_set_reverb(FluidSynth, fluid_reverb_roomsize, fluid_reverb_damping, fluid_reverb_width, fluid_reverb_level);
|
||||
if (choruschanged) fluid_synth_set_chorus(FluidSynth, (int)fluid_chorus_voices, fluid_chorus_level, fluid_chorus_speed, fluid_chorus_depth, (int)fluid_chorus_type);
|
||||
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
|
@ -771,9 +573,9 @@ DYN_FLUID_SYM(fluid_synth_set_reverb);
|
|||
DYN_FLUID_SYM(fluid_synth_set_chorus);
|
||||
DYN_FLUID_SYM(fluid_synth_sysex);
|
||||
|
||||
bool FluidSynthMIDIDevice::LoadFluidSynth()
|
||||
bool FluidSynthMIDIDevice::LoadFluidSynth(const char *fluid_lib)
|
||||
{
|
||||
if (strlen(fluid_lib) > 0)
|
||||
if (fluid_lib && strlen(fluid_lib) > 0)
|
||||
{
|
||||
if(!FluidSynthModule.Load({fluid_lib}))
|
||||
{
|
||||
|
@ -819,7 +621,7 @@ void FluidSynthMIDIDevice::UnloadFluidSynth()
|
|||
//
|
||||
//==========================================================================
|
||||
|
||||
MIDIDevice *CreateFluidSynthMIDIDevice(const char *args, int samplerate, int (*printfunc)(const char*, ...))
|
||||
MIDIDevice *CreateFluidSynthMIDIDevice(int samplerate, FluidConfig *config, int (*printfunc)(const char*, ...))
|
||||
{
|
||||
return new FluidSynthMIDIDevice(args, samplerate, printfunc);
|
||||
return new FluidSynthMIDIDevice(samplerate, config, printfunc);
|
||||
}
|
||||
|
|
|
@ -29,19 +29,41 @@ struct MidiHeader
|
|||
|
||||
struct ADLConfig
|
||||
{
|
||||
const char * (*adl_full_path)(const char* filename);
|
||||
int adl_chips_count;
|
||||
int adl_emulator_id;
|
||||
int adl_bank;
|
||||
int adl_volume_model;
|
||||
bool adl_run_at_pcm_rate;
|
||||
bool adl_fullpan;
|
||||
bool adl_use_custom_bank;
|
||||
const char *adl_custom_bank;
|
||||
int adl_chips_count = 6;
|
||||
int adl_emulator_id = 0;
|
||||
int adl_bank = 14;
|
||||
int adl_volume_model = 3; // DMX
|
||||
bool adl_run_at_pcm_rate = 0;
|
||||
bool adl_fullpan = 1;
|
||||
bool adl_use_custom_bank = 0;
|
||||
const char *adl_custom_bank = nullptr;
|
||||
};
|
||||
|
||||
extern ADLConfig adlConfig;
|
||||
|
||||
struct FluidConfig
|
||||
{
|
||||
const char* fluid_lib = nullptr;
|
||||
std::vector<std::string> fluid_patchset;
|
||||
bool fluid_reverb = false;
|
||||
bool fluid_chorus = false;
|
||||
int fluid_voices = 128;
|
||||
int fluid_interp = 1;
|
||||
int fluid_samplerate = 0;
|
||||
int fluid_threads = 1;
|
||||
int fluid_chorus_voices = 3;
|
||||
int fluid_chorus_type = 0;
|
||||
float fluid_gain = 0.5f;
|
||||
float fluid_reverb_roomsize = 0.61f;
|
||||
float fluid_reverb_damping = 0.23f;
|
||||
float fluid_reverb_width = 0.76f;
|
||||
float fluid_reverb_level = 0.57f;
|
||||
float fluid_chorus_level = 1.2f;
|
||||
float fluid_chorus_speed = 0.3f;
|
||||
float fluid_chorus_depth = 8;
|
||||
};
|
||||
|
||||
extern FluidConfig fluidConfig;
|
||||
|
||||
class MIDIStreamer;
|
||||
|
||||
|
|
|
@ -50,12 +50,13 @@
|
|||
#ifdef _WIN32
|
||||
MIDIDevice *CreateWinMIDIDevice(int mididevice);
|
||||
#endif
|
||||
MIDIDevice *CreateFluidSynthMIDIDevice(const char *args, int samplerate, int (*printfunc_)(const char*, ...));
|
||||
MIDIDevice* CreateFluidSynthMIDIDevice(int samplerate, FluidConfig* config, int (*printfunc)(const char*, ...));
|
||||
MIDIDevice *CreateTimidityMIDIDevice(const char *args, int samplerate);
|
||||
MIDIDevice *CreateTimidityPPMIDIDevice(const char *args, int samplerate);
|
||||
MIDIDevice *CreateADLMIDIDevice(const char *args, const ADLConfig* config);
|
||||
MIDIDevice *CreateOPNMIDIDevice(const char *args);
|
||||
MIDIDevice *CreateWildMIDIDevice(const char *args, int samplerate);
|
||||
int BuildFluidPatchSetList(const char* patches, bool systemfallback);
|
||||
|
||||
// PUBLIC FUNCTION PROTOTYPES ----------------------------------------------
|
||||
|
||||
|
@ -227,7 +228,8 @@ MIDIDevice *MIDIStreamer::CreateMIDIDevice(EMidiDevice devtype, int samplerate)
|
|||
// Intentional fall-through for non-Windows systems.
|
||||
|
||||
case MDEV_FLUIDSYNTH:
|
||||
dev = CreateFluidSynthMIDIDevice(Args, samplerate, Printf);
|
||||
BuildFluidPatchSetList(Args, true);
|
||||
dev = CreateFluidSynthMIDIDevice(samplerate, &fluidConfig, Printf);
|
||||
break;
|
||||
|
||||
case MDEV_OPL:
|
||||
|
|
Loading…
Reference in a new issue