- first state of music configuration refactor.

This commit is contained in:
Christoph Oelckers 2019-09-29 20:01:57 +02:00
parent ab016be6b9
commit b7b57b904d
18 changed files with 1337 additions and 670 deletions

View file

@ -251,6 +251,13 @@ inline FILE* utf8_fopen(const char* filename, const char *mode)
}
inline bool fileExists(const char *fn)
{
FILE *f = utf8_fopen(fn, "rb");
if (!f) return false;
fclose(f);
return true;
}
//==========================================================================
//

View file

@ -42,18 +42,18 @@
namespace TimidityPlus
{
std::mutex ConfigMutex;
bool timidity_modulation_wheel = true;
bool timidity_portamento = false;
int timidity_modulation_wheel = true;
int timidity_portamento = false;
int timidity_reverb = 0;
int timidity_chorus = 0;
bool timidity_surround_chorus = false; // requires restart!
bool timidity_channel_pressure = false;
int timidity_surround_chorus = false; // requires restart!
int timidity_channel_pressure = false;
int timidity_lpf_def = true;
bool timidity_temper_control = true;
bool timidity_modulation_envelope = true;
bool timidity_overlap_voice_allow = true;
bool timidity_drum_effect = false;
bool timidity_pan_delay = false;
int timidity_temper_control = true;
int timidity_modulation_envelope = true;
int timidity_overlap_voice_allow = true;
int timidity_drum_effect = false;
int timidity_pan_delay = false;
float timidity_drum_power = 1.f;
int timidity_key_adjust = 0;
float timidity_tempo_adjust = 1.f;

View file

@ -126,18 +126,18 @@ namespace TimidityPlus
{
extern std::mutex ConfigMutex;
extern bool timidity_modulation_wheel;
extern bool timidity_portamento;
extern int timidity_modulation_wheel;
extern int timidity_portamento;
extern int timidity_reverb;
extern int timidity_chorus;
extern bool timidity_surround_chorus;
extern bool timidity_channel_pressure;
extern int timidity_surround_chorus;
extern int timidity_channel_pressure;
extern int timidity_lpf_de;
extern bool timidity_temper_control;
extern bool timidity_modulation_envelope;
extern bool timidity_overlap_voice_allow;
extern bool timidity_drum_effect;
extern bool timidity_pan_delay;
extern int timidity_temper_control;
extern int timidity_modulation_envelope;
extern int timidity_overlap_voice_allow;
extern int timidity_drum_effect;
extern int timidity_pan_delay;
extern float timidity_drum_power;
extern int timidity_key_adjust;
extern float timidity_tempo_adjust;

View file

@ -79,6 +79,7 @@ add_library( zmusic STATIC
decoder/sounddecoder.cpp
decoder/sndfile_decoder.cpp
decoder/mpg123_decoder.cpp
zmusic/configuration.cpp
${PLAT_WIN32_SOURCES}
)
target_link_libraries( zmusic )
@ -86,7 +87,7 @@ target_link_libraries( zmusic )
source_group("MIDI Devices" REGULAR_EXPRESSION "^${CMAKE_CURRENT_SOURCE_DIR}/mididevices/.+")
source_group("MIDI Sources" REGULAR_EXPRESSION "^${CMAKE_CURRENT_SOURCE_DIR}/midisources/.+")
source_group("MIDI Headers" REGULAR_EXPRESSION "^${CMAKE_CURRENT_SOURCE_DIR}/zmusic/.+")
source_group("Public Interface" REGULAR_EXPRESSION "^${CMAKE_CURRENT_SOURCE_DIR}/zmusic/.+")
source_group("Sound Decoding" REGULAR_EXPRESSION "^${CMAKE_CURRENT_SOURCE_DIR}/decoder/.+")
source_group("Stream Sources" REGULAR_EXPRESSION "^${CMAKE_CURRENT_SOURCE_DIR}/streamsources/.+")
source_group("Third Party" REGULAR_EXPRESSION "^${CMAKE_CURRENT_SOURCE_DIR}/thirdparty/.+")

View file

@ -146,8 +146,8 @@ protected:
// MIDI devices
MIDIDevice *CreateFluidSynthMIDIDevice(int samplerate, const FluidConfig* config, int (*printfunc)(const char*, ...));
MIDIDevice *CreateADLMIDIDevice(const ADLConfig* config);
MIDIDevice *CreateFluidSynthMIDIDevice(int samplerate, const char *Args);
MIDIDevice *CreateADLMIDIDevice(const char* args);
MIDIDevice *CreateOPNMIDIDevice(const OpnConfig *args);
MIDIDevice *CreateOplMIDIDevice(const OPLConfig* config);
MIDIDevice *CreateTimidityMIDIDevice(GUSConfig *config, int samplerate);
@ -155,6 +155,6 @@ MIDIDevice *CreateTimidityPPMIDIDevice(TimidityConfig *config, int samplerate);
MIDIDevice *CreateWildMIDIDevice(WildMidiConfig *config, int samplerate);
#ifdef _WIN32
MIDIDevice* CreateWinMIDIDevice(int mididevice, bool precache);
MIDIDevice* CreateWinMIDIDevice(int mididevice);
#endif

View file

@ -222,9 +222,45 @@ void ADLMIDIDevice::ComputeOutput(float *buffer, int len)
//
//==========================================================================
MIDIDevice *CreateADLMIDIDevice(const ADLConfig *config)
extern ADLConfig adlConfig;
MIDIDevice *CreateADLMIDIDevice(const char *Args)
{
return new ADLMIDIDevice(config);
ADLConfig config = adlConfig;
const char* bank = Args && *Args ? Args : adlConfig.adl_use_custom_bank ? adlConfig.adl_custom_bank.c_str() : nullptr;
if (bank && *bank)
{
if (*bank >= '0' && *bank <= '9')
{
// Args specify a bank by index.
int newbank = (int)strtoll(bank, nullptr, 10);
config.adl_use_custom_bank = false;
}
else
{
const char* info;
if (musicCallbacks.PathForSoundfont)
{
info = musicCallbacks.PathForSoundfont(bank, SF_WOPL);
}
else
{
info = bank;
}
if (info == nullptr)
{
config.adl_custom_bank = "";
config.adl_use_custom_bank = false;
}
else
{
config.adl_custom_bank = info;
config.adl_use_custom_bank = true;
}
}
}
return new ADLMIDIDevice(&config);
}

View file

@ -54,7 +54,7 @@ struct fluid_synth_t;
class FluidSynthMIDIDevice : public SoftSynthMIDIDevice
{
public:
FluidSynthMIDIDevice(int samplerate, const FluidConfig *config, int (*printfunc_)(const char *, ...));
FluidSynthMIDIDevice(int samplerate, std::vector<std::string> &config, int (*printfunc_)(const char *, ...));
~FluidSynthMIDIDevice();
int OpenRenderer();
@ -68,18 +68,12 @@ 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 FluidConfig *config);
int LoadPatchSets(const std::vector<std::string>& 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 };
static TReqProc<FluidSynthModule, fluid_settings_t *(*)()> new_fluid_settings;
@ -165,27 +159,16 @@ const char *BaseFileSearch(const char *file, const char *ext, bool lookfirstinpr
//
//==========================================================================
FluidSynthMIDIDevice::FluidSynthMIDIDevice(int samplerate, const FluidConfig *config, int (*printfunc_)(const char*, ...) = nullptr)
: SoftSynthMIDIDevice(samplerate <= 0? config->fluid_samplerate : samplerate, 22050, 96000)
FluidSynthMIDIDevice::FluidSynthMIDIDevice(int samplerate, std::vector<std::string> &config, int (*printfunc_)(const char*, ...) = nullptr)
: SoftSynthMIDIDevice(samplerate <= 0? fluidConfig.fluid_samplerate : samplerate, 22050, 96000)
{
StreamBlockSize = 4;
// 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
if (!LoadFluidSynth(config->fluid_lib.c_str()))
if (!LoadFluidSynth(fluidConfig.fluid_lib.c_str()))
{
throw std::runtime_error("Failed to load FluidSynth.\n");
}
@ -196,22 +179,22 @@ FluidSynthMIDIDevice::FluidSynthMIDIDevice(int samplerate, const FluidConfig *co
throw std::runtime_error("Failed to create FluidSettings.\n");
}
fluid_settings_setnum(FluidSettings, "synth.sample-rate", SampleRate);
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);
fluid_settings_setnum(FluidSettings, "synth.gain", fluidConfig.fluid_gain);
fluid_settings_setint(FluidSettings, "synth.reverb.active", fluidConfig.fluid_reverb);
fluid_settings_setint(FluidSettings, "synth.chorus.active", fluidConfig.fluid_chorus);
fluid_settings_setint(FluidSettings, "synth.polyphony", fluidConfig.fluid_voices);
fluid_settings_setint(FluidSettings, "synth.cpu-cores", fluidConfig.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, 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,
fluid_chorus_speed, fluid_chorus_depth, fluid_chorus_type);
fluid_synth_set_interp_method(FluidSynth, -1, fluidConfig.fluid_interp);
fluid_synth_set_reverb(FluidSynth, fluidConfig.fluid_reverb_roomsize, fluidConfig.fluid_reverb_damping,
fluidConfig.fluid_reverb_width, fluidConfig.fluid_reverb_level);
fluid_synth_set_chorus(FluidSynth, fluidConfig.fluid_chorus_voices, fluidConfig.fluid_chorus_level,
fluidConfig.fluid_chorus_speed, fluidConfig.fluid_chorus_depth, fluidConfig.fluid_chorus_type);
// try loading a patch set that got specified with $mididevice.
int res = 0;
@ -345,10 +328,10 @@ void FluidSynthMIDIDevice::ComputeOutput(float *buffer, int len)
//
//==========================================================================
int FluidSynthMIDIDevice::LoadPatchSets(const FluidConfig *config)
int FluidSynthMIDIDevice::LoadPatchSets(const std::vector<std::string> &config)
{
int count = 0;
for (auto& file : config->fluid_patchset)
for (auto& file : config)
{
if (FLUID_FAILED != fluid_synth_sfload(FluidSynth, file.c_str(), count == 0))
{
@ -424,58 +407,18 @@ void FluidSynthMIDIDevice::ChangeSettingNum(const char *setting, double value)
}
setting += 11;
bool reverbchanged = false, choruschanged = false;
if (strcmp(setting, "z.reverb-roomsize") == 0)
if (strcmp(setting, "z.reverb") == 0)
{
fluid_reverb_roomsize = (float)value;
reverbchanged = true;
fluid_synth_set_reverb(FluidSynth, fluidConfig.fluid_reverb_roomsize, fluidConfig.fluid_reverb_damping, fluidConfig.fluid_reverb_width, fluidConfig.fluid_reverb_level);
}
else if (strcmp(setting, "z.reverb-damping") == 0)
else if (strcmp(setting, "z.chorus") == 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;
fluid_synth_set_chorus(FluidSynth, fluidConfig.fluid_chorus_voices, fluidConfig.fluid_chorus_level, fluidConfig.fluid_chorus_speed, fluidConfig.fluid_chorus_depth, fluidConfig.fluid_chorus_type);
}
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);
}
@ -612,13 +555,118 @@ void FluidSynthMIDIDevice::UnloadFluidSynth()
#endif
//==========================================================================
//
// sndfile
//
//==========================================================================
#ifdef _WIN32
// do this without including windows.h for this one single prototype
extern "C" unsigned __stdcall GetSystemDirectoryA(char* lpBuffer, unsigned uSize);
#endif // _WIN32
void Fluid_SetupConfig(const char* patches, std::vector<std::string> &patch_paths, bool systemfallback)
{
//Resolve the paths here, the renderer will only get a final list of file names.
if (musicCallbacks.PathForSoundfont)
{
auto info = musicCallbacks.PathForSoundfont(patches, SF_SF2);
if (info) patches = info;
}
int count;
char* wpatches = strdup(patches);
char* tok;
#ifdef _WIN32
const char* const delim = ";";
#else
const char* const delim = ":";
#endif
if (wpatches != NULL)
{
tok = strtok(wpatches, delim);
count = 0;
while (tok != NULL)
{
std::string path;
#ifdef _WIN32
// If the path does not contain any path separators, automatically
// prepend $PROGDIR to the path.
if (strcspn(tok, ":/\\") == strlen(tok))
{
path = module_progdir + "/" + tok;
}
else
#endif
{
path = tok;
}
if (musicCallbacks.NicePath)
path = musicCallbacks.NicePath(path.c_str());
if (MusicIO::fileExists(path.c_str()))
{
patch_paths.push_back(path);
}
else
{
if (musicCallbacks.Fluid_MessageFunc)
musicCallbacks.Fluid_MessageFunc("Could not find patch set %s.\n", tok);
}
tok = strtok(NULL, delim);
}
free(wpatches);
if (patch_paths.size() > 0) return;
}
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.
Fluid_SetupConfig("/usr/share/sounds/sf2/FluidR3_GS.sf2:/usr/share/sounds/sf2/FluidR3_GM.sf2", patch_paths, false);
#endif
#ifdef _WIN32
// On Windows, look for the 4 megabyte patch set installed by Creative's drivers as a default.
char sysdir[260 + sizeof("\\CT4MGM.SF2")];
uint32_t filepart;
if (0 != (filepart = GetSystemDirectoryA(sysdir, 260)))
{
strcat(sysdir, "\\CT4MGM.SF2");
if (MusicIO::fileExists(sysdir))
{
patch_paths.push_back(sysdir);
return;
}
// Try again with CT2MGM.SF2
sysdir[filepart + 3] = '2';
if (MusicIO::fileExists(sysdir))
{
patch_paths.push_back(sysdir);
return;
}
}
#endif
}
}
//==========================================================================
//
//
//
//==========================================================================
MIDIDevice *CreateFluidSynthMIDIDevice(int samplerate, const FluidConfig *config, int (*printfunc)(const char*, ...))
MIDIDevice *CreateFluidSynthMIDIDevice(int samplerate, const char *Args)
{
return new FluidSynthMIDIDevice(samplerate, config, printfunc);
std::vector<std::string> fluid_patchset;
Fluid_SetupConfig(Args, fluid_patchset, true);
return new FluidSynthMIDIDevice(samplerate, fluid_patchset, musicCallbacks.Fluid_MessageFunc);
}

View file

@ -686,9 +686,9 @@ static bool IgnoreMIDIVolume(UINT id)
return false;
}
MIDIDevice *CreateWinMIDIDevice(int mididevice, bool precache)
MIDIDevice *CreateWinMIDIDevice(int mididevice)
{
return new WinMIDIDevice(mididevice, precache);
return new WinMIDIDevice(mididevice, miscConfig.snd_midiprecache);
}
#endif

View file

@ -0,0 +1,757 @@
/*
** configuration.cpp
** Handle zmusic's configuration.
**
**---------------------------------------------------------------------------
** Copyright 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 <algorithm>
#include "timidity/timidity.h"
#include "timiditypp/timidity.h"
#include "oplsynth/oplio.h"
#include "../../libraries/dumb/include/dumb.h"
#include "zmusic.h"
#include "midiconfig.h"
struct Dummy
{
void ChangeSettingInt(const char*, int) {}
void ChangeSettingNum(const char*, double) {}
void ChangeSettingString(const char*, const char*) {}
};
static Dummy* currSong;
//extern MusInfo *CurrSong;
int devType()
{
/*if (CurrSong) return CurrSong->GetDeviceType();
else*/ return MDEV_DEFAULT;
}
// Ordered by configurable device.
ADLConfig adlConfig;
FluidConfig fluidConfig;
OPLConfig oplConfig;
OpnConfig opnConfig;
GUSConfig gusConfig;
TimidityConfig timidityConfig;
WildMidiConfig wildMidiConfig;
DumbConfig dumbConfig;
MiscConfig miscConfig;
Callbacks musicCallbacks;
void SetCallbacks(const Callbacks* cb)
{
musicCallbacks = *cb;
}
template<class valtype>
void ChangeAndReturn(valtype &variable, valtype value, valtype *realv)
{
variable = value;
if (realv) *realv = value;
}
#define FLUID_CHORUS_MOD_SINE 0
#define FLUID_CHORUS_MOD_TRIANGLE 1
#define FLUID_CHORUS_DEFAULT_TYPE FLUID_CHORUS_MOD_SINE
//==========================================================================
//
// Timidity++ uses a static global set of configuration variables.
// THese can be changed live while the synth is playing but need synchronization.
//
// Currently the synth is not reentrant due to this and a handful
// of other global variables.
//
//==========================================================================
template<class T> void ChangeVarSync(T& var, T value)
{
std::lock_guard<std::mutex> lock(TimidityPlus::ConfigMutex);
var = value;
}
//==========================================================================
//
// Timidity++ reverb is a bit more complicated because it is two properties in one value.
//
//==========================================================================
/*
* reverb=0 no reverb 0
* reverb=1 old reverb 1
* reverb=1,n set reverb level to n (-1 to -127)
* reverb=2 "global" old reverb 2
* reverb=2,n set reverb level to n (-1 to -127) - 128
* reverb=3 new reverb 3
* reverb=3,n set reverb level to n (-1 to -127) - 256
* reverb=4 "global" new reverb 4
* reverb=4,n set reverb level to n (-1 to -127) - 384
*/
static int local_timidity_reverb_level;
static int local_timidity_reverb;
static void TimidityPlus_SetReverb()
{
int value = 0;
int mode = local_timidity_reverb;
int level = local_timidity_reverb_level;
if (mode == 0 || level == 0) value = mode;
else value = (mode - 1) * -128 - level;
ChangeVarSync(TimidityPlus::timidity_reverb, value);
}
using namespace ZMusic;
//==========================================================================
//
// change an integer value
//
//==========================================================================
bool ChangeMusicSetting(ZMusic::EIntConfigKey key, int value, int *pRealValue)
{
switch (key)
{
case adl_chips_count:
ChangeAndReturn(adlConfig.adl_chips_count, value, pRealValue);
return devType() == MDEV_ADL;
case adl_emulator_id:
ChangeAndReturn(adlConfig.adl_emulator_id, value, pRealValue);
return devType() == MDEV_ADL;
case adl_run_at_pcm_rate:
ChangeAndReturn(adlConfig.adl_run_at_pcm_rate, value, pRealValue);
return devType() == MDEV_ADL;
case adl_fullpan:
ChangeAndReturn(adlConfig.adl_fullpan, value, pRealValue);
return devType() == MDEV_ADL;
case adl_bank:
ChangeAndReturn(adlConfig.adl_bank, value, pRealValue);
return devType() == MDEV_ADL;
case adl_use_custom_bank:
ChangeAndReturn(adlConfig.adl_use_custom_bank, value, pRealValue);
return devType() == MDEV_ADL;
case adl_volume_model:
ChangeAndReturn(adlConfig.adl_volume_model, value, pRealValue);
return devType() == MDEV_ADL;
case fluid_reverb:
if (currSong != NULL)
currSong->ChangeSettingInt("fluidsynth.synth.reverb", value);
ChangeAndReturn(fluidConfig.fluid_reverb, value, pRealValue);
return false;
case fluid_chorus:
if (currSong != NULL)
currSong->ChangeSettingInt("fluidsynth.synth.chorus", value);
ChangeAndReturn(fluidConfig.fluid_chorus, value, pRealValue);
return false;
case fluid_voices:
if (value < 16)
value = 16;
else if (value > 4096)
value = 4096;
if (currSong != NULL)
currSong->ChangeSettingInt("fluidsynth.synth.polyphony", value);
ChangeAndReturn(fluidConfig.fluid_voices, value, pRealValue);
return false;
case fluid_interp:
// 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 (value < 0)
value = 0;
else if (value == 2)
value = 1;
else if (value == 3 || value == 5)
value = 4;
else if (value == 6 || value > 7)
value = 7;
if (currSong != NULL)
currSong->ChangeSettingInt("fluidsynth.synth.interpolation", value);
ChangeAndReturn(fluidConfig.fluid_interp, value, pRealValue);
return false;
case fluid_samplerate:
// This will only take effect for the next song. (Q: Is this even needed?)
ChangeAndReturn(fluidConfig.fluid_samplerate, std::max<int>(value, 0), pRealValue);
return false;
// I don't know if this setting even matters for us, since we aren't letting
// FluidSynth drives its own output.
case fluid_threads:
if (value < 1)
value = 1;
else if (value > 256)
value = 256;
ChangeAndReturn(fluidConfig.fluid_threads, value, pRealValue);
return false;
case fluid_chorus_voices:
if (value < 0)
value = 0;
else if (value > 99)
value = 99;
if (currSong != NULL)
currSong->ChangeSettingNum("fluidsynth.z.chorus", value);
ChangeAndReturn(fluidConfig.fluid_chorus_voices, value, pRealValue);
return false;
case fluid_chorus_type:
if (value != FLUID_CHORUS_MOD_SINE && value != FLUID_CHORUS_MOD_TRIANGLE)
value = FLUID_CHORUS_DEFAULT_TYPE;
if (currSong != NULL)
currSong->ChangeSettingNum("fluidsynth.z.chorus", value); // Uses float to simplify the checking code in the renderer.
ChangeAndReturn(fluidConfig.fluid_chorus_type, value, pRealValue);
return false;
case opl_numchips:
if (value <= 0)
value = 1;
else if (value > MAXOPL2CHIPS)
value = MAXOPL2CHIPS;
if (currSong != NULL)
currSong->ChangeSettingInt("opl.numchips", value);
ChangeAndReturn(oplConfig.numchips, value, pRealValue);
return false;
case opl_core:
ChangeAndReturn(oplConfig.core, value, pRealValue);
return devType() == MDEV_OPL;
case opl_fullpan:
ChangeAndReturn(oplConfig.fullpan, value, pRealValue);
return false;
case opn_chips_count:
ChangeAndReturn(opnConfig.opn_chips_count, value, pRealValue);
return devType() == MDEV_OPN;
case opn_emulator_id:
ChangeAndReturn(opnConfig.opn_emulator_id, value, pRealValue);
return devType() == MDEV_OPN;
case opn_run_at_pcm_rate:
ChangeAndReturn(opnConfig.opn_run_at_pcm_rate, value, pRealValue);
return devType() == MDEV_OPN;
case opn_fullpan:
ChangeAndReturn(opnConfig.opn_fullpan, value, pRealValue);
return devType() == MDEV_OPN;
case opn_use_custom_bank:
ChangeAndReturn(opnConfig.opn_use_custom_bank, value, pRealValue);
return devType() == MDEV_OPN;
case gus_dmxgus:
ChangeAndReturn(gusConfig.gus_dmxgus, value, pRealValue);
return devType() == MDEV_GUS;
case gus_midi_voices:
ChangeAndReturn(gusConfig.midi_voices, value, pRealValue);
return devType() == MDEV_GUS;
case gus_memsize:
ChangeAndReturn(gusConfig.gus_memsize, value, pRealValue);
return devType() == MDEV_GUS && gusConfig.gus_dmxgus;
case timidity_modulation_wheel:
ChangeVarSync(TimidityPlus::timidity_modulation_wheel, value);
if (pRealValue) *pRealValue = value;
return false;
case timidity_portamento:
ChangeVarSync(TimidityPlus::timidity_portamento, value);
if (pRealValue) *pRealValue = value;
return false;
case timidity_reverb:
if (value < 0 || value > 4) value = 0;
else TimidityPlus_SetReverb();
local_timidity_reverb = value;
if (pRealValue) *pRealValue = value;
return false;
case timidity_reverb_level:
if (value < 0 || value > 127) value = 0;
else TimidityPlus_SetReverb();
local_timidity_reverb_level = value;
if (pRealValue) *pRealValue = value;
return false;
case timidity_chorus:
ChangeVarSync(TimidityPlus::timidity_chorus, value);
if (pRealValue) *pRealValue = value;
return false;
case timidity_surround_chorus:
ChangeVarSync(TimidityPlus::timidity_surround_chorus, value);
if (pRealValue) *pRealValue = value;
return devType() == MDEV_TIMIDITY;
case timidity_channel_pressure:
ChangeVarSync(TimidityPlus::timidity_channel_pressure, value);
if (pRealValue) *pRealValue = value;
return false;
case timidity_lpf_def:
ChangeVarSync(TimidityPlus::timidity_lpf_def, value);
if (pRealValue) *pRealValue = value;
return false;
case timidity_temper_control:
ChangeVarSync(TimidityPlus::timidity_temper_control, value);
if (pRealValue) *pRealValue = value;
return false;
case timidity_modulation_envelope:
ChangeVarSync(TimidityPlus::timidity_modulation_envelope, value);
if (pRealValue) *pRealValue = value;
return devType() == MDEV_TIMIDITY;
case timidity_overlap_voice_allow:
ChangeVarSync(TimidityPlus::timidity_overlap_voice_allow, value);
if (pRealValue) *pRealValue = value;
return false;
case timidity_drum_effect:
ChangeVarSync(TimidityPlus::timidity_drum_effect, value);
if (pRealValue) *pRealValue = value;
return false;
case timidity_pan_delay:
ChangeVarSync(TimidityPlus::timidity_pan_delay, value);
if (pRealValue) *pRealValue = value;
return false;
case timidity_key_adjust:
if (value < -24) value = -24;
else if (value > 24) value = 24;
ChangeVarSync(TimidityPlus::timidity_key_adjust, value);
if (pRealValue) *pRealValue = value;
return false;
case wildmidi_reverb:
if (currSong != NULL)
currSong->ChangeSettingInt("wildmidi.reverb", value);
wildMidiConfig.reverb = value;
if (pRealValue) *pRealValue = value;
return false;
case wildmidi_enhanced_resampling:
if (currSong != NULL)
currSong->ChangeSettingInt("wildmidi.resampling", value);
wildMidiConfig.enhanced_resampling = value;
if (pRealValue) *pRealValue = value;
return false;
case snd_midiprecache:
ChangeAndReturn(miscConfig.snd_midiprecache, value, pRealValue);
return false;
case snd_streambuffersize:
if (value < 16)
{
value = 16;
}
else if (value > 1024)
{
value = 1024;
}
ChangeAndReturn(miscConfig.snd_streambuffersize, value, pRealValue);
return false;
case mod_samplerate:
ChangeAndReturn(dumbConfig.mod_samplerate, value, pRealValue);
return false;
case mod_volramp:
ChangeAndReturn(dumbConfig.mod_volramp, value, pRealValue);
return false;
case mod_interp:
ChangeAndReturn(dumbConfig.mod_interp, value, pRealValue);
return false;
case mod_autochip:
ChangeAndReturn(dumbConfig.mod_autochip, value, pRealValue);
return false;
case mod_autochip_size_force:
ChangeAndReturn(dumbConfig.mod_autochip_size_force, value, pRealValue);
return false;
case mod_autochip_size_scan:
ChangeAndReturn(dumbConfig.mod_autochip_size_scan, value, pRealValue);
return false;
case mod_autochip_scan_threshold:
ChangeAndReturn(dumbConfig.mod_autochip_scan_threshold, value, pRealValue);
return false;
}
return false;
}
bool ChangeMusicSetting(ZMusic::EFloatConfigKey key, float value, float *pRealValue)
{
switch (key)
{
case fluid_gain:
if (value < 0)
value = 0;
else if (value > 10)
value = 10;
if (currSong != NULL)
currSong->ChangeSettingNum("fluidsynth.synth.gain", value);
ChangeAndReturn(fluidConfig.fluid_gain, value, pRealValue);
return false;
case fluid_reverb_roomsize:
if (value < 0)
value = 0;
else if (value > 1.2f)
value = 1.2f;
if (currSong != NULL)
currSong->ChangeSettingNum("fluidsynth.z.reverb", value);
ChangeAndReturn(fluidConfig.fluid_reverb_roomsize, value, pRealValue);
return false;
case fluid_reverb_damping:
if (value < 0)
value = 0;
else if (value > 1)
value = 1;
if (currSong != NULL)
currSong->ChangeSettingNum("fluidsynth.z.reverb", value);
ChangeAndReturn(fluidConfig.fluid_reverb_damping, value, pRealValue);
return false;
case fluid_reverb_width:
if (value < 0)
value = 0;
else if (value > 100)
value = 100;
if (currSong != NULL)
currSong->ChangeSettingNum("fluidsynth.z.reverb", value);
ChangeAndReturn(fluidConfig.fluid_reverb_width, value, pRealValue);
return false;
case fluid_reverb_level:
if (value < 0)
value = 0;
else if (value > 1)
value = 1;
if (currSong != NULL)
currSong->ChangeSettingNum("fluidsynth.z.reverb", value);
ChangeAndReturn(fluidConfig.fluid_reverb_level, value, pRealValue);
return false;
case fluid_chorus_level:
if (value < 0)
value = 0;
else if (value > 1)
value = 1;
if (currSong != NULL)
currSong->ChangeSettingNum("fluidsynth.z.chorus", value);
ChangeAndReturn(fluidConfig.fluid_chorus_level, value, pRealValue);
return false;
case fluid_chorus_speed:
if (value < 0.29f)
value = 0.29f;
else if (value > 5)
value = 5;
if (currSong != NULL)
currSong->ChangeSettingNum("fluidsynth.z.chorus", value);
ChangeAndReturn(fluidConfig.fluid_chorus_speed, value, pRealValue);
return false;
// depth is in ms and actual maximum depends on the sample rate
case fluid_chorus_depth:
if (value < 0)
value = 0;
else if (value > 21)
value = 21;
if (currSong != NULL)
currSong->ChangeSettingNum("fluidsynth.z.chorus", value);
ChangeAndReturn(fluidConfig.fluid_chorus_depth, value, pRealValue);
return false;
case timidity_drum_power:
if (value < 0) value = 0;
else if (value > MAX_AMPLIFICATION / 100.f) value = MAX_AMPLIFICATION / 100.f;
ChangeVarSync(TimidityPlus::timidity_drum_power, value);
if (pRealValue) *pRealValue = value;
return false;
// For testing mainly.
case timidity_tempo_adjust:
if (value < 0.25) value = 0.25;
else if (value > 10) value = 10;
ChangeVarSync(TimidityPlus::timidity_tempo_adjust, value);
if (pRealValue) *pRealValue = value;
return false;
case min_sustain_time:
if (value < 0) value = 0;
ChangeVarSync(TimidityPlus::min_sustain_time, value);
if (pRealValue) *pRealValue = value;
return false;
case gme_stereodepth:
if (currSong != nullptr)
currSong->ChangeSettingNum("GME.stereodepth", value);
ChangeAndReturn(miscConfig.gme_stereodepth, value, pRealValue);
return false;
case mod_dumb_mastervolume:
if (value < 0) value = 0;
ChangeAndReturn(dumbConfig.mod_dumb_mastervolume, value, pRealValue);
return false;
}
return false;
}
bool ChangeMusicSetting(ZMusic::EStringConfigKey key, const char *value)
{
switch (key)
{
case adl_custom_bank:
adlConfig.adl_custom_bank = value;
return devType() == MDEV_ADL;
case fluid_lib:
fluidConfig.fluid_lib = value;
return false; // only takes effect for next song.
case fluid_patchset:
fluidConfig.fluid_patchset = value;
return devType() == MDEV_FLUIDSYNTH;
case opn_custom_bank:
opnConfig.opn_custom_bank = value;
return devType() == MDEV_OPN && opnConfig.opn_use_custom_bank;
case gus_config:
gusConfig.gus_config = value;
return devType() == MDEV_GUS;
case gus_patchdir:
gusConfig.gus_patchdir = value;
return devType() == MDEV_GUS && gusConfig.gus_dmxgus;
case timidity_config:
timidityConfig.timidity_config = value;
return devType() == MDEV_TIMIDITY;
case wildmidi_config:
wildMidiConfig.config = value;
return devType() == MDEV_TIMIDITY;
}
return false;
}
#if 0
void OPL_SetupConfig(OPLConfig *config, const char *args, bool midi)
{
// This needs to be done only once.
if (!config->genmidiset && midi)
{
// The OPL renderer should not care about where this comes from.
// Note: No I_Error here - this needs to be consistent with the rest of the music code.
auto lump = Wads.CheckNumForName("GENMIDI", ns_global);
if (lump < 0) throw std::runtime_error("No GENMIDI lump found");
auto data = Wads.OpenLumpReader(lump);
uint8_t filehdr[8];
data.Read(filehdr, 8);
if (memcmp(filehdr, "#OPL_II#", 8)) throw std::runtime_error("Corrupt GENMIDI lump");
data.Read(oplConfig.OPLinstruments, 175 * 36);
config->genmidiset = true;
}
config->core = opl_core;
if (args != NULL && *args >= '0' && *args < '4') config->core = *args - '0';
}
void OPN_SetupConfig(OpnConfig *config, const char *Args)
{
//Resolve the path here, so that the renderer does not have to do the work itself and only needs to process final names.
const char *bank = Args && *Args? Args : opn_use_custom_bank? *opn_custom_bank : nullptr;
if (bank && *bank)
{
auto info = sfmanager.FindSoundFont(bank, SF_WOPN);
if (info == nullptr)
{
config->opn_custom_bank = "";
}
else
{
config->opn_custom_bank = info->mFilename;
}
}
int lump = Wads.CheckNumForFullName("xg.wopn");
if (lump < 0)
{
config->default_bank.resize(0);
return;
}
FMemLump data = Wads.ReadLump(lump);
config->default_bank.resize(data.GetSize());
memcpy(config->default_bank.data(), data.GetMem(), data.GetSize());
}
//==========================================================================
//
// Sets up the date to load the instruments for the GUS device.
// The actual instrument loader is part of the device.
//
//==========================================================================
bool GUS_SetupConfig(GUSConfig *config, const char *args)
{
config->errorfunc = gus_printfunc;
if ((midi_dmxgus && *args == 0) || !stricmp(args, "DMXGUS"))
{
if (stricmp(config->loadedConfig.c_str(), "DMXGUS") == 0) return false; // aleady loaded
int lump = Wads.CheckNumForName("DMXGUS");
if (lump == -1) lump = Wads.CheckNumForName("DMXGUSC");
if (lump >= 0)
{
auto data = Wads.OpenLumpReader(lump);
if (data.GetLength() > 0)
{
config->dmxgus.resize(data.GetLength());
data.Read(config->dmxgus.data(), data.GetLength());
return true;
}
}
}
if (*args == 0) args = midi_config;
if (stricmp(config->loadedConfig.c_str(), args) == 0) return false; // aleady loaded
auto reader = sfmanager.OpenSoundFont(args, SF_GUS | SF_SF2);
if (reader == nullptr)
{
char error[80];
snprintf(error, 80, "GUS: %s: Unable to load sound font\n",args);
throw std::runtime_error(error);
}
config->reader = reader;
config->readerName = args;
return true;
}
bool Timidity_SetupConfig(TimidityConfig* config, const char* args)
{
config->errorfunc = gus_printfunc;
if (*args == 0) args = timidity_config;
if (stricmp(config->loadedConfig.c_str(), args) == 0) return false; // aleady loaded
auto reader = sfmanager.OpenSoundFont(args, SF_GUS | SF_SF2);
if (reader == nullptr)
{
char error[80];
snprintf(error, 80, "Timidity++: %s: Unable to load sound font\n", args);
throw std::runtime_error(error);
}
config->reader = reader;
config->readerName = args;
return true;
}
bool WildMidi_SetupConfig(WildMidiConfig* config, const char* args)
{
config->errorfunc = wm_printfunc;
if (*args == 0) args = wildmidi_config;
if (stricmp(config->loadedConfig.c_str(), args) == 0) return false; // aleady loaded
auto reader = sfmanager.OpenSoundFont(args, SF_GUS);
if (reader == nullptr)
{
char error[80];
snprintf(error, 80, "WildMidi: %s: Unable to load sound font\n", args);
throw std::runtime_error(error);
}
config->reader = reader;
config->readerName = args;
config->reverb = wildmidi_reverb;
config->enhanced_resampling = wildmidi_enhanced_resampling;
return true;
}
#endif

View file

@ -3,25 +3,29 @@
#include <string>
#include <vector>
#include <memory>
#include "zmusic.h"
#include "../../libraries/music_common/fileio.h"
// Note: Bools here are stored as ints to allow having a simpler interface.
struct ADLConfig
{
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;
int adl_run_at_pcm_rate = 0;
int adl_fullpan = 1;
int adl_use_custom_bank = false;
std::string adl_custom_bank;
};
struct FluidConfig
{
std::string fluid_lib;
std::vector<std::string> fluid_patchset;
bool fluid_reverb = false;
bool fluid_chorus = false;
std::string fluid_patchset;
int fluid_reverb = false;
int fluid_chorus = false;
int fluid_voices = 128;
int fluid_interp = 1;
int fluid_samplerate = 0;
@ -42,8 +46,8 @@ struct OPLConfig
{
int numchips = 2;
int core = 0;
bool fullpan = true;
bool genmidiset = false;
int fullpan = true;
int genmidiset = false;
uint8_t OPLinstruments[36 * 175]; // it really is 'struct GenMidiInstrument OPLinstruments[GENMIDI_NUM_TOTAL]'; but since this is a public header it cannot pull in a dependency from oplsynth.
};
@ -51,8 +55,9 @@ struct OpnConfig
{
int opn_chips_count = 8;
int opn_emulator_id = 0;
bool opn_run_at_pcm_rate = false;
bool opn_fullpan = 1;
int opn_run_at_pcm_rate = false;
int opn_fullpan = 1;
int opn_use_custom_bank = false;
std::string opn_custom_bank;
std::vector<uint8_t> default_bank;
};
@ -65,19 +70,16 @@ namespace Timidity
struct GUSConfig
{
// This one is a bit more complex because it also implements the instrument cache.
int midi_voices = 32;
int gus_memsize = 0;
void (*errorfunc)(int type, int verbosity_level, const char* fmt, ...) = nullptr;
int gus_dmxgus = false;
std::string gus_patchdir;
std::string gus_config;
std::vector<uint8_t> dmxgus; // can contain the contents of a DMXGUS lump that may be used as the instrument set. In this case gus_patchdir must point to the location of the GUS data and gus_dmxgus must be true.
// This is the instrument cache for the GUS synth.
MusicIO::SoundFontReaderInterface *reader;
std::string readerName;
std::vector<uint8_t> dmxgus; // can contain the contents of a DMXGUS lump that may be used as the instrument set. In this case gus_patchdir must point to the location of the GUS data.
std::string gus_patchdir;
// These next two fields are for caching the instruments for repeated use. The GUS device will work without them being cached in the config but it'd require reloading the instruments each time.
// Thus, this config should always be stored globally to avoid this.
// If the last loaded instrument set is to be reused or the caller wants to manage them itself, both 'reader' and 'dmxgus' fields should be left empty.
std::string loadedConfig;
std::shared_ptr<Timidity::Instruments> instruments; // this is held both by the config and the device
};
@ -90,14 +92,10 @@ namespace TimidityPlus
struct TimidityConfig
{
void (*errorfunc)(int type, int verbosity_level, const char* fmt, ...) = nullptr;
std::string timidity_config;
MusicIO::SoundFontReaderInterface* reader;
std::string readerName;
// These next two fields are for caching the instruments for repeated use. The GUS device will work without them being cached in the config but it'd require reloading the instruments each time.
// Thus, this config should always be stored globally to avoid this.
// If the last loaded instrument set is to be reused or the caller wants to manage them itself, 'reader' should be left empty.
std::string loadedConfig;
std::shared_ptr<TimidityPlus::Instruments> instruments; // this is held both by the config and the device
@ -113,26 +111,21 @@ struct WildMidiConfig
{
bool reverb = false;
bool enhanced_resampling = true;
void (*errorfunc)(const char* wmfmt, va_list args) = nullptr;
std::string config;
MusicIO::SoundFontReaderInterface* reader;
std::string readerName;
// These next two fields are for caching the instruments for repeated use. The GUS device will work without them being cached in the config but it'd require reloading the instruments each time.
// Thus, this config should always be stored globally to avoid this.
// If the last loaded instrument set is to be reused or the caller wants to manage them itself, 'reader' should be left empty.
std::string loadedConfig;
std::shared_ptr<WildMidi::Instruments> instruments; // this is held both by the config and the device
};
struct DumbConfig
{
int mod_samplerate;
int mod_volramp;
int mod_interp;
bool mod_autochip;
int mod_autochip;
int mod_autochip_size_force;
int mod_autochip_size_scan;
int mod_autochip_scan_threshold;
@ -141,116 +134,21 @@ struct DumbConfig
// The rest is not used yet.
struct misc
struct MiscConfig
{
bool snd_midiprecache;
int snd_midiprecache;
float gme_stereodepth;
int snd_streambuffersize;
};
extern ADLConfig adlConfig;
extern FluidConfig fluidConfig;
extern OPLConfig oplConfig;
extern OpnConfig opnConfig;
extern GUSConfig gusConfig;
extern TimidityConfig timidityConfig;
extern WildMidiConfig wildMidiConfig;
extern DumbConfig dumbConfig;
extern MiscConfig miscConfig;
extern Callbacks musicCallbacks;
namespace ZMusic
{
enum EZMusicIntConfigKey
{
adl_chips_count,
adl_emulator_id,
adl_run_at_pcm_rate,
adl_fullpan,
adl_bank,
adl_use_custom_bank,
adl_volume_model,
fluid_reverb,
fluid_chorus,
fluid_voices,
fluid_interp,
fluid_samplerate,
fluid_threads,
fluid_chorus_voices,
fluid_chorus_type,
opl_numchips,
opl_core,
opl_fullpan,
opn_chips_count,
opn_emulator_id,
opn_run_at_pcm_rate,
opn_fullpan,
opn_use_custom_bank,
midi_dmxgus,
midi_voices,
gus_memsize,
timidity_modulation_wheel,
timidity_portamento,
timidity_reverb,
timidity_reverb_level,
timidity_chorus,
timidity_surround_chorus,
timidity_channel_pressure,
timidity_lpf_def,
timidity_temper_control,
timidity_modulation_envelope,
timidity_overlap_voice_allow,
timidity_drum_effect,
timidity_pan_delay,
timidity_key_adjust,
wildmidi_reverb,
wildmidi_enhanced_resampling,
snd_midiprecache,
mod_samplerate,
mod_volramp,
mod_interp,
mod_autochip,
mod_autochip_size_force,
mod_autochip_size_scan,
mod_autochip_scan_threshold,
snd_streambuffersize,
NUM_INT_CONFIGS
};
enum EZMusicFloatConfigKey
{
fluid_gain,
fluid_reverb_roomsize,
fluid_reverb_damping,
fluid_reverb_width,
fluid_reverb_level,
fluid_chorus_level,
fluid_chorus_speed,
fluid_chorus_depth,
timidity_drum_power,
timidity_tempo_adjust,
min_sustain_time,
gme_stereodepth,
mod_dumb_mastervolume,
NUM_FLOAT_CONFIGS
};
enum EMusicStringConfigKey
{
adl_custom_bank,
fluid_lib,
fluid_patchset,
opn_custom_bank,
midi_config,
gus_patchdir,
timidity_config,
wildmidi_config,
NUM_STRING_CONFIGS
};
}

View file

@ -56,6 +56,15 @@ enum EMidiDevice
MDEV_COUNT
};
enum ESoundFontTypes
{
SF_SF2 = 1,
SF_GUS = 2,
SF_WOPL = 4,
SF_WOPN = 8
};
struct SoundStreamInfo
{
int mBufferSize; // If mBufferSize is 0, the song doesn't use streaming but plays through a different interface.

View file

@ -2,7 +2,140 @@
#include "mididefs.h"
namespace ZMusic // Namespaced because these conflict with the same-named CVARs
{
enum EIntConfigKey
{
adl_chips_count,
adl_emulator_id,
adl_run_at_pcm_rate,
adl_fullpan,
adl_bank,
adl_use_custom_bank,
adl_volume_model,
fluid_reverb,
fluid_chorus,
fluid_voices,
fluid_interp,
fluid_samplerate,
fluid_threads,
fluid_chorus_voices,
fluid_chorus_type,
opl_numchips,
opl_core,
opl_fullpan,
opn_chips_count,
opn_emulator_id,
opn_run_at_pcm_rate,
opn_fullpan,
opn_use_custom_bank,
gus_dmxgus,
gus_midi_voices,
gus_memsize,
timidity_modulation_wheel,
timidity_portamento,
timidity_reverb,
timidity_reverb_level,
timidity_chorus,
timidity_surround_chorus,
timidity_channel_pressure,
timidity_lpf_def,
timidity_temper_control,
timidity_modulation_envelope,
timidity_overlap_voice_allow,
timidity_drum_effect,
timidity_pan_delay,
timidity_key_adjust,
wildmidi_reverb,
wildmidi_enhanced_resampling,
snd_midiprecache,
mod_samplerate,
mod_volramp,
mod_interp,
mod_autochip,
mod_autochip_size_force,
mod_autochip_size_scan,
mod_autochip_scan_threshold,
snd_streambuffersize,
NUM_INT_CONFIGS
};
enum EFloatConfigKey
{
fluid_gain,
fluid_reverb_roomsize,
fluid_reverb_damping,
fluid_reverb_width,
fluid_reverb_level,
fluid_chorus_level,
fluid_chorus_speed,
fluid_chorus_depth,
timidity_drum_power,
timidity_tempo_adjust,
min_sustain_time,
gme_stereodepth,
mod_dumb_mastervolume,
NUM_FLOAT_CONFIGS
};
enum EStringConfigKey
{
adl_custom_bank,
fluid_lib,
fluid_patchset,
opn_custom_bank,
gus_config,
gus_patchdir,
timidity_config,
wildmidi_config,
NUM_STRING_CONFIGS
};
}
struct Callbacks
{
// Callbacks the client can install to capture messages from the backends
// or to provide sound font data.
// The message callbacks are optional, without them the output goes to stdout.
void (*WildMidi_MessageFunc)(const char* wmfmt, va_list args) = nullptr;
void (*GUS_MessageFunc)(int type, int verbosity_level, const char* fmt, ...) = nullptr;
void (*Timidity_Messagefunc)(int type, int verbosity_level, const char* fmt, ...) = nullptr;
int (*Fluid_MessageFunc)(const char *fmt, ...) = nullptr;
// The sound font callbacks are for allowing the client to customize sound font management
// Without them only paths to real files can be used.
const char *(*PathForSoundfont)(const char *name, int type) = nullptr;
// Used to handle client-specific path macros. If not set, the path may not contain any special tokens that may need expansion.
std::string (*NicePath)(const char *path) = nullptr;
};
void SetCallbacks(const Callbacks *callbacks);
// These exports is needed by the MIDI dumpers which need to remain on the client side.
class MIDISource; // abstract for the client
EMIDIType IdentifyMIDIType(uint32_t *id, int size);
MIDISource *CreateMIDISource(const uint8_t *data, size_t length, EMIDIType miditype);
// Configuration interface. The return value specifies if a music restart is needed.
// RealValue should be written back to the CVAR or whatever other method the client uses to store configuration state.
bool ChangeMusicSetting(ZMusic::EIntConfigKey key, int value, int *pRealValue = nullptr);
bool ChangeMusicSetting(ZMusic::EFloatConfigKey key, float value, float *pRealValue = nullptr);
bool ChangeMusicSetting(ZMusic::EStringConfigKey key, const char *value);

View file

@ -45,7 +45,10 @@
#include "c_dispatch.h"
#include "templates.h"
#include "stats.h"
#include "c_console.h"
#include "vm.h"
#include "v_text.h"
#include "i_soundfont.h"
#include "s_music.h"
#include "zmusic/zmusic.h"
#include "streamsources/streamsource.h"
@ -127,6 +130,56 @@ CUSTOM_CVAR (Float, snd_musicvolume, 0.5f, CVAR_ARCHIVE|CVAR_GLOBALCONFIG)
}
}
//==========================================================================
//
// Callbacks for the music system.
//
//==========================================================================
static void tim_printfunc(int type, int verbosity_level, const char* fmt, ...)
{
if (verbosity_level >= 3/*Timidity::VERB_DEBUG*/) return; // Don't waste time on diagnostics.
va_list args;
va_start(args, fmt);
FString msg;
msg.VFormat(fmt, args);
va_end(args);
switch (type)
{
case 2:// Timidity::CMSG_ERROR:
Printf(TEXTCOLOR_RED "%s\n", msg.GetChars());
break;
case 1://Timidity::CMSG_WARNING:
Printf(TEXTCOLOR_YELLOW "%s\n", msg.GetChars());
break;
case 0://Timidity::CMSG_INFO:
DPrintf(DMSG_SPAMMY, "%s\n", msg.GetChars());
break;
}
}
static void wm_printfunc(const char* wmfmt, va_list args)
{
Printf(TEXTCOLOR_RED);
VPrintf(PRINT_HIGH, wmfmt, args);
}
static std::string mus_NicePath(const char* str)
{
FString strv = NicePath(str);
return strv.GetChars();
}
static const char* mus_pathToSoundFont(const char* sfname, int type)
{
auto info = sfmanager.FindSoundFont(sfname, type);
return info ? info->mFilename.GetChars() : nullptr;
}
//==========================================================================
//
//
@ -147,6 +200,15 @@ void I_InitMusic (void)
MusicDown = false;
dumb_decode_vorbis = dumb_decode_vorbis_;
Callbacks callbacks;
callbacks.Fluid_MessageFunc = Printf;
callbacks.GUS_MessageFunc = callbacks.Timidity_Messagefunc = tim_printfunc;
callbacks.WildMidi_MessageFunc = wm_printfunc;
callbacks.NicePath = mus_NicePath;
callbacks.PathForSoundfont = mus_pathToSoundFont;
SetCallbacks(&callbacks);
}

View file

@ -19,7 +19,6 @@ class MIDIDevice;
class OPLmusicFile;
extern ADLConfig adlConfig;
extern FluidConfig fluidConfig;
extern OPLConfig oplConfig;
extern OpnConfig opnConfig;

View file

@ -40,6 +40,7 @@
#include "i_system.h"
#include "gameconfigfile.h"
#include "filereadermusicinterface.h"
#include "zmusic/zmusic.h"
#include "resourcefiles/resourcefile.h"
#include "../libraries/timidityplus/timiditypp/common.h"

View file

@ -5,14 +5,6 @@
#include "files.h"
#include "filereadermusicinterface.h"
enum
{
SF_SF2 = 1,
SF_GUS = 2,
SF_WOPL = 4,
SF_WOPN = 8
};
struct FSoundFontInfo
{
FString mName; // This is what the sounfont is identified with. It's the extension-less base file name

View file

@ -1,7 +1,7 @@
/*
** music_config.cpp
** All game side configuration settings for the various parts of the
** music system
** This forwards all CVAR changes to the music system which
** was designed for any kind of configuration system.
**
**---------------------------------------------------------------------------
** Copyright 1999-2016 Randy Heit
@ -39,7 +39,9 @@
#include "doomerrors.h"
#include "v_text.h"
#include "c_console.h"
#include "zmusic/zmusic.h"
#include "zmusic/midiconfig.h"
#include "../libraries/timidity/timidity/timidity.h"
#include "../libraries/timidityplus/timiditypp/timidity.h"
#include "../libraries/oplsynth/oplsynth/oplio.h"
@ -58,89 +60,67 @@ static void CheckRestart(int devtype)
}
}
ADLConfig adlConfig;
FluidConfig fluidConfig;
OPLConfig oplConfig;
OpnConfig opnConfig;
GUSConfig gusConfig;
TimidityConfig timidityConfig;
WildMidiConfig wildMidiConfig;
DumbConfig dumbConfig;
//==========================================================================
//
// ADL Midi device
//
//==========================================================================
CUSTOM_CVAR(Int, adl_chips_count, 6, CVAR_ARCHIVE | CVAR_GLOBALCONFIG)
#define FORWARD_CVAR(key) \
decltype(*self) newval; \
auto ret = ChangeMusicSetting(ZMusic::key, *self, &newval); \
self = (decltype(*self))newval; \
if (ret) MIDIDeviceChanged(-1, true);
#define FORWARD_BOOL_CVAR(key) \
int newval; \
auto ret = ChangeMusicSetting(ZMusic::key, *self, &newval); \
self = !!newval; \
if (ret) MIDIDeviceChanged(-1, true);
#define FORWARD_STRING_CVAR(key) \
auto ret = ChangeMusicSetting(ZMusic::key, *self); \
if (ret) MIDIDeviceChanged(-1, true);
CUSTOM_CVAR(Int, adl_chips_count, 6, CVAR_ARCHIVE | CVAR_GLOBALCONFIG | CVAR_VIRTUAL)
{
adlConfig.adl_chips_count = self;
CheckRestart(MDEV_ADL);
FORWARD_CVAR(adl_chips_count);
}
CUSTOM_CVAR(Int, adl_emulator_id, 0, CVAR_ARCHIVE | CVAR_GLOBALCONFIG)
CUSTOM_CVAR(Int, adl_emulator_id, 0, CVAR_ARCHIVE | CVAR_GLOBALCONFIG | CVAR_VIRTUAL)
{
adlConfig.adl_emulator_id = self;
CheckRestart(MDEV_ADL);
FORWARD_CVAR(adl_emulator_id);
}
CUSTOM_CVAR(Bool, adl_run_at_pcm_rate, 0, CVAR_ARCHIVE | CVAR_GLOBALCONFIG)
CUSTOM_CVAR(Bool, adl_run_at_pcm_rate, 0, CVAR_ARCHIVE | CVAR_GLOBALCONFIG | CVAR_VIRTUAL)
{
adlConfig.adl_run_at_pcm_rate = self;
CheckRestart(MDEV_ADL);
FORWARD_BOOL_CVAR(adl_run_at_pcm_rate);
}
CUSTOM_CVAR(Bool, adl_fullpan, 1, CVAR_ARCHIVE | CVAR_GLOBALCONFIG)
CUSTOM_CVAR(Bool, adl_fullpan, 1, CVAR_ARCHIVE | CVAR_GLOBALCONFIG | CVAR_VIRTUAL)
{
adlConfig.adl_fullpan = self;
CheckRestart(MDEV_ADL);
FORWARD_BOOL_CVAR(adl_fullpan);
}
CUSTOM_CVAR(Int, adl_bank, 14, CVAR_ARCHIVE | CVAR_GLOBALCONFIG)
CUSTOM_CVAR(Int, adl_bank, 14, CVAR_ARCHIVE | CVAR_GLOBALCONFIG | CVAR_VIRTUAL)
{
adlConfig.adl_bank = self;
CheckRestart(MDEV_ADL);
FORWARD_CVAR(adl_bank);
}
CUSTOM_CVAR(Bool, adl_use_custom_bank, 0, CVAR_ARCHIVE | CVAR_GLOBALCONFIG)
CUSTOM_CVAR(Bool, adl_use_custom_bank, 0, CVAR_ARCHIVE | CVAR_GLOBALCONFIG | CVAR_VIRTUAL)
{
CheckRestart(MDEV_ADL);
FORWARD_BOOL_CVAR(adl_use_custom_bank);
}
CUSTOM_CVAR(String, adl_custom_bank, "", CVAR_ARCHIVE | CVAR_GLOBALCONFIG)
CUSTOM_CVAR(String, adl_custom_bank, "", CVAR_ARCHIVE | CVAR_GLOBALCONFIG | CVAR_VIRTUAL)
{
if (adl_use_custom_bank) CheckRestart(MDEV_ADL);
FORWARD_STRING_CVAR(adl_custom_bank);
}
void ADL_SetupConfig(ADLConfig *config, const char *Args)
CUSTOM_CVAR(Int, adl_volume_model, 3/*ADLMIDI_VolumeModel_DMX*/, CVAR_ARCHIVE | CVAR_GLOBALCONFIG | CVAR_VIRTUAL)
{
//Resolve the path here, so that the renderer does not have to do the work itself and only needs to process final names.
const char *bank = Args && *Args? Args : adl_use_custom_bank? *adl_custom_bank : nullptr;
config->adl_bank = adl_bank;
if (bank && *bank)
{
auto info = sfmanager.FindSoundFont(bank, SF_WOPL);
if (info == nullptr)
{
if (*bank >= '0' && *bank <= '9')
{
config->adl_bank = (int)strtoll(bank, nullptr, 10);
}
config->adl_custom_bank = nullptr;
}
else
{
config->adl_custom_bank = info->mFilename;
}
}
}
CUSTOM_CVAR(Int, adl_volume_model, 3/*ADLMIDI_VolumeModel_DMX*/, CVAR_ARCHIVE | CVAR_GLOBALCONFIG)
{
adlConfig.adl_volume_model = self;
CheckRestart(MDEV_ADL);
FORWARD_CVAR(adl_bank);
}
//==========================================================================
@ -149,311 +129,95 @@ CUSTOM_CVAR(Int, adl_volume_model, 3/*ADLMIDI_VolumeModel_DMX*/, CVAR_ARCHIVE |
//
//==========================================================================
#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)
CUSTOM_CVAR(String, fluid_lib, "", CVAR_ARCHIVE | CVAR_GLOBALCONFIG | CVAR_VIRTUAL)
{
fluidConfig.fluid_lib = self; // only takes effect for next song.
FORWARD_STRING_CVAR(fluid_lib);
}
void Fluid_SetupConfig(FluidConfig *config, const char* patches, bool systemfallback)
CUSTOM_CVAR(String, fluid_patchset, "gzdoom", CVAR_ARCHIVE | CVAR_GLOBALCONFIG | CVAR_VIRTUAL)
{
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)
{
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))
{
config->fluid_patchset.push_back(path.GetChars());
}
else
{
Printf("Could not find patch set %s.\n", tok);
}
tok = strtok(NULL, delim);
}
free(wpatches);
if (config->fluid_patchset.size() > 0) return;
}
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.
Fluid_SetupConfig(config, "/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))
{
config->fluid_patchset.push_back(sysdir);
return;
}
// Try again with CT2MGM.SF2
sysdir[filepart + 3] = '2';
if (FileExists(sysdir))
{
config->fluid_patchset.push_back(sysdir);
return;
}
}
#endif
}
FORWARD_STRING_CVAR(fluid_patchset);
}
CUSTOM_CVAR(String, fluid_patchset, "gzdoom", CVAR_ARCHIVE | CVAR_GLOBALCONFIG)
CUSTOM_CVAR(Float, fluid_gain, 0.5, CVAR_ARCHIVE | CVAR_GLOBALCONFIG | CVAR_VIRTUAL)
{
CheckRestart(MDEV_FLUIDSYNTH);
FORWARD_CVAR(fluid_gain);
}
CUSTOM_CVAR(Float, fluid_gain, 0.5, CVAR_ARCHIVE|CVAR_GLOBALCONFIG)
CUSTOM_CVAR(Bool, fluid_reverb, false, CVAR_ARCHIVE | CVAR_GLOBALCONFIG | CVAR_VIRTUAL)
{
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;
}
FORWARD_BOOL_CVAR(fluid_reverb);
}
CUSTOM_CVAR(Bool, fluid_reverb, false, CVAR_ARCHIVE|CVAR_GLOBALCONFIG)
CUSTOM_CVAR(Bool, fluid_chorus, false, CVAR_ARCHIVE | CVAR_GLOBALCONFIG | CVAR_VIRTUAL)
{
if (currSong != NULL)
currSong->ChangeSettingInt("fluidsynth.synth.reverb.active", self);
fluidConfig.fluid_reverb = self;
FORWARD_BOOL_CVAR(fluid_chorus);
}
CUSTOM_CVAR(Bool, fluid_chorus, false, CVAR_ARCHIVE|CVAR_GLOBALCONFIG)
CUSTOM_CVAR(Int, fluid_voices, 128, CVAR_ARCHIVE | CVAR_GLOBALCONFIG | CVAR_VIRTUAL)
{
if (currSong != NULL)
currSong->ChangeSettingInt("fluidsynth.synth.chorus.active", self);
fluidConfig.fluid_chorus = self;
FORWARD_CVAR(fluid_voices);
}
CUSTOM_CVAR(Int, fluid_voices, 128, CVAR_ARCHIVE|CVAR_GLOBALCONFIG)
CUSTOM_CVAR(Int, fluid_interp, 1, CVAR_ARCHIVE | CVAR_GLOBALCONFIG | CVAR_VIRTUAL)
{
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;
}
FORWARD_CVAR(fluid_interp);
}
CUSTOM_CVAR(Int, fluid_interp, 1, CVAR_ARCHIVE|CVAR_GLOBALCONFIG)
CUSTOM_CVAR(Int, fluid_samplerate, 0, CVAR_ARCHIVE | CVAR_GLOBALCONFIG | CVAR_VIRTUAL)
{
// 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;
}
FORWARD_CVAR(fluid_samplerate);
}
CUSTOM_CVAR(Int, fluid_samplerate, 0, CVAR_ARCHIVE|CVAR_GLOBALCONFIG)
CUSTOM_CVAR(Int, fluid_threads, 1, CVAR_ARCHIVE | CVAR_GLOBALCONFIG | CVAR_VIRTUAL)
{
fluidConfig.fluid_samplerate = std::max<int>(*self, 0);
FORWARD_CVAR(fluid_threads);
}
// 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)
CUSTOM_CVAR(Float, fluid_reverb_roomsize, 0.61f, CVAR_ARCHIVE | CVAR_GLOBALCONFIG | CVAR_VIRTUAL)
{
if (self < 1)
self = 1;
else if (self > 256)
self = 256;
else
fluidConfig.fluid_threads = self;
FORWARD_CVAR(fluid_reverb_roomsize);
}
CUSTOM_CVAR(Float, fluid_reverb_roomsize, 0.61f, CVAR_ARCHIVE|CVAR_GLOBALCONFIG)
CUSTOM_CVAR(Float, fluid_reverb_damping, 0.23f, CVAR_ARCHIVE | CVAR_GLOBALCONFIG | CVAR_VIRTUAL)
{
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;
}
FORWARD_CVAR(fluid_reverb_damping);
}
CUSTOM_CVAR(Float, fluid_reverb_damping, 0.23f, CVAR_ARCHIVE|CVAR_GLOBALCONFIG)
CUSTOM_CVAR(Float, fluid_reverb_width, 0.76f, CVAR_ARCHIVE | CVAR_GLOBALCONFIG | CVAR_VIRTUAL)
{
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;
}
FORWARD_CVAR(fluid_reverb_width);
}
CUSTOM_CVAR(Float, fluid_reverb_width, 0.76f, CVAR_ARCHIVE|CVAR_GLOBALCONFIG)
CUSTOM_CVAR(Float, fluid_reverb_level, 0.57f, CVAR_ARCHIVE | CVAR_GLOBALCONFIG | CVAR_VIRTUAL)
{
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;
}
FORWARD_CVAR(fluid_reverb_level);
}
CUSTOM_CVAR(Float, fluid_reverb_level, 0.57f, CVAR_ARCHIVE|CVAR_GLOBALCONFIG)
CUSTOM_CVAR(Int, fluid_chorus_voices, 3, CVAR_ARCHIVE | CVAR_GLOBALCONFIG | CVAR_VIRTUAL)
{
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;
}
FORWARD_CVAR(fluid_chorus_voices);
}
CUSTOM_CVAR(Int, fluid_chorus_voices, 3, CVAR_ARCHIVE|CVAR_GLOBALCONFIG)
CUSTOM_CVAR(Float, fluid_chorus_level, 1.2f, CVAR_ARCHIVE | CVAR_GLOBALCONFIG | CVAR_VIRTUAL)
{
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;
}
FORWARD_CVAR(fluid_chorus_level);
}
CUSTOM_CVAR(Float, fluid_chorus_level, 1.2f, CVAR_ARCHIVE|CVAR_GLOBALCONFIG)
CUSTOM_CVAR(Float, fluid_chorus_speed, 0.3f, CVAR_ARCHIVE | CVAR_GLOBALCONFIG | CVAR_VIRTUAL)
{
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;
}
FORWARD_CVAR(fluid_chorus_speed);
}
// depth is in ms and actual maximum depends on the sample rate
CUSTOM_CVAR(Float, fluid_chorus_depth, 8, CVAR_ARCHIVE|CVAR_GLOBALCONFIG)
CUSTOM_CVAR(Float, fluid_chorus_depth, 8, CVAR_ARCHIVE | CVAR_GLOBALCONFIG | CVAR_VIRTUAL)
{
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;
}
FORWARD_CVAR(fluid_chorus_depth);
}
CUSTOM_CVAR(Int, fluid_chorus_type, FLUID_CHORUS_DEFAULT_TYPE, CVAR_ARCHIVE|CVAR_GLOBALCONFIG)
CUSTOM_CVAR(Int, fluid_chorus_type, 0/*FLUID_CHORUS_DEFAULT_TYPE*/, CVAR_ARCHIVE | CVAR_GLOBALCONFIG | CVAR_VIRTUAL)
{
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;
}
FORWARD_CVAR(fluid_chorus_type);
}
@ -463,7 +227,7 @@ CUSTOM_CVAR(Int, fluid_chorus_type, FLUID_CHORUS_DEFAULT_TYPE, CVAR_ARCHIVE|CVAR
//
//==========================================================================
CUSTOM_CVAR(Int, opl_numchips, 2, CVAR_ARCHIVE | CVAR_GLOBALCONFIG)
CUSTOM_CVAR(Int, opl_numchips, 2, CVAR_ARCHIVE | CVAR_GLOBALCONFIG | CVAR_VIRTUAL)
{
if (*self <= 0)
{
@ -481,12 +245,12 @@ CUSTOM_CVAR(Int, opl_numchips, 2, CVAR_ARCHIVE | CVAR_GLOBALCONFIG)
}
}
CUSTOM_CVAR(Int, opl_core, 0, CVAR_ARCHIVE | CVAR_GLOBALCONFIG)
CUSTOM_CVAR(Int, opl_core, 0, CVAR_ARCHIVE | CVAR_GLOBALCONFIG | CVAR_VIRTUAL)
{
CheckRestart(MDEV_OPL);
}
CUSTOM_CVAR(Bool, opl_fullpan, true, CVAR_ARCHIVE | CVAR_GLOBALCONFIG)
CUSTOM_CVAR(Bool, opl_fullpan, true, CVAR_ARCHIVE | CVAR_GLOBALCONFIG | CVAR_VIRTUAL)
{
oplConfig.fullpan = self;
}
@ -521,40 +285,40 @@ void OPL_SetupConfig(OPLConfig *config, const char *args, bool midi)
//==========================================================================
CUSTOM_CVAR(Int, opn_chips_count, 8, CVAR_ARCHIVE | CVAR_GLOBALCONFIG)
CUSTOM_CVAR(Int, opn_chips_count, 8, CVAR_ARCHIVE | CVAR_GLOBALCONFIG | CVAR_VIRTUAL)
{
opnConfig.opn_chips_count = self;
CheckRestart(MDEV_OPN);
}
CUSTOM_CVAR(Int, opn_emulator_id, 0, CVAR_ARCHIVE | CVAR_GLOBALCONFIG)
CUSTOM_CVAR(Int, opn_emulator_id, 0, CVAR_ARCHIVE | CVAR_GLOBALCONFIG | CVAR_VIRTUAL)
{
opnConfig.opn_emulator_id = self;
CheckRestart(MDEV_OPN);
}
CUSTOM_CVAR(Bool, opn_run_at_pcm_rate, 0, CVAR_ARCHIVE | CVAR_GLOBALCONFIG)
CUSTOM_CVAR(Bool, opn_run_at_pcm_rate, 0, CVAR_ARCHIVE | CVAR_GLOBALCONFIG | CVAR_VIRTUAL)
{
opnConfig.opn_run_at_pcm_rate = self;
CheckRestart(MDEV_OPN);
}
CUSTOM_CVAR(Bool, opn_fullpan, 1, CVAR_ARCHIVE | CVAR_GLOBALCONFIG)
CUSTOM_CVAR(Bool, opn_fullpan, 1, CVAR_ARCHIVE | CVAR_GLOBALCONFIG | CVAR_VIRTUAL)
{
opnConfig.opn_fullpan = self;
CheckRestart(MDEV_OPN);
}
CUSTOM_CVAR(Bool, opn_use_custom_bank, 0, CVAR_ARCHIVE | CVAR_GLOBALCONFIG)
CUSTOM_CVAR(Bool, opn_use_custom_bank, 0, CVAR_ARCHIVE | CVAR_GLOBALCONFIG | CVAR_VIRTUAL)
{
CheckRestart(MDEV_OPN);
}
CUSTOM_CVAR(String, opn_custom_bank, "", CVAR_ARCHIVE | CVAR_GLOBALCONFIG)
CUSTOM_CVAR(String, opn_custom_bank, "", CVAR_ARCHIVE | CVAR_GLOBALCONFIG | CVAR_VIRTUAL)
{
if (opn_use_custom_bank)
{
@ -598,65 +362,34 @@ void OPN_SetupConfig(OpnConfig *config, const char *Args)
//==========================================================================
CUSTOM_CVAR(String, midi_config, "gzdoom", CVAR_ARCHIVE | CVAR_GLOBALCONFIG)
CUSTOM_CVAR(String, midi_config, "gzdoom", CVAR_ARCHIVE | CVAR_GLOBALCONFIG | CVAR_VIRTUAL)
{
CheckRestart(MDEV_GUS);
}
CUSTOM_CVAR(Bool, midi_dmxgus, false, CVAR_ARCHIVE | CVAR_GLOBALCONFIG) // This was 'true' but since it requires special setup that's not such a good idea.
CUSTOM_CVAR(Bool, midi_dmxgus, false, CVAR_ARCHIVE | CVAR_GLOBALCONFIG | CVAR_VIRTUAL) // This was 'true' but since it requires special setup that's not such a good idea.
{
CheckRestart(MDEV_GUS);
}
CUSTOM_CVAR(String, gus_patchdir, "", CVAR_ARCHIVE | CVAR_GLOBALCONFIG)
CUSTOM_CVAR(String, gus_patchdir, "", CVAR_ARCHIVE | CVAR_GLOBALCONFIG | CVAR_VIRTUAL)
{
gusConfig.gus_patchdir = self;
CheckRestart(MDEV_GUS);
}
CUSTOM_CVAR(Int, midi_voices, 32, CVAR_ARCHIVE | CVAR_GLOBALCONFIG)
CUSTOM_CVAR(Int, midi_voices, 32, CVAR_ARCHIVE | CVAR_GLOBALCONFIG | CVAR_VIRTUAL)
{
gusConfig.midi_voices = self;
CheckRestart(MDEV_GUS);
}
CUSTOM_CVAR(Int, gus_memsize, 0, CVAR_ARCHIVE | CVAR_GLOBALCONFIG)
CUSTOM_CVAR(Int, gus_memsize, 0, CVAR_ARCHIVE | CVAR_GLOBALCONFIG | CVAR_VIRTUAL)
{
gusConfig.gus_memsize = self;
CheckRestart(MDEV_GUS);
}
//==========================================================================
//
// Error printing override to redirect to the internal console instead of stdout.
//
//==========================================================================
static void gus_printfunc(int type, int verbosity_level, const char* fmt, ...)
{
if (verbosity_level >= Timidity::VERB_DEBUG) return; // Don't waste time on diagnostics.
va_list args;
va_start(args, fmt);
FString msg;
msg.VFormat(fmt, args);
va_end(args);
switch (type)
{
case Timidity::CMSG_ERROR:
Printf(TEXTCOLOR_RED "%s\n", msg.GetChars());
break;
case Timidity::CMSG_WARNING:
Printf(TEXTCOLOR_YELLOW "%s\n", msg.GetChars());
break;
case Timidity::CMSG_INFO:
DPrintf(DMSG_SPAMMY, "%s\n", msg.GetChars());
break;
}
}
// make sure we can use the above function for the Timidity++ device as well.
static_assert(Timidity::CMSG_ERROR == TimidityPlus::CMSG_ERROR, "Timidity constant mismatch");
@ -673,7 +406,6 @@ static_assert(Timidity::VERB_DEBUG == TimidityPlus::VERB_DEBUG, "Timidity consta
bool GUS_SetupConfig(GUSConfig *config, const char *args)
{
config->errorfunc = gus_printfunc;
if ((midi_dmxgus && *args == 0) || !stricmp(args, "DMXGUS"))
{
if (stricmp(config->loadedConfig.c_str(), "DMXGUS") == 0) return false; // aleady loaded
@ -718,20 +450,22 @@ bool GUS_SetupConfig(GUSConfig *config, const char *args)
//
//==========================================================================
/*
template<class T> void ChangeVarSync(T& var, T value)
{
std::lock_guard<std::mutex> lock(TimidityPlus::ConfigMutex);
var = value;
}
*/
CUSTOM_CVAR(Bool, timidity_modulation_wheel, true, CVAR_ARCHIVE | CVAR_GLOBALCONFIG)
CUSTOM_CVAR(Bool, timidity_modulation_wheel, true, CVAR_ARCHIVE | CVAR_GLOBALCONFIG | CVAR_VIRTUAL)
{
ChangeVarSync(TimidityPlus::timidity_modulation_wheel, *self);
////ChangeVarSync(TimidityPlus::timidity_modulation_wheel, *self);
}
CUSTOM_CVAR(Bool, timidity_portamento, true, CVAR_ARCHIVE | CVAR_GLOBALCONFIG)
CUSTOM_CVAR(Bool, timidity_portamento, true, CVAR_ARCHIVE | CVAR_GLOBALCONFIG | CVAR_VIRTUAL)
{
ChangeVarSync(TimidityPlus::timidity_portamento, *self);
////ChangeVarSync(TimidityPlus::timidity_portamento, *self);
}
/*
* reverb=0 no reverb 0
@ -755,103 +489,102 @@ static void SetReverb()
if (mode == 0 || level == 0) value = mode;
else value = (mode - 1) * -128 - level;
ChangeVarSync(TimidityPlus::timidity_reverb, value);
//ChangeVarSync(TimidityPlus::timidity_reverb, value);
}
CUSTOM_CVAR(Int, timidity_reverb, 0, CVAR_ARCHIVE | CVAR_GLOBALCONFIG)
CUSTOM_CVAR(Int, timidity_reverb, 0, CVAR_ARCHIVE | CVAR_GLOBALCONFIG | CVAR_VIRTUAL)
{
if (self < 0 || self > 4) self = 0;
else SetReverb();
}
CUSTOM_CVAR(Int, timidity_reverb_level, 0, CVAR_ARCHIVE | CVAR_GLOBALCONFIG)
CUSTOM_CVAR(Int, timidity_reverb_level, 0, CVAR_ARCHIVE | CVAR_GLOBALCONFIG | CVAR_VIRTUAL)
{
if (self < 0 || self > 127) self = 0;
else SetReverb();
}
CUSTOM_CVAR(Int, timidity_chorus, 0, CVAR_ARCHIVE | CVAR_GLOBALCONFIG)
CUSTOM_CVAR(Int, timidity_chorus, 0, CVAR_ARCHIVE | CVAR_GLOBALCONFIG | CVAR_VIRTUAL)
{
ChangeVarSync(TimidityPlus::timidity_chorus, *self);
//ChangeVarSync(TimidityPlus::timidity_chorus, *self);
}
CUSTOM_CVAR(Bool, timidity_surround_chorus, false, CVAR_ARCHIVE | CVAR_GLOBALCONFIG)
CUSTOM_CVAR(Bool, timidity_surround_chorus, false, CVAR_ARCHIVE | CVAR_GLOBALCONFIG | CVAR_VIRTUAL)
{
ChangeVarSync(TimidityPlus::timidity_surround_chorus, *self);
//ChangeVarSync(TimidityPlus::timidity_surround_chorus, *self);
CheckRestart(MDEV_TIMIDITY);
}
CUSTOM_CVAR(Bool, timidity_channel_pressure, false, CVAR_ARCHIVE | CVAR_GLOBALCONFIG)
CUSTOM_CVAR(Bool, timidity_channel_pressure, false, CVAR_ARCHIVE | CVAR_GLOBALCONFIG | CVAR_VIRTUAL)
{
ChangeVarSync(TimidityPlus::timidity_channel_pressure, *self);
//ChangeVarSync(TimidityPlus::timidity_channel_pressure, *self);
}
CUSTOM_CVAR(Int, timidity_lpf_def, true, CVAR_ARCHIVE | CVAR_GLOBALCONFIG)
CUSTOM_CVAR(Int, timidity_lpf_def, true, CVAR_ARCHIVE | CVAR_GLOBALCONFIG | CVAR_VIRTUAL)
{
ChangeVarSync(TimidityPlus::timidity_lpf_def, *self);
//ChangeVarSync(TimidityPlus::timidity_lpf_def, *self);
}
CUSTOM_CVAR(Bool, timidity_temper_control, true, CVAR_ARCHIVE | CVAR_GLOBALCONFIG)
CUSTOM_CVAR(Bool, timidity_temper_control, true, CVAR_ARCHIVE | CVAR_GLOBALCONFIG | CVAR_VIRTUAL)
{
ChangeVarSync(TimidityPlus::timidity_temper_control, *self);
//ChangeVarSync(TimidityPlus::timidity_temper_control, *self);
}
CUSTOM_CVAR(Bool, timidity_modulation_envelope, true, CVAR_ARCHIVE | CVAR_GLOBALCONFIG)
CUSTOM_CVAR(Bool, timidity_modulation_envelope, true, CVAR_ARCHIVE | CVAR_GLOBALCONFIG | CVAR_VIRTUAL)
{
ChangeVarSync(TimidityPlus::timidity_modulation_envelope, *self);
//ChangeVarSync(TimidityPlus::timidity_modulation_envelope, *self);
CheckRestart(MDEV_TIMIDITY);
}
CUSTOM_CVAR(Bool, timidity_overlap_voice_allow, true, CVAR_ARCHIVE | CVAR_GLOBALCONFIG)
CUSTOM_CVAR(Bool, timidity_overlap_voice_allow, true, CVAR_ARCHIVE | CVAR_GLOBALCONFIG | CVAR_VIRTUAL)
{
ChangeVarSync(TimidityPlus::timidity_overlap_voice_allow, *self);
//ChangeVarSync(TimidityPlus::timidity_overlap_voice_allow, *self);
}
CUSTOM_CVAR(Bool, timidity_drum_effect, false, CVAR_ARCHIVE | CVAR_GLOBALCONFIG)
CUSTOM_CVAR(Bool, timidity_drum_effect, false, CVAR_ARCHIVE | CVAR_GLOBALCONFIG | CVAR_VIRTUAL)
{
ChangeVarSync(TimidityPlus::timidity_drum_effect, *self);
//ChangeVarSync(TimidityPlus::timidity_drum_effect, *self);
}
CUSTOM_CVAR(Bool, timidity_pan_delay, false, CVAR_ARCHIVE | CVAR_GLOBALCONFIG)
CUSTOM_CVAR(Bool, timidity_pan_delay, false, CVAR_ARCHIVE | CVAR_GLOBALCONFIG | CVAR_VIRTUAL)
{
ChangeVarSync(TimidityPlus::timidity_pan_delay, *self);
//ChangeVarSync(TimidityPlus::timidity_pan_delay, *self);
}
CUSTOM_CVAR(Float, timidity_drum_power, 1.0, CVAR_ARCHIVE | CVAR_GLOBALCONFIG) /* coef. of drum amplitude */
CUSTOM_CVAR(Float, timidity_drum_power, 1.0, CVAR_ARCHIVE | CVAR_GLOBALCONFIG | CVAR_VIRTUAL) /* coef. of drum amplitude */
{
if (self < 0) self = 0;
else if (self > MAX_AMPLIFICATION / 100.f) self = MAX_AMPLIFICATION / 100.f;
ChangeVarSync(TimidityPlus::timidity_drum_power, *self);
//ChangeVarSync(TimidityPlus::timidity_drum_power, *self);
}
CUSTOM_CVAR(Int, timidity_key_adjust, 0, CVAR_ARCHIVE | CVAR_GLOBALCONFIG)
CUSTOM_CVAR(Int, timidity_key_adjust, 0, CVAR_ARCHIVE | CVAR_GLOBALCONFIG | CVAR_VIRTUAL)
{
if (self < -24) self = -24;
else if (self > 24) self = 24;
ChangeVarSync(TimidityPlus::timidity_key_adjust, *self);
//ChangeVarSync(TimidityPlus::timidity_key_adjust, *self);
}
// For testing mainly.
CUSTOM_CVAR(Float, timidity_tempo_adjust, 1, CVAR_ARCHIVE | CVAR_GLOBALCONFIG)
CUSTOM_CVAR(Float, timidity_tempo_adjust, 1, CVAR_ARCHIVE | CVAR_GLOBALCONFIG | CVAR_VIRTUAL)
{
if (self < 0.25) self = 0.25;
else if (self > 10) self = 10;
ChangeVarSync(TimidityPlus::timidity_tempo_adjust, *self);
//ChangeVarSync(TimidityPlus::timidity_tempo_adjust, *self);
}
CUSTOM_CVAR(Float, min_sustain_time, 5000, CVAR_ARCHIVE | CVAR_GLOBALCONFIG)
CUSTOM_CVAR(Float, min_sustain_time, 5000, CVAR_ARCHIVE | CVAR_GLOBALCONFIG | CVAR_VIRTUAL)
{
if (self < 0) self = 0;
ChangeVarSync(TimidityPlus::min_sustain_time, *self);
//ChangeVarSync(TimidityPlus::min_sustain_time, *self);
}
// Config file to use
CUSTOM_CVAR(String, timidity_config, "gzdoom", CVAR_ARCHIVE | CVAR_GLOBALCONFIG)
CUSTOM_CVAR(String, timidity_config, "gzdoom", CVAR_ARCHIVE | CVAR_GLOBALCONFIG | CVAR_VIRTUAL)
{
CheckRestart(MDEV_TIMIDITY);
}
bool Timidity_SetupConfig(TimidityConfig* config, const char* args)
{
config->errorfunc = gus_printfunc;
if (*args == 0) args = timidity_config;
if (stricmp(config->loadedConfig.c_str(), args) == 0) return false; // aleady loaded
@ -873,35 +606,28 @@ bool Timidity_SetupConfig(TimidityConfig* config, const char* args)
//
//==========================================================================
CUSTOM_CVAR(String, wildmidi_config, "", CVAR_ARCHIVE | CVAR_GLOBALCONFIG)
CUSTOM_CVAR(String, wildmidi_config, "", CVAR_ARCHIVE | CVAR_GLOBALCONFIG | CVAR_VIRTUAL)
{
CheckRestart(MDEV_WILDMIDI);
}
CUSTOM_CVAR(Bool, wildmidi_reverb, false, CVAR_ARCHIVE | CVAR_GLOBALCONFIG | CVAR_NOINITCALL)
CUSTOM_CVAR(Bool, wildmidi_reverb, false, CVAR_ARCHIVE | CVAR_GLOBALCONFIG | CVAR_VIRTUAL | CVAR_NOINITCALL)
{
if (currSong != NULL)
currSong->ChangeSettingInt("wildmidi.reverb", *self);
wildMidiConfig.reverb = self;
}
CUSTOM_CVAR(Bool, wildmidi_enhanced_resampling, true, CVAR_ARCHIVE | CVAR_GLOBALCONFIG | CVAR_NOINITCALL)
CUSTOM_CVAR(Bool, wildmidi_enhanced_resampling, true, CVAR_ARCHIVE | CVAR_GLOBALCONFIG | CVAR_VIRTUAL | CVAR_NOINITCALL)
{
if (currSong != NULL)
currSong->ChangeSettingInt("wildmidi.resampling", *self);
wildMidiConfig.enhanced_resampling = self;
}
static void wm_printfunc(const char* wmfmt, va_list args)
{
Printf(TEXTCOLOR_RED);
VPrintf(PRINT_HIGH, wmfmt, args);
}
bool WildMidi_SetupConfig(WildMidiConfig* config, const char* args)
{
config->errorfunc = wm_printfunc;
if (*args == 0) args = wildmidi_config;
if (stricmp(config->loadedConfig.c_str(), args) == 0) return false; // aleady loaded
@ -925,7 +651,7 @@ bool WildMidi_SetupConfig(WildMidiConfig* config, const char* args)
//
//==========================================================================
CVAR(Bool, snd_midiprecache, false, CVAR_ARCHIVE | CVAR_GLOBALCONFIG);
CVAR(Bool, snd_midiprecache, false, CVAR_ARCHIVE | CVAR_GLOBALCONFIG | CVAR_VIRTUAL);
//==========================================================================
//
@ -933,7 +659,7 @@ CVAR(Bool, snd_midiprecache, false, CVAR_ARCHIVE | CVAR_GLOBALCONFIG);
//
//==========================================================================
CUSTOM_CVAR(Float, gme_stereodepth, 0.f, CVAR_ARCHIVE | CVAR_GLOBALCONFIG)
CUSTOM_CVAR(Float, gme_stereodepth, 0.f, CVAR_ARCHIVE | CVAR_GLOBALCONFIG | CVAR_VIRTUAL)
{
if (currSong != nullptr)
currSong->ChangeSettingNum("GME.stereodepth", *self);
@ -945,14 +671,14 @@ CUSTOM_CVAR(Float, gme_stereodepth, 0.f, CVAR_ARCHIVE | CVAR_GLOBALCONFIG)
//
//==========================================================================
CVAR(Int, mod_samplerate, 0, CVAR_ARCHIVE|CVAR_GLOBALCONFIG);
CVAR(Int, mod_volramp, 2, CVAR_ARCHIVE|CVAR_GLOBALCONFIG);
CVAR(Int, mod_interp, DUMB_LQ_CUBIC, CVAR_ARCHIVE|CVAR_GLOBALCONFIG);
CVAR(Bool, mod_autochip, false, CVAR_ARCHIVE|CVAR_GLOBALCONFIG);
CVAR(Int, mod_autochip_size_force, 100, CVAR_ARCHIVE|CVAR_GLOBALCONFIG);
CVAR(Int, mod_autochip_size_scan, 500, CVAR_ARCHIVE|CVAR_GLOBALCONFIG);
CVAR(Int, mod_autochip_scan_threshold, 12, CVAR_ARCHIVE|CVAR_GLOBALCONFIG);
CUSTOM_CVAR(Float, mod_dumb_mastervolume, 1.f, CVAR_ARCHIVE | CVAR_GLOBALCONFIG)
CVAR(Int, mod_samplerate, 0, CVAR_ARCHIVE | CVAR_GLOBALCONFIG | CVAR_VIRTUAL);
CVAR(Int, mod_volramp, 2, CVAR_ARCHIVE | CVAR_GLOBALCONFIG | CVAR_VIRTUAL);
CVAR(Int, mod_interp, DUMB_LQ_CUBIC, CVAR_ARCHIVE | CVAR_GLOBALCONFIG | CVAR_VIRTUAL);
CVAR(Bool, mod_autochip, false, CVAR_ARCHIVE | CVAR_GLOBALCONFIG | CVAR_VIRTUAL);
CVAR(Int, mod_autochip_size_force, 100, CVAR_ARCHIVE | CVAR_GLOBALCONFIG | CVAR_VIRTUAL);
CVAR(Int, mod_autochip_size_scan, 500, CVAR_ARCHIVE | CVAR_GLOBALCONFIG | CVAR_VIRTUAL);
CVAR(Int, mod_autochip_scan_threshold, 12, CVAR_ARCHIVE | CVAR_GLOBALCONFIG | CVAR_VIRTUAL);
CUSTOM_CVAR(Float, mod_dumb_mastervolume, 1.f, CVAR_ARCHIVE | CVAR_GLOBALCONFIG | CVAR_VIRTUAL)
{
if (self < 0.5f) self = 0.5f;
else if (self > 16.f) self = 16.f;
@ -977,7 +703,7 @@ void Dumb_SetupConfig(DumbConfig* config)
//
//==========================================================================
CUSTOM_CVAR(Int, snd_streambuffersize, 64, CVAR_ARCHIVE | CVAR_GLOBALCONFIG)
CUSTOM_CVAR(Int, snd_streambuffersize, 64, CVAR_ARCHIVE | CVAR_GLOBALCONFIG | CVAR_VIRTUAL)
{
if (self < 16)
{

View file

@ -198,8 +198,7 @@ MIDIDevice *MIDIStreamer::CreateMIDIDevice(EMidiDevice devtype, int samplerate)
break;
case MDEV_ADL:
ADL_SetupConfig(&adlConfig, Args);
dev = CreateADLMIDIDevice(&adlConfig);
dev = CreateADLMIDIDevice(Args);
break;
case MDEV_OPN:
@ -210,14 +209,13 @@ MIDIDevice *MIDIStreamer::CreateMIDIDevice(EMidiDevice devtype, int samplerate)
case MDEV_MMAPI:
#ifdef _WIN32
dev = CreateWinMIDIDevice(mididevice, snd_midiprecache);
dev = CreateWinMIDIDevice(mididevice);
break;
#endif
// Intentional fall-through for non-Windows systems.
case MDEV_FLUIDSYNTH:
Fluid_SetupConfig(&fluidConfig, Args, true);
dev = CreateFluidSynthMIDIDevice(samplerate, &fluidConfig, Printf);
dev = CreateFluidSynthMIDIDevice(samplerate, Args);
break;
case MDEV_OPL: