diff --git a/libraries/music_common/fileio.h b/libraries/music_common/fileio.h index 849c677516..ebf740cda6 100644 --- a/libraries/music_common/fileio.h +++ b/libraries/music_common/fileio.h @@ -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; +} //========================================================================== // diff --git a/libraries/timidityplus/playmidi.cpp b/libraries/timidityplus/playmidi.cpp index 04fb2741a5..441365ee49 100644 --- a/libraries/timidityplus/playmidi.cpp +++ b/libraries/timidityplus/playmidi.cpp @@ -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_chorus = 0; + 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; diff --git a/libraries/timidityplus/timiditypp/timidity.h b/libraries/timidityplus/timiditypp/timidity.h index 0edce9f82a..ba1edd652b 100644 --- a/libraries/timidityplus/timiditypp/timidity.h +++ b/libraries/timidityplus/timiditypp/timidity.h @@ -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_chorus; +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; diff --git a/libraries/zmusic/CMakeLists.txt b/libraries/zmusic/CMakeLists.txt index b2b0a78e0e..4e75ac2565 100644 --- a/libraries/zmusic/CMakeLists.txt +++ b/libraries/zmusic/CMakeLists.txt @@ -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/.+") diff --git a/libraries/zmusic/mididevices/mididevice.h b/libraries/zmusic/mididevices/mididevice.h index 98789a8740..8ced9d824d 100644 --- a/libraries/zmusic/mididevices/mididevice.h +++ b/libraries/zmusic/mididevices/mididevice.h @@ -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 diff --git a/libraries/zmusic/mididevices/music_adlmidi_mididevice.cpp b/libraries/zmusic/mididevices/music_adlmidi_mididevice.cpp index a04ff224df..8599de9182 100644 --- a/libraries/zmusic/mididevices/music_adlmidi_mididevice.cpp +++ b/libraries/zmusic/mididevices/music_adlmidi_mididevice.cpp @@ -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); } diff --git a/libraries/zmusic/mididevices/music_fluidsynth_mididevice.cpp b/libraries/zmusic/mididevices/music_fluidsynth_mididevice.cpp index 778f8a231b..be42dad4af 100644 --- a/libraries/zmusic/mididevices/music_fluidsynth_mididevice.cpp +++ b/libraries/zmusic/mididevices/music_fluidsynth_mididevice.cpp @@ -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 &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& 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 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 &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 &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 &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 fluid_patchset; + + Fluid_SetupConfig(Args, fluid_patchset, true); + return new FluidSynthMIDIDevice(samplerate, fluid_patchset, musicCallbacks.Fluid_MessageFunc); } diff --git a/libraries/zmusic/mididevices/music_win_mididevice.cpp b/libraries/zmusic/mididevices/music_win_mididevice.cpp index 11b6fc7012..19915a5569 100644 --- a/libraries/zmusic/mididevices/music_win_mididevice.cpp +++ b/libraries/zmusic/mididevices/music_win_mididevice.cpp @@ -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 diff --git a/libraries/zmusic/zmusic/configuration.cpp b/libraries/zmusic/zmusic/configuration.cpp new file mode 100644 index 0000000000..852b3b39c5 --- /dev/null +++ b/libraries/zmusic/zmusic/configuration.cpp @@ -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 +#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 +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 void ChangeVarSync(T& var, T value) +{ + std::lock_guard 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(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 \ No newline at end of file diff --git a/libraries/zmusic/zmusic/midiconfig.h b/libraries/zmusic/zmusic/midiconfig.h index df6cd55273..f6d800229b 100644 --- a/libraries/zmusic/zmusic/midiconfig.h +++ b/libraries/zmusic/zmusic/midiconfig.h @@ -3,25 +3,29 @@ #include #include #include +#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 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 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 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 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 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 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 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 -}; - -} \ No newline at end of file diff --git a/libraries/zmusic/zmusic/mididefs.h b/libraries/zmusic/zmusic/mididefs.h index 42418feaae..29cfcb5a5a 100644 --- a/libraries/zmusic/zmusic/mididefs.h +++ b/libraries/zmusic/zmusic/mididefs.h @@ -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. diff --git a/libraries/zmusic/zmusic/zmusic.h b/libraries/zmusic/zmusic/zmusic.h index 10f4d2d5f7..d810525ea5 100644 --- a/libraries/zmusic/zmusic/zmusic.h +++ b/libraries/zmusic/zmusic/zmusic.h @@ -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); diff --git a/src/sound/music/i_music.cpp b/src/sound/music/i_music.cpp index a787ad093b..511e55c1c4 100644 --- a/src/sound/music/i_music.cpp +++ b/src/sound/music/i_music.cpp @@ -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); } diff --git a/src/sound/music/i_musicinterns.h b/src/sound/music/i_musicinterns.h index 7c9a3b5f9b..90fc82cf97 100644 --- a/src/sound/music/i_musicinterns.h +++ b/src/sound/music/i_musicinterns.h @@ -19,7 +19,6 @@ class MIDIDevice; class OPLmusicFile; -extern ADLConfig adlConfig; extern FluidConfig fluidConfig; extern OPLConfig oplConfig; extern OpnConfig opnConfig; diff --git a/src/sound/music/i_soundfont.cpp b/src/sound/music/i_soundfont.cpp index 075d77a5ff..4f4bb1110d 100644 --- a/src/sound/music/i_soundfont.cpp +++ b/src/sound/music/i_soundfont.cpp @@ -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" diff --git a/src/sound/music/i_soundfont.h b/src/sound/music/i_soundfont.h index 629d041236..76e20d1b19 100644 --- a/src/sound/music/i_soundfont.h +++ b/src/sound/music/i_soundfont.h @@ -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 diff --git a/src/sound/music/midi_cvars.cpp b/src/sound/music/midi_cvars.cpp index 6e4215d7ed..f63f0cf408 100644 --- a/src/sound/music/midi_cvars.cpp +++ b/src/sound/music/midi_cvars.cpp @@ -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(*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 void ChangeVarSync(T& var, T value) { std::lock_guard 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) { diff --git a/src/sound/musicformats/music_midistream.cpp b/src/sound/musicformats/music_midistream.cpp index 9b7fd810fd..535a444efc 100644 --- a/src/sound/musicformats/music_midistream.cpp +++ b/src/sound/musicformats/music_midistream.cpp @@ -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: