mirror of
https://github.com/ZDoom/gzdoom-gles.git
synced 2024-11-24 21:21:04 +00:00
Merge branch 'midi_work_2'
This commit is contained in:
commit
c5f2578ff5
23 changed files with 790 additions and 632 deletions
|
@ -1,7 +1,5 @@
|
|||
cmake_minimum_required( VERSION 2.8.7 )
|
||||
|
||||
make_release_only()
|
||||
|
||||
if( ZD_CMAKE_COMPILER_IS_GNUC_COMPATIBLE )
|
||||
set( CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wall -Wextra -Wno-unused-parameter -fomit-frame-pointer" )
|
||||
set( CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11" )
|
||||
|
|
|
@ -1,7 +1,5 @@
|
|||
cmake_minimum_required( VERSION 2.8.7 )
|
||||
|
||||
make_release_only()
|
||||
|
||||
if( ZD_CMAKE_COMPILER_IS_GNUC_COMPATIBLE )
|
||||
set( CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wall -Wextra -Wno-unused-parameter -fomit-frame-pointer" )
|
||||
set( CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11" )
|
||||
|
|
|
@ -38,8 +38,6 @@
|
|||
namespace Timidity
|
||||
{
|
||||
|
||||
static std::string def_instr_name;
|
||||
|
||||
static long ParseCommandLine(const char* args, int* argc, char** argv)
|
||||
{
|
||||
int count;
|
||||
|
@ -718,8 +716,8 @@ Renderer::Renderer(float sample_rate, int voices_, Instruments *inst)
|
|||
|
||||
default_instrument = NULL;
|
||||
default_program = DEFAULT_PROGRAM;
|
||||
if (def_instr_name.length() > 0)
|
||||
set_default_instrument(def_instr_name.c_str());
|
||||
if (inst->def_instr_name.length() > 0)
|
||||
set_default_instrument(inst->def_instr_name.c_str());
|
||||
|
||||
voices = std::max(voices_, 16);
|
||||
voice = new Voice[voices];
|
||||
|
|
|
@ -168,6 +168,7 @@ public:
|
|||
ToneBank* tonebank[MAXBANK] = {};
|
||||
ToneBank* drumset[MAXBANK] = {};
|
||||
FontFile* Fonts = nullptr;
|
||||
std::string def_instr_name;
|
||||
|
||||
Instruments(SoundFontReaderInterface* reader);
|
||||
~Instruments();
|
||||
|
|
|
@ -1,7 +1,5 @@
|
|||
cmake_minimum_required( VERSION 2.8.7 )
|
||||
|
||||
make_release_only()
|
||||
|
||||
if( ZD_CMAKE_COMPILER_IS_GNUC_COMPATIBLE )
|
||||
set( CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wall -Wextra -Wno-unused-parameter -fomit-frame-pointer" )
|
||||
set( CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11" )
|
||||
|
|
|
@ -41,7 +41,7 @@
|
|||
|
||||
namespace TimidityPlus
|
||||
{
|
||||
std::mutex CvarCritSec;
|
||||
std::mutex ConfigMutex;
|
||||
bool timidity_modulation_wheel = true;
|
||||
bool timidity_portamento = false;
|
||||
int timidity_reverb = 0;
|
||||
|
@ -4997,7 +4997,7 @@ int Player::compute_data(float *buffer, int32_t count)
|
|||
{
|
||||
if (count == 0) return RC_OK;
|
||||
|
||||
std::lock_guard<std::mutex> lock(CvarCritSec);
|
||||
std::lock_guard<std::mutex> lock(ConfigMutex);
|
||||
|
||||
if (last_reverb_setting != timidity_reverb)
|
||||
{
|
||||
|
|
|
@ -125,7 +125,7 @@
|
|||
namespace TimidityPlus
|
||||
{
|
||||
|
||||
extern std::mutex CvarCritSec;
|
||||
extern std::mutex ConfigMutex;
|
||||
extern bool timidity_modulation_wheel;
|
||||
extern bool timidity_portamento;
|
||||
extern int timidity_reverb;
|
||||
|
|
|
@ -1,7 +1,5 @@
|
|||
cmake_minimum_required( VERSION 2.8.7 )
|
||||
|
||||
make_release_only()
|
||||
|
||||
if( ZD_CMAKE_COMPILER_IS_GNUC_COMPATIBLE )
|
||||
set( CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wall -Wextra -Wno-unused-parameter -fomit-frame-pointer" )
|
||||
set( CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11" )
|
||||
|
|
|
@ -38,9 +38,18 @@
|
|||
#include "adlmidi.h"
|
||||
#include "cmdlib.h"
|
||||
#include "doomerrors.h"
|
||||
#include "timidity/timidity.h"
|
||||
#include "timidity/playmidi.h"
|
||||
#include "timidity/instrum.h"
|
||||
#include "timiditypp/controls.h"
|
||||
#include "timiditypp/timidity.h"
|
||||
#include "timiditypp/instrum.h"
|
||||
#include "v_text.h"
|
||||
#include "c_console.h"
|
||||
|
||||
#ifdef _WIN32
|
||||
// do this without including windows.h for this one single prototype
|
||||
#ifdef _WIN32
|
||||
extern "C" unsigned __stdcall GetSystemDirectoryA(char* lpBuffer, unsigned uSize);
|
||||
#endif // _WIN32
|
||||
|
||||
|
@ -55,7 +64,16 @@ static void CheckRestart(int devtype)
|
|||
ADLConfig adlConfig;
|
||||
FluidConfig fluidConfig;
|
||||
OPLMidiConfig oplMidiConfig;
|
||||
OpnConfig opnConfig;
|
||||
GUSConfig gusConfig;
|
||||
TimidityConfig timidityConfig;
|
||||
WildMidiConfig wildMidiConfig;
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
// ADL Midi device
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
CUSTOM_CVAR(Int, adl_chips_count, 6, CVAR_ARCHIVE | CVAR_GLOBALCONFIG)
|
||||
{
|
||||
|
@ -89,26 +107,51 @@ CUSTOM_CVAR(Int, adl_bank, 14, CVAR_ARCHIVE | CVAR_GLOBALCONFIG)
|
|||
|
||||
CUSTOM_CVAR(Bool, adl_use_custom_bank, 0, CVAR_ARCHIVE | CVAR_GLOBALCONFIG)
|
||||
{
|
||||
adlConfig.adl_use_custom_bank = self;
|
||||
CheckRestart(MDEV_ADL);
|
||||
}
|
||||
|
||||
CUSTOM_CVAR(String, adl_custom_bank, "", CVAR_ARCHIVE | CVAR_GLOBALCONFIG)
|
||||
{
|
||||
CheckRestart(MDEV_ADL);
|
||||
|
||||
//Resolve the path here, so that the renderer does not have to do the work itself and only needs to process final names.
|
||||
auto info = sfmanager.FindSoundFont(self, SF_WOPL);
|
||||
if (info == nullptr) adlConfig.adl_custom_bank = nullptr;
|
||||
else adlConfig.adl_custom_bank = info->mFilename;
|
||||
if (adl_use_custom_bank) CheckRestart(MDEV_ADL);
|
||||
}
|
||||
|
||||
void ADL_SetupConfig(ADLConfig *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 : 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, ADLMIDI_VolumeModel_DMX, CVAR_ARCHIVE | CVAR_GLOBALCONFIG)
|
||||
{
|
||||
adlConfig.adl_volume_model = self;
|
||||
CheckRestart(MDEV_ADL);
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
// Fluidsynth MIDI device
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
|
||||
#define FLUID_CHORUS_MOD_SINE 0
|
||||
#define FLUID_CHORUS_MOD_TRIANGLE 1
|
||||
#define FLUID_CHORUS_DEFAULT_TYPE FLUID_CHORUS_MOD_SINE
|
||||
|
@ -119,13 +162,13 @@ CUSTOM_CVAR(String, fluid_lib, "", CVAR_ARCHIVE|CVAR_GLOBALCONFIG)
|
|||
fluidConfig.fluid_lib = self; // only takes effect for next song.
|
||||
}
|
||||
|
||||
int BuildFluidPatchSetList(const char* patches, bool systemfallback)
|
||||
void Fluid_SetupConfig(FluidConfig *config, const char* patches, bool systemfallback)
|
||||
{
|
||||
fluidConfig.fluid_patchset.clear();
|
||||
//Resolve the paths here, the renderer will only get a final list of file names.
|
||||
auto info = sfmanager.FindSoundFont(patches, SF_SF2);
|
||||
if (info != nullptr) patches = info->mFilename.GetChars();
|
||||
|
||||
|
||||
int count;
|
||||
char* wpatches = strdup(patches);
|
||||
char* tok;
|
||||
|
@ -134,11 +177,9 @@ int BuildFluidPatchSetList(const char* patches, bool systemfallback)
|
|||
#else
|
||||
const char* const delim = ":";
|
||||
#endif
|
||||
|
||||
if (wpatches == NULL)
|
||||
|
||||
if (wpatches != NULL)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
tok = strtok(wpatches, delim);
|
||||
count = 0;
|
||||
while (tok != NULL)
|
||||
|
@ -159,7 +200,7 @@ int BuildFluidPatchSetList(const char* patches, bool systemfallback)
|
|||
}
|
||||
if (FileExists(path))
|
||||
{
|
||||
fluidConfig.fluid_patchset.push_back(path.GetChars());
|
||||
config->fluid_patchset.push_back(path.GetChars());
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -168,14 +209,15 @@ int BuildFluidPatchSetList(const char* patches, bool systemfallback)
|
|||
tok = strtok(NULL, delim);
|
||||
}
|
||||
free(wpatches);
|
||||
if (fluidConfig.fluid_patchset.size() > 0) return 1;
|
||||
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.
|
||||
return BuildFluidPatchSetList("/usr/share/sounds/sf2/FluidR3_GS.sf2:/usr/share/sounds/sf2/FluidR3_GM.sf2", false);
|
||||
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.
|
||||
|
@ -186,22 +228,21 @@ int BuildFluidPatchSetList(const char* patches, bool systemfallback)
|
|||
strcat(sysdir, "\\CT4MGM.SF2");
|
||||
if (FileExists(sysdir))
|
||||
{
|
||||
fluidConfig.fluid_patchset.push_back(sysdir);
|
||||
return 1;
|
||||
config->fluid_patchset.push_back(sysdir);
|
||||
return;
|
||||
}
|
||||
// Try again with CT2MGM.SF2
|
||||
sysdir[filepart + 3] = '2';
|
||||
if (FileExists(sysdir))
|
||||
{
|
||||
fluidConfig.fluid_patchset.push_back(sysdir);
|
||||
return 1;
|
||||
config->fluid_patchset.push_back(sysdir);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
CUSTOM_CVAR(String, fluid_patchset, "gzdoom", CVAR_ARCHIVE | CVAR_GLOBALCONFIG)
|
||||
|
@ -418,7 +459,11 @@ CUSTOM_CVAR(Int, fluid_chorus_type, FLUID_CHORUS_DEFAULT_TYPE, CVAR_ARCHIVE|CVAR
|
|||
}
|
||||
|
||||
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
// OPL MIDI device
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
CUSTOM_CVAR(Int, opl_numchips, 2, CVAR_ARCHIVE | CVAR_GLOBALCONFIG)
|
||||
{
|
||||
|
@ -440,10 +485,7 @@ CUSTOM_CVAR(Int, opl_numchips, 2, CVAR_ARCHIVE | CVAR_GLOBALCONFIG)
|
|||
|
||||
CUSTOM_CVAR(Int, opl_core, 0, CVAR_ARCHIVE | CVAR_GLOBALCONFIG)
|
||||
{
|
||||
if (currSong != nullptr && currSong->GetDeviceType() == MDEV_OPL)
|
||||
{
|
||||
MIDIDeviceChanged(-1, true);
|
||||
}
|
||||
CheckRestart(MDEV_OPL);
|
||||
}
|
||||
|
||||
CUSTOM_CVAR(Bool, opl_fullpan, true, CVAR_ARCHIVE | CVAR_GLOBALCONFIG)
|
||||
|
@ -451,7 +493,7 @@ CUSTOM_CVAR(Bool, opl_fullpan, true, CVAR_ARCHIVE | CVAR_GLOBALCONFIG)
|
|||
oplMidiConfig.fullpan = self;
|
||||
}
|
||||
|
||||
void LoadGenMidi()
|
||||
void OPL_SetupConfig(OPLMidiConfig *config, const char *args)
|
||||
{
|
||||
// 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.
|
||||
|
@ -463,11 +505,414 @@ void LoadGenMidi()
|
|||
data.Read(filehdr, 8);
|
||||
if (memcmp(filehdr, "#OPL_II#", 8)) throw std::runtime_error("Corrupt GENMIDI lump");
|
||||
data.Read(oplMidiConfig.OPLinstruments, sizeof(GenMidiInstrument) * GENMIDI_NUM_TOTAL);
|
||||
|
||||
config->core = opl_core;
|
||||
if (args != NULL && *args >= '0' && *args < '4') config->core = *args - '0';
|
||||
}
|
||||
|
||||
int getOPLCore(const char* args)
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
// OPN MIDI device
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
|
||||
CUSTOM_CVAR(Int, opn_chips_count, 8, CVAR_ARCHIVE | CVAR_GLOBALCONFIG)
|
||||
{
|
||||
int current_opl_core = opl_core;
|
||||
if (args != NULL && *args >= '0' && *args < '4') current_opl_core = *args - '0';
|
||||
return current_opl_core;
|
||||
opnConfig.opn_chips_count = self;
|
||||
CheckRestart(MDEV_OPN);
|
||||
}
|
||||
|
||||
CUSTOM_CVAR(Int, opn_emulator_id, 0, CVAR_ARCHIVE | CVAR_GLOBALCONFIG)
|
||||
{
|
||||
opnConfig.opn_emulator_id = self;
|
||||
CheckRestart(MDEV_OPN);
|
||||
|
||||
}
|
||||
|
||||
CUSTOM_CVAR(Bool, opn_run_at_pcm_rate, 0, CVAR_ARCHIVE | CVAR_GLOBALCONFIG)
|
||||
{
|
||||
opnConfig.opn_run_at_pcm_rate = self;
|
||||
CheckRestart(MDEV_OPN);
|
||||
|
||||
}
|
||||
|
||||
CUSTOM_CVAR(Bool, opn_fullpan, 1, CVAR_ARCHIVE | CVAR_GLOBALCONFIG)
|
||||
{
|
||||
opnConfig.opn_fullpan = self;
|
||||
CheckRestart(MDEV_OPN);
|
||||
|
||||
}
|
||||
|
||||
CUSTOM_CVAR(Bool, opn_use_custom_bank, 0, CVAR_ARCHIVE | CVAR_GLOBALCONFIG)
|
||||
{
|
||||
CheckRestart(MDEV_OPN);
|
||||
|
||||
}
|
||||
|
||||
CUSTOM_CVAR(String, opn_custom_bank, "", CVAR_ARCHIVE | CVAR_GLOBALCONFIG)
|
||||
{
|
||||
if (opn_use_custom_bank)
|
||||
{
|
||||
CheckRestart(MDEV_OPN);
|
||||
}
|
||||
}
|
||||
|
||||
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());
|
||||
}
|
||||
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
// GUS MIDI device
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
|
||||
CUSTOM_CVAR(String, midi_config, "gzdoom", CVAR_ARCHIVE | CVAR_GLOBALCONFIG)
|
||||
{
|
||||
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.
|
||||
{
|
||||
CheckRestart(MDEV_GUS);
|
||||
}
|
||||
|
||||
CUSTOM_CVAR(String, gus_patchdir, "", CVAR_ARCHIVE | CVAR_GLOBALCONFIG)
|
||||
{
|
||||
gusConfig.gus_patchdir = self;
|
||||
CheckRestart(MDEV_GUS);
|
||||
}
|
||||
|
||||
CUSTOM_CVAR(Int, midi_voices, 32, CVAR_ARCHIVE | CVAR_GLOBALCONFIG)
|
||||
{
|
||||
gusConfig.midi_voices = self;
|
||||
CheckRestart(MDEV_GUS);
|
||||
}
|
||||
|
||||
CUSTOM_CVAR(Int, gus_memsize, 0, CVAR_ARCHIVE | CVAR_GLOBALCONFIG)
|
||||
{
|
||||
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");
|
||||
static_assert(Timidity::CMSG_WARNING == TimidityPlus::CMSG_WARNING, "Timidity constant mismatch");
|
||||
static_assert(Timidity::CMSG_INFO == TimidityPlus::CMSG_INFO, "Timidity constant mismatch");
|
||||
static_assert(Timidity::VERB_DEBUG == TimidityPlus::VERB_DEBUG, "Timidity constant mismatch");
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
// 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;
|
||||
}
|
||||
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
// CVar interface to configurable parameters
|
||||
//
|
||||
// Timidity++ uses a static global set of configuration variables
|
||||
// THese can be changed while the synth is playing but need synchronization.
|
||||
//
|
||||
// Currently the synth is not fully 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;
|
||||
}
|
||||
|
||||
CUSTOM_CVAR(Bool, timidity_modulation_wheel, true, CVAR_ARCHIVE | CVAR_GLOBALCONFIG)
|
||||
{
|
||||
ChangeVarSync(TimidityPlus::timidity_modulation_wheel, *self);
|
||||
}
|
||||
|
||||
CUSTOM_CVAR(Bool, timidity_portamento, true, CVAR_ARCHIVE | CVAR_GLOBALCONFIG)
|
||||
{
|
||||
ChangeVarSync(TimidityPlus::timidity_portamento, *self);
|
||||
}
|
||||
/*
|
||||
* 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
|
||||
*/
|
||||
EXTERN_CVAR(Int, timidity_reverb_level)
|
||||
EXTERN_CVAR(Int, timidity_reverb)
|
||||
|
||||
static void SetReverb()
|
||||
{
|
||||
int value = 0;
|
||||
int mode = timidity_reverb;
|
||||
int level = timidity_reverb_level;
|
||||
|
||||
if (mode == 0 || level == 0) value = mode;
|
||||
else value = (mode - 1) * -128 - level;
|
||||
ChangeVarSync(TimidityPlus::timidity_reverb, value);
|
||||
}
|
||||
|
||||
CUSTOM_CVAR(Int, timidity_reverb, 0, CVAR_ARCHIVE | CVAR_GLOBALCONFIG)
|
||||
{
|
||||
if (self < 0 || self > 4) self = 0;
|
||||
else SetReverb();
|
||||
}
|
||||
|
||||
CUSTOM_CVAR(Int, timidity_reverb_level, 0, CVAR_ARCHIVE | CVAR_GLOBALCONFIG)
|
||||
{
|
||||
if (self < 0 || self > 127) self = 0;
|
||||
else SetReverb();
|
||||
}
|
||||
|
||||
CUSTOM_CVAR(Int, timidity_chorus, 0, CVAR_ARCHIVE | CVAR_GLOBALCONFIG)
|
||||
{
|
||||
ChangeVarSync(TimidityPlus::timidity_chorus, *self);
|
||||
}
|
||||
|
||||
CUSTOM_CVAR(Bool, timidity_surround_chorus, false, CVAR_ARCHIVE | CVAR_GLOBALCONFIG)
|
||||
{
|
||||
ChangeVarSync(TimidityPlus::timidity_surround_chorus, *self);
|
||||
CheckRestart(MDEV_TIMIDITY);
|
||||
}
|
||||
|
||||
CUSTOM_CVAR(Bool, timidity_channel_pressure, false, CVAR_ARCHIVE | CVAR_GLOBALCONFIG)
|
||||
{
|
||||
ChangeVarSync(TimidityPlus::timidity_channel_pressure, *self);
|
||||
}
|
||||
|
||||
CUSTOM_CVAR(Int, timidity_lpf_def, true, CVAR_ARCHIVE | CVAR_GLOBALCONFIG)
|
||||
{
|
||||
ChangeVarSync(TimidityPlus::timidity_lpf_def, *self);
|
||||
}
|
||||
|
||||
CUSTOM_CVAR(Bool, timidity_temper_control, true, CVAR_ARCHIVE | CVAR_GLOBALCONFIG)
|
||||
{
|
||||
ChangeVarSync(TimidityPlus::timidity_temper_control, *self);
|
||||
}
|
||||
|
||||
CUSTOM_CVAR(Bool, timidity_modulation_envelope, true, CVAR_ARCHIVE | CVAR_GLOBALCONFIG)
|
||||
{
|
||||
ChangeVarSync(TimidityPlus::timidity_modulation_envelope, *self);
|
||||
CheckRestart(MDEV_TIMIDITY);
|
||||
}
|
||||
|
||||
CUSTOM_CVAR(Bool, timidity_overlap_voice_allow, true, CVAR_ARCHIVE | CVAR_GLOBALCONFIG)
|
||||
{
|
||||
ChangeVarSync(TimidityPlus::timidity_overlap_voice_allow, *self);
|
||||
}
|
||||
|
||||
CUSTOM_CVAR(Bool, timidity_drum_effect, false, CVAR_ARCHIVE | CVAR_GLOBALCONFIG)
|
||||
{
|
||||
ChangeVarSync(TimidityPlus::timidity_drum_effect, *self);
|
||||
}
|
||||
|
||||
CUSTOM_CVAR(Bool, timidity_pan_delay, false, CVAR_ARCHIVE | CVAR_GLOBALCONFIG)
|
||||
{
|
||||
ChangeVarSync(TimidityPlus::timidity_pan_delay, *self);
|
||||
}
|
||||
|
||||
CUSTOM_CVAR(Float, timidity_drum_power, 1.0, CVAR_ARCHIVE | CVAR_GLOBALCONFIG) /* 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);
|
||||
}
|
||||
CUSTOM_CVAR(Int, timidity_key_adjust, 0, CVAR_ARCHIVE | CVAR_GLOBALCONFIG)
|
||||
{
|
||||
if (self < -24) self = -24;
|
||||
else if (self > 24) self = 24;
|
||||
ChangeVarSync(TimidityPlus::timidity_key_adjust, *self);
|
||||
}
|
||||
// For testing mainly.
|
||||
CUSTOM_CVAR(Float, timidity_tempo_adjust, 1, CVAR_ARCHIVE | CVAR_GLOBALCONFIG)
|
||||
{
|
||||
if (self < 0.25) self = 0.25;
|
||||
else if (self > 10) self = 10;
|
||||
ChangeVarSync(TimidityPlus::timidity_tempo_adjust, *self);
|
||||
}
|
||||
|
||||
CUSTOM_CVAR(Float, min_sustain_time, 5000, CVAR_ARCHIVE | CVAR_GLOBALCONFIG)
|
||||
{
|
||||
if (self < 0) self = 0;
|
||||
ChangeVarSync(TimidityPlus::min_sustain_time, *self);
|
||||
}
|
||||
|
||||
// Config file to use
|
||||
CUSTOM_CVAR(String, timidity_config, "gzdoom", CVAR_ARCHIVE | CVAR_GLOBALCONFIG)
|
||||
{
|
||||
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
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
// WildMidi
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
CUSTOM_CVAR(String, wildmidi_config, "", CVAR_ARCHIVE | CVAR_GLOBALCONFIG)
|
||||
{
|
||||
CheckRestart(MDEV_WILDMIDI);
|
||||
}
|
||||
|
||||
CUSTOM_CVAR(Bool, wildmidi_reverb, false, CVAR_ARCHIVE | CVAR_GLOBALCONFIG | CVAR_NOINITCALL)
|
||||
{
|
||||
if (currSong != NULL)
|
||||
currSong->ChangeSettingInt("wildmidi.reverb", self ? WildMidi::WM_MO_REVERB : 0);
|
||||
wildMidiConfig.reverb = self;
|
||||
}
|
||||
|
||||
CUSTOM_CVAR(Bool, wildmidi_enhanced_resampling, true, CVAR_ARCHIVE | CVAR_GLOBALCONFIG | CVAR_NOINITCALL)
|
||||
{
|
||||
if (currSong != NULL)
|
||||
currSong->ChangeSettingInt("wildmidi.resampling", self ? WildMidi::WM_MO_ENHANCED_RESAMPLING : 0);
|
||||
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
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
|
|
|
@ -41,7 +41,7 @@ class ADLMIDIDevice : public SoftSynthMIDIDevice
|
|||
{
|
||||
struct ADL_MIDIPlayer *Renderer;
|
||||
public:
|
||||
ADLMIDIDevice(const char *args, const ADLConfig *config);
|
||||
ADLMIDIDevice(const ADLConfig *config);
|
||||
~ADLMIDIDevice();
|
||||
|
||||
int Open(MidiCallback, void *userdata);
|
||||
|
@ -54,7 +54,7 @@ protected:
|
|||
void ComputeOutput(float *buffer, int len);
|
||||
|
||||
private:
|
||||
int LoadCustomBank(const char *bankfile, const ADLConfig *config);
|
||||
int LoadCustomBank(const ADLConfig *config);
|
||||
};
|
||||
|
||||
|
||||
|
@ -75,7 +75,7 @@ enum
|
|||
//
|
||||
//==========================================================================
|
||||
|
||||
ADLMIDIDevice::ADLMIDIDevice(const char *args, const ADLConfig *config)
|
||||
ADLMIDIDevice::ADLMIDIDevice(const ADLConfig *config)
|
||||
:SoftSynthMIDIDevice(44100)
|
||||
{
|
||||
Renderer = adl_init(44100); // todo: make it configurable
|
||||
|
@ -83,7 +83,7 @@ ADLMIDIDevice::ADLMIDIDevice(const char *args, const ADLConfig *config)
|
|||
{
|
||||
adl_switchEmulator(Renderer, config->adl_emulator_id);
|
||||
adl_setRunAtPcmRate(Renderer, config->adl_run_at_pcm_rate);
|
||||
if (!LoadCustomBank(config->adl_custom_bank, config))
|
||||
if (!LoadCustomBank(config))
|
||||
adl_setBank(Renderer, config->adl_bank);
|
||||
adl_setNumChips(Renderer, config->adl_chips_count);
|
||||
adl_setVolumeRangeModel(Renderer, config->adl_volume_model);
|
||||
|
@ -116,9 +116,10 @@ ADLMIDIDevice::~ADLMIDIDevice()
|
|||
//
|
||||
//==========================================================================
|
||||
|
||||
int ADLMIDIDevice::LoadCustomBank(const char *bankfile, const ADLConfig *config)
|
||||
int ADLMIDIDevice::LoadCustomBank(const ADLConfig *config)
|
||||
{
|
||||
if(!config->adl_use_custom_bank || !bankfile || !*bankfile)
|
||||
const char *bankfile = config->adl_custom_bank.c_str();
|
||||
if(!*bankfile)
|
||||
return 0;
|
||||
return (adl_openBankFile(Renderer, bankfile) == 0);
|
||||
}
|
||||
|
@ -225,9 +226,9 @@ void ADLMIDIDevice::ComputeOutput(float *buffer, int len)
|
|||
//
|
||||
//==========================================================================
|
||||
|
||||
MIDIDevice *CreateADLMIDIDevice(const char *args, const ADLConfig *config)
|
||||
MIDIDevice *CreateADLMIDIDevice(const ADLConfig *config)
|
||||
{
|
||||
return new ADLMIDIDevice(args, config);
|
||||
return new ADLMIDIDevice(config);
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -51,7 +51,7 @@ struct fluid_synth_t;
|
|||
class FluidSynthMIDIDevice : public SoftSynthMIDIDevice
|
||||
{
|
||||
public:
|
||||
FluidSynthMIDIDevice(int samplerate, FluidConfig *config, int (*printfunc_)(const char *, ...));
|
||||
FluidSynthMIDIDevice(int samplerate, const FluidConfig *config, int (*printfunc_)(const char *, ...));
|
||||
~FluidSynthMIDIDevice();
|
||||
|
||||
int Open(MidiCallback, void *userdata);
|
||||
|
@ -65,7 +65,7 @@ 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(FluidConfig *config);
|
||||
int LoadPatchSets(const FluidConfig *config);
|
||||
|
||||
fluid_settings_t *FluidSettings;
|
||||
fluid_synth_t *FluidSynth;
|
||||
|
@ -162,7 +162,7 @@ const char *BaseFileSearch(const char *file, const char *ext, bool lookfirstinpr
|
|||
//
|
||||
//==========================================================================
|
||||
|
||||
FluidSynthMIDIDevice::FluidSynthMIDIDevice(int samplerate, FluidConfig *config, int (*printfunc_)(const char*, ...) = nullptr)
|
||||
FluidSynthMIDIDevice::FluidSynthMIDIDevice(int samplerate, const FluidConfig *config, int (*printfunc_)(const char*, ...) = nullptr)
|
||||
: SoftSynthMIDIDevice(samplerate <= 0? config->fluid_samplerate : samplerate, 22050, 96000)
|
||||
{
|
||||
// These are needed for changing the settings. If something posts a transient config in here we got no way to retrieve the values afterward.
|
||||
|
@ -180,7 +180,7 @@ FluidSynthMIDIDevice::FluidSynthMIDIDevice(int samplerate, FluidConfig *config,
|
|||
FluidSynth = NULL;
|
||||
FluidSettings = NULL;
|
||||
#ifdef DYN_FLUIDSYNTH
|
||||
if (!LoadFluidSynth(config->fluid_lib))
|
||||
if (!LoadFluidSynth(config->fluid_lib.c_str()))
|
||||
{
|
||||
throw std::runtime_error("Failed to load FluidSynth.\n");
|
||||
}
|
||||
|
@ -348,7 +348,7 @@ void FluidSynthMIDIDevice::ComputeOutput(float *buffer, int len)
|
|||
//
|
||||
//==========================================================================
|
||||
|
||||
int FluidSynthMIDIDevice::LoadPatchSets(FluidConfig *config)
|
||||
int FluidSynthMIDIDevice::LoadPatchSets(const FluidConfig *config)
|
||||
{
|
||||
int count = 0;
|
||||
for (auto& file : config->fluid_patchset)
|
||||
|
@ -621,7 +621,7 @@ void FluidSynthMIDIDevice::UnloadFluidSynth()
|
|||
//
|
||||
//==========================================================================
|
||||
|
||||
MIDIDevice *CreateFluidSynthMIDIDevice(int samplerate, FluidConfig *config, int (*printfunc)(const char*, ...))
|
||||
MIDIDevice *CreateFluidSynthMIDIDevice(int samplerate, const FluidConfig *config, int (*printfunc)(const char*, ...))
|
||||
{
|
||||
return new FluidSynthMIDIDevice(samplerate, config, printfunc);
|
||||
}
|
||||
|
|
|
@ -55,7 +55,7 @@
|
|||
class OPLMIDIDevice : public SoftSynthMIDIDevice, protected OPLmusicBlock
|
||||
{
|
||||
public:
|
||||
OPLMIDIDevice(OPLMidiConfig *config);
|
||||
OPLMIDIDevice(const OPLMidiConfig *config);
|
||||
int Open(MidiCallback, void *userdata);
|
||||
void Close();
|
||||
int GetTechnology() const;
|
||||
|
@ -82,7 +82,7 @@ protected:
|
|||
//
|
||||
//==========================================================================
|
||||
|
||||
OPLMIDIDevice::OPLMIDIDevice(OPLMidiConfig *config)
|
||||
OPLMIDIDevice::OPLMIDIDevice(const OPLMidiConfig *config)
|
||||
: SoftSynthMIDIDevice((int)OPL_SAMPLE_RATE), OPLmusicBlock(config->core, config->numchips)
|
||||
{
|
||||
FullPan = config->fullpan;
|
||||
|
@ -314,7 +314,7 @@ FString OPLMIDIDevice::GetStats()
|
|||
return out;
|
||||
}
|
||||
|
||||
MIDIDevice* CreateOplMIDIDevice(OPLMidiConfig* config)
|
||||
MIDIDevice* CreateOplMIDIDevice(const OPLMidiConfig* config)
|
||||
{
|
||||
return new OPLMIDIDevice(config);
|
||||
}
|
||||
|
|
|
@ -44,7 +44,7 @@ class OPNMIDIDevice : public SoftSynthMIDIDevice
|
|||
{
|
||||
struct OPN2_MIDIPlayer *Renderer;
|
||||
public:
|
||||
OPNMIDIDevice(const char *args);
|
||||
OPNMIDIDevice(const OpnConfig *config);
|
||||
~OPNMIDIDevice();
|
||||
|
||||
|
||||
|
@ -72,53 +72,6 @@ enum
|
|||
ME_PITCHWHEEL = 0xE0
|
||||
};
|
||||
|
||||
CUSTOM_CVAR(Int, opn_chips_count, 8, CVAR_ARCHIVE | CVAR_GLOBALCONFIG)
|
||||
{
|
||||
if (currSong != nullptr && currSong->GetDeviceType() == MDEV_OPN)
|
||||
{
|
||||
MIDIDeviceChanged(-1, true);
|
||||
}
|
||||
}
|
||||
|
||||
CUSTOM_CVAR(Int, opn_emulator_id, 0, CVAR_ARCHIVE | CVAR_GLOBALCONFIG)
|
||||
{
|
||||
if (currSong != nullptr && currSong->GetDeviceType() == MDEV_OPN)
|
||||
{
|
||||
MIDIDeviceChanged(-1, true);
|
||||
}
|
||||
}
|
||||
|
||||
CUSTOM_CVAR(Bool, opn_run_at_pcm_rate, 0, CVAR_ARCHIVE | CVAR_GLOBALCONFIG)
|
||||
{
|
||||
if (currSong != nullptr && currSong->GetDeviceType() == MDEV_OPN)
|
||||
{
|
||||
MIDIDeviceChanged(-1, true);
|
||||
}
|
||||
}
|
||||
|
||||
CUSTOM_CVAR(Bool, opn_fullpan, 1, CVAR_ARCHIVE | CVAR_GLOBALCONFIG)
|
||||
{
|
||||
if (currSong != nullptr && currSong->GetDeviceType() == MDEV_OPN)
|
||||
{
|
||||
MIDIDeviceChanged(-1, true);
|
||||
}
|
||||
}
|
||||
|
||||
CUSTOM_CVAR(Bool, opn_use_custom_bank, 0, CVAR_ARCHIVE | CVAR_GLOBALCONFIG)
|
||||
{
|
||||
if (currSong != nullptr && currSong->GetDeviceType() == MDEV_OPN)
|
||||
{
|
||||
MIDIDeviceChanged(-1, true);
|
||||
}
|
||||
}
|
||||
|
||||
CUSTOM_CVAR(String, opn_custom_bank, "", CVAR_ARCHIVE | CVAR_GLOBALCONFIG)
|
||||
{
|
||||
if (opn_use_custom_bank && currSong != nullptr && currSong->GetDeviceType() == MDEV_OPN)
|
||||
{
|
||||
MIDIDeviceChanged(-1, true);
|
||||
}
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
|
@ -126,27 +79,30 @@ CUSTOM_CVAR(String, opn_custom_bank, "", CVAR_ARCHIVE | CVAR_GLOBALCONFIG)
|
|||
//
|
||||
//==========================================================================
|
||||
|
||||
OPNMIDIDevice::OPNMIDIDevice(const char *args)
|
||||
OPNMIDIDevice::OPNMIDIDevice(const OpnConfig *config)
|
||||
:SoftSynthMIDIDevice(44100)
|
||||
{
|
||||
Renderer = opn2_init(44100); // todo: make it configurable
|
||||
if (Renderer != nullptr)
|
||||
{
|
||||
if (!LoadCustomBank(opn_custom_bank))
|
||||
if (!LoadCustomBank(config->opn_custom_bank.c_str()))
|
||||
{
|
||||
int lump = Wads.CheckNumForFullName("xg.wopn");
|
||||
if (lump < 0)
|
||||
if(config->default_bank.size() == 0)
|
||||
{
|
||||
I_Error("No OPN bank found");
|
||||
opn2_close(Renderer);
|
||||
throw std::runtime_error("No OPN bank found");
|
||||
}
|
||||
FMemLump data = Wads.ReadLump(lump);
|
||||
opn2_openBankData(Renderer, data.GetMem(), (long)data.GetSize());
|
||||
opn2_openBankData(Renderer, config->default_bank.data(), (long)config->default_bank.size());
|
||||
}
|
||||
|
||||
opn2_switchEmulator(Renderer, (int)opn_emulator_id);
|
||||
opn2_setRunAtPcmRate(Renderer, (int)opn_run_at_pcm_rate);
|
||||
opn2_setNumChips(Renderer, opn_chips_count);
|
||||
opn2_setSoftPanEnabled(Renderer, (int)opn_fullpan);
|
||||
opn2_switchEmulator(Renderer, (int)config->opn_emulator_id);
|
||||
opn2_setRunAtPcmRate(Renderer, (int)config->opn_run_at_pcm_rate);
|
||||
opn2_setNumChips(Renderer, config->opn_chips_count);
|
||||
opn2_setSoftPanEnabled(Renderer, (int)config->opn_fullpan);
|
||||
}
|
||||
else
|
||||
{
|
||||
throw std::runtime_error("Unable to create OPN renderer.");
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -177,12 +133,8 @@ OPNMIDIDevice::~OPNMIDIDevice()
|
|||
|
||||
int OPNMIDIDevice::LoadCustomBank(const char *bankfile)
|
||||
{
|
||||
if(!opn_use_custom_bank)
|
||||
if(!bankfile || !*bankfile)
|
||||
return 0;
|
||||
auto info = sfmanager.FindSoundFont(bankfile, SF_WOPN);
|
||||
if(info == nullptr)
|
||||
return 0;
|
||||
bankfile = info->mFilename.GetChars();
|
||||
return (opn2_openBankFile(Renderer, bankfile) == 0);
|
||||
}
|
||||
|
||||
|
@ -283,9 +235,9 @@ void OPNMIDIDevice::ComputeOutput(float *buffer, int len)
|
|||
//
|
||||
//==========================================================================
|
||||
|
||||
MIDIDevice *CreateOPNMIDIDevice(const char *args)
|
||||
MIDIDevice *CreateOPNMIDIDevice(const OpnConfig *config)
|
||||
{
|
||||
return new OPNMIDIDevice(args);
|
||||
return new OPNMIDIDevice(config);
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -54,7 +54,7 @@
|
|||
|
||||
// PUBLIC DATA DEFINITIONS -------------------------------------------------
|
||||
|
||||
CVAR(Bool, synth_watch, false, 0)
|
||||
//CVAR(Bool, synth_watch, false, 0)
|
||||
|
||||
// CODE --------------------------------------------------------------------
|
||||
|
||||
|
@ -72,7 +72,7 @@ SoftSynthMIDIDevice::SoftSynthMIDIDevice(int samplerate, int minrate, int maxrat
|
|||
Events = NULL;
|
||||
Started = false;
|
||||
SampleRate = samplerate;
|
||||
if (SampleRate < minrate || SampleRate > maxrate) SampleRate = GSnd != NULL ? clamp((int)GSnd->GetOutputRate(), minrate, maxrate) : 44100;
|
||||
if (SampleRate < minrate || SampleRate > maxrate) SampleRate = 44100;
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
|
@ -318,6 +318,7 @@ int SoftSynthMIDIDevice::PlayTick()
|
|||
int parm2 = (event[2] >> 16) & 0x7f;
|
||||
HandleEvent(status, parm1, parm2);
|
||||
|
||||
#if 0
|
||||
if (synth_watch)
|
||||
{
|
||||
static const char *const commands[8] =
|
||||
|
@ -339,6 +340,7 @@ int SoftSynthMIDIDevice::PlayTick()
|
|||
fputs(buffer, stderr);
|
||||
#endif
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
// Advance to next event.
|
||||
|
|
|
@ -56,72 +56,6 @@
|
|||
|
||||
// PRIVATE DATA DEFINITIONS ------------------------------------------------
|
||||
|
||||
// CVARS for this device - all of them require a device reset --------------------------------------------
|
||||
|
||||
static void CheckRestart()
|
||||
{
|
||||
if (currSong != nullptr && currSong->GetDeviceType() == MDEV_GUS)
|
||||
{
|
||||
MIDIDeviceChanged(-1, true);
|
||||
}
|
||||
}
|
||||
|
||||
CUSTOM_CVAR(String, midi_config, "gzdoom", CVAR_ARCHIVE | CVAR_GLOBALCONFIG)
|
||||
{
|
||||
CheckRestart();
|
||||
}
|
||||
|
||||
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.
|
||||
{
|
||||
CheckRestart();
|
||||
}
|
||||
|
||||
CUSTOM_CVAR(String, gus_patchdir, "", CVAR_ARCHIVE | CVAR_GLOBALCONFIG)
|
||||
{
|
||||
CheckRestart();
|
||||
}
|
||||
|
||||
CUSTOM_CVAR(Int, midi_voices, 32, CVAR_ARCHIVE | CVAR_GLOBALCONFIG)
|
||||
{
|
||||
CheckRestart();
|
||||
}
|
||||
|
||||
CUSTOM_CVAR(Int, gus_memsize, 0, CVAR_ARCHIVE | CVAR_GLOBALCONFIG)
|
||||
{
|
||||
CheckRestart();
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
// Error printing override to redirect to the internal console instead of stdout.
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
static void gzdoom_ctl_cmsg(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;
|
||||
}
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
|
@ -133,8 +67,9 @@ namespace Timidity { struct Renderer; }
|
|||
|
||||
class TimidityMIDIDevice : public SoftSynthMIDIDevice
|
||||
{
|
||||
void LoadInstruments(GUSConfig *config);
|
||||
public:
|
||||
TimidityMIDIDevice(const char *args, int samplerate);
|
||||
TimidityMIDIDevice(GUSConfig *config, int samplerate);
|
||||
~TimidityMIDIDevice();
|
||||
|
||||
int Open(MidiCallback, void *userdata);
|
||||
|
@ -143,82 +78,72 @@ public:
|
|||
|
||||
protected:
|
||||
Timidity::Renderer *Renderer;
|
||||
std::shared_ptr<Timidity::Instruments> instruments; // The device needs to hold a reference to this while the renderer is in use.
|
||||
|
||||
void HandleEvent(int status, int parm1, int parm2);
|
||||
void HandleLongEvent(const uint8_t *data, int len);
|
||||
void ComputeOutput(float *buffer, int len);
|
||||
void LoadConfig(const char *);
|
||||
};
|
||||
|
||||
|
||||
// DATA DEFINITIONS -------------------------------------------------
|
||||
|
||||
static FString currentConfig;
|
||||
static Timidity::Instruments* instruments;
|
||||
|
||||
// CODE --------------------------------------------------------------------
|
||||
|
||||
void TimidityMIDIDevice::LoadConfig(const char *config)
|
||||
|
||||
void TimidityMIDIDevice::LoadInstruments(GUSConfig *config)
|
||||
{
|
||||
if ((midi_dmxgus && *config == 0) || !stricmp(config, "DMXGUS"))
|
||||
if (config->dmxgus.size())
|
||||
{
|
||||
if (currentConfig.CompareNoCase("DMXGUS") == 0) return; // aleady loaded
|
||||
int lump = Wads.CheckNumForName("DMXGUS");
|
||||
if (lump == -1) lump = Wads.CheckNumForName("DMXGUSC");
|
||||
if (lump >= 0)
|
||||
// Check if we got some GUS data before using it.
|
||||
FString ultradir = getenv("ULTRADIR");
|
||||
if (ultradir.IsNotEmpty() || config->gus_patchdir.length() != 0)
|
||||
{
|
||||
auto data = Wads.OpenLumpReader(lump);
|
||||
if (data.GetLength() > 0)
|
||||
FileReader fr;
|
||||
fr.OpenMemory((const char *)config->dmxgus.data(), (long)config->dmxgus.size());
|
||||
auto psreader = new FPatchSetReader(fr);
|
||||
|
||||
// The GUS put its patches in %ULTRADIR%/MIDI so we can try that
|
||||
if (ultradir.IsNotEmpty())
|
||||
{
|
||||
// Check if we got some GUS data before using it.
|
||||
FString ultradir = getenv("ULTRADIR");
|
||||
if (ultradir.IsNotEmpty() || *(*gus_patchdir) != 0)
|
||||
{
|
||||
|
||||
auto psreader = new FPatchSetReader(data);
|
||||
|
||||
// The GUS put its patches in %ULTRADIR%/MIDI so we can try that
|
||||
if (ultradir.IsNotEmpty())
|
||||
{
|
||||
ultradir += "/midi";
|
||||
psreader->AddPath(ultradir);
|
||||
}
|
||||
if (instruments) delete instruments;
|
||||
instruments = new Timidity::Instruments(psreader);
|
||||
|
||||
// Load DMXGUS lump and patches from gus_patchdir
|
||||
if (*(*gus_patchdir) != 0) psreader->AddPath(gus_patchdir);
|
||||
|
||||
if (instruments->LoadDMXGUS(gus_memsize) < 0)
|
||||
{
|
||||
delete instruments;
|
||||
instruments = nullptr;
|
||||
I_Error("Unable to initialize instruments for GUS MIDI device");
|
||||
}
|
||||
currentConfig = "DMXGUS";
|
||||
}
|
||||
ultradir += "/midi";
|
||||
psreader->timidity_add_path(ultradir);
|
||||
}
|
||||
// Load DMXGUS lump and patches from gus_patchdir
|
||||
if (config->gus_patchdir.length() != 0) psreader->timidity_add_path(config->gus_patchdir.c_str());
|
||||
|
||||
config->instruments.reset(new Timidity::Instruments(psreader));
|
||||
bool success = config->instruments->LoadDMXGUS(config->gus_memsize) >= 0;
|
||||
|
||||
config->dmxgus.clear();
|
||||
|
||||
if (success)
|
||||
{
|
||||
config->loadedConfig = "DMXGUS";
|
||||
return;
|
||||
}
|
||||
}
|
||||
config->loadedConfig = "";
|
||||
config->instruments.reset();
|
||||
throw std::runtime_error("Unable to initialize DMXGUS for GUS MIDI device");
|
||||
}
|
||||
if (*config == 0) config = midi_config;
|
||||
if (currentConfig.CompareNoCase(config) == 0) return;
|
||||
if (instruments) delete instruments;
|
||||
instruments = nullptr;
|
||||
|
||||
auto reader = sfmanager.OpenSoundFont(config, SF_GUS | SF_SF2);
|
||||
if (reader == nullptr)
|
||||
else if (config->reader)
|
||||
{
|
||||
I_Error("GUS: %s: Unable to load sound font\n",config);
|
||||
config->loadedConfig = config->readerName;
|
||||
config->instruments.reset(new Timidity::Instruments(config->reader));
|
||||
bool err = config->instruments->LoadConfig() < 0;
|
||||
config->reader = nullptr;
|
||||
|
||||
if (err)
|
||||
{
|
||||
config->instruments.reset();
|
||||
config->loadedConfig = "";
|
||||
throw std::runtime_error("Unable to initialize instruments for GUS MIDI device");
|
||||
}
|
||||
}
|
||||
|
||||
instruments = new Timidity::Instruments(reader);
|
||||
if (instruments->LoadConfig() < 0)
|
||||
else if (config->instruments == nullptr)
|
||||
{
|
||||
delete instruments;
|
||||
instruments = nullptr;
|
||||
I_Error("Unable to initialize instruments for GUS MIDI device");
|
||||
throw std::runtime_error("No instruments set for GUS device");
|
||||
}
|
||||
currentConfig = config;
|
||||
instruments = config->instruments;
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
|
@ -227,12 +152,11 @@ void TimidityMIDIDevice::LoadConfig(const char *config)
|
|||
//
|
||||
//==========================================================================
|
||||
|
||||
TimidityMIDIDevice::TimidityMIDIDevice(const char *args, int samplerate)
|
||||
TimidityMIDIDevice::TimidityMIDIDevice(GUSConfig *config, int samplerate)
|
||||
: SoftSynthMIDIDevice(samplerate, 11025, 65535)
|
||||
{
|
||||
LoadConfig(args);
|
||||
Timidity::printMessage = gzdoom_ctl_cmsg;
|
||||
Renderer = new Timidity::Renderer((float)SampleRate, midi_voices, instruments);
|
||||
LoadInstruments(config);
|
||||
Renderer = new Timidity::Renderer((float)SampleRate, config->midi_voices, instruments.get());
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
|
@ -328,13 +252,7 @@ void TimidityMIDIDevice::ComputeOutput(float *buffer, int len)
|
|||
//
|
||||
//==========================================================================
|
||||
|
||||
MIDIDevice *CreateTimidityMIDIDevice(const char *args, int samplerate)
|
||||
MIDIDevice *CreateTimidityMIDIDevice(GUSConfig *config, int samplerate)
|
||||
{
|
||||
return new TimidityMIDIDevice(args, samplerate);
|
||||
}
|
||||
|
||||
void Timidity_Shutdown()
|
||||
{
|
||||
if (instruments) delete instruments;
|
||||
instruments = nullptr;
|
||||
return new TimidityMIDIDevice(config, samplerate);
|
||||
}
|
||||
|
|
|
@ -44,194 +44,19 @@
|
|||
#include "timiditypp/playmidi.h"
|
||||
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
// Error printing override to redirect to the internal console instead of stdout.
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
static void gzdoom_ctl_cmsg(int type, int verbosity_level, const char* fmt, ...)
|
||||
{
|
||||
if (verbosity_level >= TimidityPlus::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 TimidityPlus::CMSG_ERROR:
|
||||
Printf(TEXTCOLOR_RED "%s\n", msg.GetChars());
|
||||
break;
|
||||
|
||||
case TimidityPlus::CMSG_WARNING:
|
||||
Printf(TEXTCOLOR_YELLOW "%s\n", msg.GetChars());
|
||||
break;
|
||||
|
||||
case TimidityPlus::CMSG_INFO:
|
||||
DPrintf(DMSG_SPAMMY, "%s\n", msg.GetChars());
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
// CVar interface to configurable parameters
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
template<class T> void ChangeVarSync(T& var, T value)
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(TimidityPlus::CvarCritSec);
|
||||
var = value;
|
||||
}
|
||||
|
||||
CUSTOM_CVAR(Bool, timidity_modulation_wheel, true, CVAR_ARCHIVE | CVAR_GLOBALCONFIG)
|
||||
{
|
||||
ChangeVarSync(TimidityPlus::timidity_modulation_wheel, *self);
|
||||
}
|
||||
|
||||
CUSTOM_CVAR(Bool, timidity_portamento, true, CVAR_ARCHIVE | CVAR_GLOBALCONFIG)
|
||||
{
|
||||
ChangeVarSync(TimidityPlus::timidity_portamento, *self);
|
||||
}
|
||||
/*
|
||||
* 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
|
||||
*/
|
||||
EXTERN_CVAR(Int, timidity_reverb_level)
|
||||
EXTERN_CVAR(Int, timidity_reverb)
|
||||
|
||||
static void SetReverb()
|
||||
{
|
||||
int value = 0;
|
||||
int mode = timidity_reverb;
|
||||
int level = timidity_reverb_level;
|
||||
|
||||
if (mode == 0 || level == 0) value = mode;
|
||||
else value = (mode - 1) * -128 - level;
|
||||
ChangeVarSync(TimidityPlus::timidity_reverb, value);
|
||||
}
|
||||
|
||||
CUSTOM_CVAR(Int, timidity_reverb, 0, CVAR_ARCHIVE | CVAR_GLOBALCONFIG)
|
||||
{
|
||||
if (self < 0 || self > 4) self = 0;
|
||||
else SetReverb();
|
||||
}
|
||||
|
||||
CUSTOM_CVAR(Int, timidity_reverb_level, 0, CVAR_ARCHIVE | CVAR_GLOBALCONFIG)
|
||||
{
|
||||
if (self < 0 || self > 127) self = 0;
|
||||
else SetReverb();
|
||||
}
|
||||
|
||||
CUSTOM_CVAR(Int, timidity_chorus, 0, CVAR_ARCHIVE | CVAR_GLOBALCONFIG)
|
||||
{
|
||||
ChangeVarSync(TimidityPlus::timidity_chorus, *self);
|
||||
}
|
||||
|
||||
CUSTOM_CVAR(Bool, timidity_surround_chorus, false, CVAR_ARCHIVE | CVAR_GLOBALCONFIG)
|
||||
{
|
||||
if (currSong != nullptr && currSong->GetDeviceType() == MDEV_TIMIDITY)
|
||||
{
|
||||
MIDIDeviceChanged(-1, true);
|
||||
}
|
||||
ChangeVarSync(TimidityPlus::timidity_surround_chorus, *self);
|
||||
}
|
||||
|
||||
CUSTOM_CVAR(Bool, timidity_channel_pressure, false, CVAR_ARCHIVE | CVAR_GLOBALCONFIG)
|
||||
{
|
||||
ChangeVarSync(TimidityPlus::timidity_channel_pressure, *self);
|
||||
}
|
||||
|
||||
CUSTOM_CVAR(Int, timidity_lpf_def, true, CVAR_ARCHIVE | CVAR_GLOBALCONFIG)
|
||||
{
|
||||
ChangeVarSync(TimidityPlus::timidity_lpf_def, *self);
|
||||
}
|
||||
|
||||
CUSTOM_CVAR(Bool, timidity_temper_control, true, CVAR_ARCHIVE | CVAR_GLOBALCONFIG)
|
||||
{
|
||||
ChangeVarSync(TimidityPlus::timidity_temper_control, *self);
|
||||
}
|
||||
|
||||
CUSTOM_CVAR(Bool, timidity_modulation_envelope, true, CVAR_ARCHIVE | CVAR_GLOBALCONFIG)
|
||||
{
|
||||
ChangeVarSync(TimidityPlus::timidity_modulation_envelope, *self);
|
||||
if (currSong != nullptr && currSong->GetDeviceType() == MDEV_TIMIDITY)
|
||||
{
|
||||
MIDIDeviceChanged(-1, true);
|
||||
}
|
||||
}
|
||||
|
||||
CUSTOM_CVAR(Bool, timidity_overlap_voice_allow, true, CVAR_ARCHIVE | CVAR_GLOBALCONFIG)
|
||||
{
|
||||
ChangeVarSync(TimidityPlus::timidity_overlap_voice_allow, *self);
|
||||
}
|
||||
|
||||
CUSTOM_CVAR(Bool, timidity_drum_effect, false, CVAR_ARCHIVE | CVAR_GLOBALCONFIG)
|
||||
{
|
||||
ChangeVarSync(TimidityPlus::timidity_drum_effect, *self);
|
||||
}
|
||||
|
||||
CUSTOM_CVAR(Bool, timidity_pan_delay, false, CVAR_ARCHIVE | CVAR_GLOBALCONFIG)
|
||||
{
|
||||
ChangeVarSync(TimidityPlus::timidity_pan_delay, *self);
|
||||
}
|
||||
|
||||
CUSTOM_CVAR(Float, timidity_drum_power, 1.0, CVAR_ARCHIVE | CVAR_GLOBALCONFIG) /* 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);
|
||||
}
|
||||
CUSTOM_CVAR(Int, timidity_key_adjust, 0, CVAR_ARCHIVE | CVAR_GLOBALCONFIG)
|
||||
{
|
||||
if (self < -24) self = -24;
|
||||
else if (self > 24) self = 24;
|
||||
ChangeVarSync(TimidityPlus::timidity_key_adjust, *self);
|
||||
}
|
||||
// For testing mainly.
|
||||
CUSTOM_CVAR(Float, timidity_tempo_adjust, 1, CVAR_ARCHIVE | CVAR_GLOBALCONFIG)
|
||||
{
|
||||
if (self < 0.25) self = 0.25;
|
||||
else if (self > 10) self = 10;
|
||||
ChangeVarSync(TimidityPlus::timidity_tempo_adjust, *self);
|
||||
}
|
||||
|
||||
CUSTOM_CVAR(Float, min_sustain_time, 5000, CVAR_ARCHIVE | CVAR_GLOBALCONFIG)
|
||||
{
|
||||
if (self < 0) self = 0;
|
||||
ChangeVarSync(TimidityPlus::min_sustain_time, *self);
|
||||
}
|
||||
|
||||
|
||||
class TimidityPPMIDIDevice : public SoftSynthMIDIDevice
|
||||
{
|
||||
static TimidityPlus::Instruments *instruments;
|
||||
static FString configName;
|
||||
int sampletime;
|
||||
std::shared_ptr<TimidityPlus::Instruments> instruments;
|
||||
public:
|
||||
TimidityPPMIDIDevice(const char *args, int samplerate);
|
||||
TimidityPPMIDIDevice(TimidityConfig *config, int samplerate);
|
||||
~TimidityPPMIDIDevice();
|
||||
|
||||
int Open(MidiCallback, void *userdata);
|
||||
void PrecacheInstruments(const uint16_t *instruments, int count);
|
||||
//FString GetStats();
|
||||
int GetDeviceType() const override { return MDEV_TIMIDITY; }
|
||||
static void ClearInstruments()
|
||||
{
|
||||
if (instruments != nullptr) delete instruments;
|
||||
instruments = nullptr;
|
||||
}
|
||||
|
||||
double test[3] = { 0, 0, 0 };
|
||||
|
||||
|
@ -241,64 +66,50 @@ protected:
|
|||
void HandleEvent(int status, int parm1, int parm2);
|
||||
void HandleLongEvent(const uint8_t *data, int len);
|
||||
void ComputeOutput(float *buffer, int len);
|
||||
void LoadInstruments(TimidityConfig* config);
|
||||
};
|
||||
TimidityPlus::Instruments *TimidityPPMIDIDevice::instruments;
|
||||
FString TimidityPPMIDIDevice::configName;
|
||||
|
||||
// Config file to use
|
||||
CUSTOM_CVAR(String, timidity_config, "gzdoom", CVAR_ARCHIVE | CVAR_GLOBALCONFIG)
|
||||
//==========================================================================
|
||||
//
|
||||
//
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
void TimidityPPMIDIDevice::LoadInstruments(TimidityConfig* config)
|
||||
{
|
||||
if (currSong != nullptr && currSong->GetDeviceType() == MDEV_TIMIDITY)
|
||||
if (config->reader)
|
||||
{
|
||||
MIDIDeviceChanged(-1, true);
|
||||
config->loadedConfig = config->readerName;
|
||||
config->instruments.reset(new TimidityPlus::Instruments());
|
||||
bool success = config->instruments->load(config->reader);
|
||||
config->reader = nullptr;
|
||||
|
||||
if (!success)
|
||||
{
|
||||
config->instruments.reset();
|
||||
config->loadedConfig = "";
|
||||
throw std::runtime_error("Unable to initialize instruments for Timidity++ MIDI device");
|
||||
}
|
||||
}
|
||||
else if (config->instruments == nullptr)
|
||||
{
|
||||
throw std::runtime_error("No instruments set for Timidity++ device");
|
||||
}
|
||||
instruments = config->instruments;
|
||||
}
|
||||
|
||||
|
||||
CVAR (Int, timidity_frequency, 0, CVAR_ARCHIVE|CVAR_GLOBALCONFIG)
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
// TimidityPPMIDIDevice Constructor
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
TimidityPPMIDIDevice::TimidityPPMIDIDevice(const char *args, int samplerate)
|
||||
:SoftSynthMIDIDevice(samplerate <= 0? timidity_frequency : samplerate, 4000, 65000)
|
||||
TimidityPPMIDIDevice::TimidityPPMIDIDevice(TimidityConfig *config, int samplerate)
|
||||
:SoftSynthMIDIDevice(samplerate, 4000, 65000)
|
||||
{
|
||||
if (args == NULL || *args == 0) args = timidity_config;
|
||||
|
||||
Renderer = nullptr;
|
||||
if (instruments != nullptr && configName.CompareNoCase(args)) // Only load instruments if they have changed from the last played song.
|
||||
{
|
||||
delete instruments;
|
||||
instruments = nullptr;
|
||||
}
|
||||
TimidityPlus::printMessage = gzdoom_ctl_cmsg;
|
||||
TimidityPlus::set_playback_rate(SampleRate);
|
||||
|
||||
if (instruments == nullptr)
|
||||
{
|
||||
auto sfreader = sfmanager.OpenSoundFont(args, SF_SF2 | SF_GUS);
|
||||
if (sfreader != nullptr)
|
||||
{
|
||||
instruments = new TimidityPlus::Instruments;
|
||||
if (!instruments->load(sfreader))
|
||||
{
|
||||
delete instruments;
|
||||
instruments = nullptr;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (instruments != nullptr)
|
||||
{
|
||||
Renderer = new TimidityPlus::Player(instruments);
|
||||
}
|
||||
else
|
||||
{
|
||||
I_Error("Failed to load any MIDI patches");
|
||||
}
|
||||
sampletime = 0;
|
||||
LoadInstruments(config);
|
||||
Renderer = new TimidityPlus::Player(instruments.get());
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
|
@ -329,8 +140,6 @@ int TimidityPPMIDIDevice::Open(MidiCallback callback, void *userdata)
|
|||
{
|
||||
Renderer->playmidi_stream_init();
|
||||
}
|
||||
// No instruments loaded means we cannot play...
|
||||
if (instruments == nullptr) return 0;
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
@ -393,14 +202,14 @@ void TimidityPPMIDIDevice::ComputeOutput(float *buffer, int len)
|
|||
//
|
||||
//==========================================================================
|
||||
|
||||
MIDIDevice *CreateTimidityPPMIDIDevice(const char *args, int samplerate)
|
||||
MIDIDevice *CreateTimidityPPMIDIDevice(TimidityConfig* config, int samplerate)
|
||||
{
|
||||
return new TimidityPPMIDIDevice(args, samplerate);
|
||||
return new TimidityPPMIDIDevice(config, samplerate);
|
||||
}
|
||||
|
||||
|
||||
void TimidityPP_Shutdown()
|
||||
{
|
||||
TimidityPPMIDIDevice::ClearInstruments();
|
||||
TimidityPlus::free_gauss_table();
|
||||
TimidityPlus::free_global_mblock();
|
||||
}
|
||||
|
|
|
@ -50,7 +50,7 @@
|
|||
class WildMIDIDevice : public SoftSynthMIDIDevice
|
||||
{
|
||||
public:
|
||||
WildMIDIDevice(const char *args, int samplerate);
|
||||
WildMIDIDevice(WildMidiConfig* config, int samplerate);
|
||||
~WildMIDIDevice();
|
||||
|
||||
int Open(MidiCallback, void *userdata);
|
||||
|
@ -60,11 +60,14 @@ public:
|
|||
|
||||
protected:
|
||||
WildMidi::Renderer *Renderer;
|
||||
std::shared_ptr<WildMidi::Instruments> instruments;
|
||||
|
||||
void HandleEvent(int status, int parm1, int parm2);
|
||||
void HandleLongEvent(const uint8_t *data, int len);
|
||||
void ComputeOutput(float *buffer, int len);
|
||||
void WildMidiSetOption(int opt, int set);
|
||||
void ChangeSettingInt(const char *opt, int set);
|
||||
void LoadInstruments(WildMidiConfig* config);
|
||||
|
||||
};
|
||||
|
||||
|
||||
|
@ -80,44 +83,43 @@ protected:
|
|||
|
||||
// PRIVATE DATA DEFINITIONS ------------------------------------------------
|
||||
|
||||
static FString CurrentConfig;
|
||||
|
||||
// PUBLIC DATA DEFINITIONS -------------------------------------------------
|
||||
|
||||
CUSTOM_CVAR(String, wildmidi_config, "", CVAR_ARCHIVE | CVAR_GLOBALCONFIG)
|
||||
{
|
||||
if (currSong != nullptr && currSong->GetDeviceType() == MDEV_WILDMIDI)
|
||||
{
|
||||
MIDIDeviceChanged(-1, true);
|
||||
}
|
||||
}
|
||||
|
||||
CVAR(Int, wildmidi_frequency, 0, CVAR_ARCHIVE|CVAR_GLOBALCONFIG)
|
||||
CUSTOM_CVAR(Bool, wildmidi_reverb, false, CVAR_ARCHIVE | CVAR_GLOBALCONFIG | CVAR_NOINITCALL)
|
||||
{
|
||||
if (currSong != NULL)
|
||||
currSong->WildMidiSetOption(WildMidi::WM_MO_REVERB, *self? WildMidi::WM_MO_REVERB:0);
|
||||
}
|
||||
|
||||
CUSTOM_CVAR(Bool, wildmidi_enhanced_resampling, true, CVAR_ARCHIVE | CVAR_GLOBALCONFIG | CVAR_NOINITCALL)
|
||||
{
|
||||
if (currSong != NULL)
|
||||
currSong->WildMidiSetOption(WildMidi::WM_MO_ENHANCED_RESAMPLING, *self? WildMidi::WM_MO_ENHANCED_RESAMPLING:0);
|
||||
}
|
||||
|
||||
static WildMidi::Instruments *instruments;
|
||||
|
||||
void WildMidi_Shutdown()
|
||||
{
|
||||
if (instruments) delete instruments;
|
||||
}
|
||||
|
||||
// CODE --------------------------------------------------------------------
|
||||
|
||||
static void gzdoom_error_func(const char* wmfmt, va_list args)
|
||||
//==========================================================================
|
||||
//
|
||||
//
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
void WildMIDIDevice::LoadInstruments(WildMidiConfig* config)
|
||||
{
|
||||
Printf(TEXTCOLOR_RED);
|
||||
VPrintf(PRINT_HIGH, wmfmt, args);
|
||||
if (config->reader)
|
||||
{
|
||||
config->loadedConfig = config->readerName;
|
||||
config->instruments.reset(new WildMidi::Instruments(config->reader, SampleRate));
|
||||
bool success = config->instruments->LoadConfig(config->readerName.c_str());
|
||||
config->reader = nullptr;
|
||||
|
||||
if (!success)
|
||||
{
|
||||
config->instruments.reset();
|
||||
config->loadedConfig = "";
|
||||
throw std::runtime_error("Unable to initialize instruments for WildMidi device");
|
||||
}
|
||||
}
|
||||
else if (config->instruments == nullptr)
|
||||
{
|
||||
throw std::runtime_error("No instruments set for WildMidi device");
|
||||
}
|
||||
instruments = config->instruments;
|
||||
if (instruments->LoadConfig(nullptr) < 0)
|
||||
{
|
||||
throw std::runtime_error("Unable to load instruments set for WildMidi device");
|
||||
}
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
|
@ -126,45 +128,17 @@ static void gzdoom_error_func(const char* wmfmt, va_list args)
|
|||
//
|
||||
//==========================================================================
|
||||
|
||||
WildMIDIDevice::WildMIDIDevice(const char *args, int samplerate)
|
||||
:SoftSynthMIDIDevice(samplerate <= 0? wildmidi_frequency : samplerate, 11025, 65535)
|
||||
WildMIDIDevice::WildMIDIDevice(WildMidiConfig *config, int samplerate)
|
||||
:SoftSynthMIDIDevice(samplerate, 11025, 65535)
|
||||
{
|
||||
Renderer = NULL;
|
||||
WildMidi::wm_error_func = gzdoom_error_func;
|
||||
LoadInstruments(config);
|
||||
|
||||
if (args == NULL || *args == 0) args = wildmidi_config;
|
||||
|
||||
if (instruments == nullptr || (CurrentConfig.CompareNoCase(args) != 0 || SampleRate != instruments->GetSampleRate()))
|
||||
{
|
||||
if (instruments) delete instruments;
|
||||
instruments = nullptr;
|
||||
CurrentConfig = "";
|
||||
|
||||
auto reader = sfmanager.OpenSoundFont(args, SF_GUS);
|
||||
if (reader == nullptr)
|
||||
{
|
||||
I_Error("WildMidi: Unable to open sound font %s\n", args);
|
||||
}
|
||||
|
||||
instruments = new WildMidi::Instruments(reader, SampleRate);
|
||||
if (instruments->LoadConfig(nullptr) < 0)
|
||||
{
|
||||
I_Error("WildMidi: Unable to load instruments for sound font %s\n", args);
|
||||
}
|
||||
CurrentConfig = args;
|
||||
}
|
||||
if (CurrentConfig.IsNotEmpty())
|
||||
{
|
||||
Renderer = new WildMidi::Renderer(instruments);
|
||||
int flags = 0;
|
||||
if (wildmidi_enhanced_resampling) flags |= WildMidi::WM_MO_ENHANCED_RESAMPLING;
|
||||
if (wildmidi_reverb) flags |= WildMidi::WM_MO_REVERB;
|
||||
Renderer->SetOption(WildMidi::WM_MO_ENHANCED_RESAMPLING | WildMidi::WM_MO_REVERB, flags);
|
||||
}
|
||||
else
|
||||
{
|
||||
I_Error("Failed to load any MIDI patches");
|
||||
}
|
||||
Renderer = new WildMidi::Renderer(instruments.get());
|
||||
int flags = 0;
|
||||
if (config->enhanced_resampling) flags |= WildMidi::WM_MO_ENHANCED_RESAMPLING;
|
||||
if (config->reverb) flags |= WildMidi::WM_MO_REVERB;
|
||||
Renderer->SetOption(WildMidi::WM_MO_ENHANCED_RESAMPLING | WildMidi::WM_MO_REVERB, flags);
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
|
@ -180,7 +154,6 @@ WildMIDIDevice::~WildMIDIDevice()
|
|||
{
|
||||
delete Renderer;
|
||||
}
|
||||
// Do not shut down the device so that it can be reused for the next song being played.
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
|
@ -277,9 +250,14 @@ FString WildMIDIDevice::GetStats()
|
|||
//
|
||||
//==========================================================================
|
||||
|
||||
void WildMIDIDevice::WildMidiSetOption(int opt, int set)
|
||||
void WildMIDIDevice::ChangeSettingInt(const char *opt, int set)
|
||||
{
|
||||
Renderer->SetOption(opt, set);
|
||||
int option;
|
||||
if (!stricmp(opt, "wildmidi.reverb")) option = WildMidi::WM_MO_REVERB;
|
||||
else if (!stricmp(opt, "wildmidi.resampling")) option = WildMidi::WM_MO_ENHANCED_RESAMPLING;
|
||||
else return;
|
||||
int setit = option * int(set);
|
||||
Renderer->SetOption(option, setit);
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
|
@ -288,8 +266,8 @@ void WildMIDIDevice::WildMidiSetOption(int opt, int set)
|
|||
//
|
||||
//==========================================================================
|
||||
|
||||
MIDIDevice *CreateWildMIDIDevice(const char *args, int samplerate)
|
||||
MIDIDevice *CreateWildMIDIDevice(WildMidiConfig *config, int samplerate)
|
||||
{
|
||||
return new WildMIDIDevice(args, samplerate);
|
||||
return new WildMIDIDevice(config, samplerate);
|
||||
}
|
||||
|
||||
|
|
|
@ -98,7 +98,6 @@ public:
|
|||
//protected:
|
||||
static void CALLBACK CallbackFunc(HMIDIOUT, UINT, DWORD_PTR, DWORD, DWORD);
|
||||
|
||||
MIDIStreamer *Streamer;
|
||||
HMIDISTRM MidiOut;
|
||||
UINT DeviceID;
|
||||
DWORD SavedVolume;
|
||||
|
|
|
@ -160,8 +160,7 @@ void I_ShutdownMusic(bool onexit)
|
|||
}
|
||||
if (onexit)
|
||||
{
|
||||
Timidity_Shutdown();
|
||||
WildMidi_Shutdown();
|
||||
// free static data in the backends.
|
||||
TimidityPP_Shutdown();
|
||||
dumb_exit();
|
||||
}
|
||||
|
@ -257,10 +256,6 @@ void MusInfo::ChangeSettingString(const char *, const char *)
|
|||
{
|
||||
}
|
||||
|
||||
void MusInfo::WildMidiSetOption(int opt, int set)
|
||||
{
|
||||
}
|
||||
|
||||
FString MusInfo::GetStats()
|
||||
{
|
||||
return "No stats available for this song";
|
||||
|
|
|
@ -82,7 +82,6 @@ public:
|
|||
virtual void ChangeSettingInt(const char *setting, int value); // FluidSynth settings
|
||||
virtual void ChangeSettingNum(const char *setting, double value); // "
|
||||
virtual void ChangeSettingString(const char *setting, const char *value); // "
|
||||
virtual void WildMidiSetOption(int opt, int set);
|
||||
virtual void GMEDepthChanged(float val);
|
||||
|
||||
void Start(bool loop, float rel_vol = -1.f, int subsong = 0);
|
||||
|
|
|
@ -35,15 +35,14 @@ struct ADLConfig
|
|||
int adl_volume_model = 3; // DMX
|
||||
bool adl_run_at_pcm_rate = 0;
|
||||
bool adl_fullpan = 1;
|
||||
bool adl_use_custom_bank = 0;
|
||||
const char *adl_custom_bank = nullptr;
|
||||
std::string adl_custom_bank;
|
||||
};
|
||||
|
||||
extern ADLConfig adlConfig;
|
||||
|
||||
struct FluidConfig
|
||||
{
|
||||
const char* fluid_lib = nullptr;
|
||||
std::string fluid_lib;
|
||||
std::vector<std::string> fluid_patchset;
|
||||
bool fluid_reverb = false;
|
||||
bool fluid_chorus = false;
|
||||
|
@ -75,6 +74,86 @@ struct OPLMidiConfig
|
|||
|
||||
extern OPLMidiConfig oplMidiConfig;
|
||||
|
||||
struct OpnConfig
|
||||
{
|
||||
int opn_chips_count = 8;
|
||||
int opn_emulator_id = 0;
|
||||
bool opn_run_at_pcm_rate = false;
|
||||
bool opn_fullpan = 1;
|
||||
std::string opn_custom_bank;
|
||||
std::vector<uint8_t> default_bank;
|
||||
};
|
||||
|
||||
extern OpnConfig opnConfig;
|
||||
|
||||
namespace Timidity
|
||||
{
|
||||
class Instruments;
|
||||
class SoundFontReaderInterface;
|
||||
}
|
||||
|
||||
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;
|
||||
|
||||
Timidity::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
|
||||
};
|
||||
|
||||
extern GUSConfig gusConfig;
|
||||
|
||||
namespace TimidityPlus
|
||||
{
|
||||
class Instruments;
|
||||
class SoundFontReaderInterface;
|
||||
}
|
||||
|
||||
struct TimidityConfig
|
||||
{
|
||||
void (*errorfunc)(int type, int verbosity_level, const char* fmt, ...) = nullptr;
|
||||
|
||||
TimidityPlus::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
|
||||
|
||||
};
|
||||
|
||||
extern TimidityConfig timidityConfig;
|
||||
|
||||
struct WildMidiConfig
|
||||
{
|
||||
bool reverb = false;
|
||||
bool enhanced_resampling = true;
|
||||
void (*errorfunc)(const char* wmfmt, va_list args) = nullptr;
|
||||
|
||||
WildMidi::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
|
||||
|
||||
};
|
||||
|
||||
extern WildMidiConfig wildMidiConfig;
|
||||
|
||||
class MIDIStreamer;
|
||||
|
||||
|
@ -105,7 +184,6 @@ public:
|
|||
virtual void ChangeSettingInt(const char *setting, int value);
|
||||
virtual void ChangeSettingNum(const char *setting, double value);
|
||||
virtual void ChangeSettingString(const char *setting, const char *value);
|
||||
virtual void WildMidiSetOption(int opt, int set);
|
||||
virtual bool Preprocess(MIDIStreamer *song, bool looping);
|
||||
virtual FString GetStats();
|
||||
virtual int GetDeviceType() const { return MDEV_DEFAULT; }
|
||||
|
@ -114,9 +192,7 @@ public:
|
|||
|
||||
|
||||
|
||||
void Timidity_Shutdown();
|
||||
void TimidityPP_Shutdown();
|
||||
void WildMidi_Shutdown ();
|
||||
|
||||
|
||||
// Base class for software synthesizer MIDI output devices ------------------
|
||||
|
@ -220,7 +296,6 @@ public:
|
|||
void ChangeSettingInt(const char *setting, int value) override;
|
||||
void ChangeSettingNum(const char *setting, double value) override;
|
||||
void ChangeSettingString(const char *setting, const char *value) override;
|
||||
void WildMidiSetOption(int opt, int set) override;
|
||||
int ServiceEvent();
|
||||
void SetMIDISource(MIDISource *_source);
|
||||
|
||||
|
@ -313,7 +388,7 @@ public:
|
|||
void Play (bool looping, int subsong);
|
||||
bool IsPlaying ();
|
||||
bool IsValid () const;
|
||||
void ResetChips ();
|
||||
void ChangeSettingInt (const char *, int) override;
|
||||
|
||||
protected:
|
||||
|
||||
|
@ -351,11 +426,29 @@ public:
|
|||
CDDAFile (FileReader &reader);
|
||||
};
|
||||
|
||||
// MIDI devices
|
||||
|
||||
MIDIDevice *CreateFluidSynthMIDIDevice(int samplerate, const FluidConfig* config, int (*printfunc)(const char*, ...));
|
||||
MIDIDevice *CreateADLMIDIDevice(const ADLConfig* config);
|
||||
MIDIDevice *CreateOPNMIDIDevice(const OpnConfig *args);
|
||||
MIDIDevice *CreateOplMIDIDevice(const OPLMidiConfig* config);
|
||||
MIDIDevice *CreateTimidityMIDIDevice(GUSConfig *config, int samplerate);
|
||||
MIDIDevice *CreateTimidityPPMIDIDevice(TimidityConfig *config, int samplerate);
|
||||
MIDIDevice *CreateWildMIDIDevice(WildMidiConfig *config, int samplerate);
|
||||
|
||||
#ifdef _WIN32
|
||||
MIDIDevice* CreateWinMIDIDevice(int mididevice);
|
||||
#endif
|
||||
|
||||
// Data interface
|
||||
|
||||
int BuildFluidPatchSetList(const char* patches, bool systemfallback);
|
||||
void LoadGenMidi();
|
||||
int getOPLCore(const char* args);
|
||||
void Fluid_SetupConfig(FluidConfig *config, const char* patches, bool systemfallback);
|
||||
void ADL_SetupConfig(ADLConfig *config, const char *Args);
|
||||
void OPL_SetupConfig(OPLMidiConfig *config, const char *args);
|
||||
void OPN_SetupConfig(OpnConfig *config, const char *Args);
|
||||
bool GUS_SetupConfig(GUSConfig *config, const char *args);
|
||||
bool Timidity_SetupConfig(TimidityConfig* config, const char* args);
|
||||
bool WildMidi_SetupConfig(WildMidiConfig* config, const char* args);
|
||||
|
||||
// Module played via foo_dumb -----------------------------------------------
|
||||
|
||||
|
|
|
@ -47,17 +47,6 @@
|
|||
|
||||
// EXTERNAL FUNCTION PROTOTYPES --------------------------------------------
|
||||
|
||||
#ifdef _WIN32
|
||||
MIDIDevice *CreateWinMIDIDevice(int mididevice);
|
||||
#endif
|
||||
MIDIDevice* CreateFluidSynthMIDIDevice(int samplerate, FluidConfig* config, int (*printfunc)(const char*, ...));
|
||||
MIDIDevice *CreateTimidityMIDIDevice(const char *args, int samplerate);
|
||||
MIDIDevice *CreateTimidityPPMIDIDevice(const char *args, int samplerate);
|
||||
MIDIDevice *CreateADLMIDIDevice(const char *args, const ADLConfig* config);
|
||||
MIDIDevice *CreateOPNMIDIDevice(const char *args);
|
||||
MIDIDevice *CreateWildMIDIDevice(const char *args, int samplerate);
|
||||
MIDIDevice* CreateOplMIDIDevice(OPLMidiConfig* config);
|
||||
int BuildFluidPatchSetList(const char* patches, bool systemfallback);
|
||||
|
||||
// PUBLIC FUNCTION PROTOTYPES ----------------------------------------------
|
||||
|
||||
|
@ -209,15 +198,18 @@ MIDIDevice *MIDIStreamer::CreateMIDIDevice(EMidiDevice devtype, int samplerate)
|
|||
switch (devtype)
|
||||
{
|
||||
case MDEV_GUS:
|
||||
dev = CreateTimidityMIDIDevice(Args, samplerate);
|
||||
GUS_SetupConfig(&gusConfig, Args);
|
||||
dev = CreateTimidityMIDIDevice(&gusConfig, samplerate);
|
||||
break;
|
||||
|
||||
case MDEV_ADL:
|
||||
dev = CreateADLMIDIDevice(Args, &adlConfig);
|
||||
ADL_SetupConfig(&adlConfig, Args);
|
||||
dev = CreateADLMIDIDevice(&adlConfig);
|
||||
break;
|
||||
|
||||
case MDEV_OPN:
|
||||
dev = CreateOPNMIDIDevice(Args);
|
||||
OPN_SetupConfig(&opnConfig, Args);
|
||||
dev = CreateOPNMIDIDevice(&opnConfig);
|
||||
break;
|
||||
|
||||
case MDEV_MMAPI:
|
||||
|
@ -229,22 +221,23 @@ MIDIDevice *MIDIStreamer::CreateMIDIDevice(EMidiDevice devtype, int samplerate)
|
|||
// Intentional fall-through for non-Windows systems.
|
||||
|
||||
case MDEV_FLUIDSYNTH:
|
||||
BuildFluidPatchSetList(Args, true);
|
||||
Fluid_SetupConfig(&fluidConfig, Args, true);
|
||||
dev = CreateFluidSynthMIDIDevice(samplerate, &fluidConfig, Printf);
|
||||
break;
|
||||
|
||||
case MDEV_OPL:
|
||||
LoadGenMidi();
|
||||
oplMidiConfig.core = getOPLCore(Args);
|
||||
OPL_SetupConfig(&oplMidiConfig, Args);
|
||||
dev = CreateOplMIDIDevice(&oplMidiConfig);
|
||||
break;
|
||||
|
||||
case MDEV_TIMIDITY:
|
||||
dev = CreateTimidityPPMIDIDevice(Args, samplerate);
|
||||
Timidity_SetupConfig(&timidityConfig, Args);
|
||||
dev = CreateTimidityPPMIDIDevice(&timidityConfig, samplerate);
|
||||
break;
|
||||
|
||||
case MDEV_WILDMIDI:
|
||||
dev = CreateWildMIDIDevice(Args, samplerate);
|
||||
WildMidi_SetupConfig(&wildMidiConfig, Args);
|
||||
dev = CreateWildMIDIDevice(&wildMidiConfig, samplerate);
|
||||
break;
|
||||
|
||||
default:
|
||||
|
@ -308,7 +301,7 @@ void MIDIStreamer::Play(bool looping, int subsong)
|
|||
m_Looping = looping;
|
||||
source->SetMIDISubsong(subsong);
|
||||
devtype = SelectMIDIDevice(DeviceType);
|
||||
MIDI = CreateMIDIDevice(devtype, 0);
|
||||
MIDI = CreateMIDIDevice(devtype, (int)GSnd->GetOutputRate());
|
||||
InitPlayback();
|
||||
}
|
||||
|
||||
|
@ -601,21 +594,6 @@ void MIDIStreamer::ChangeSettingString(const char *setting, const char *value)
|
|||
}
|
||||
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
// MIDIDeviceStreamer :: WildMidiSetOption
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
void MIDIStreamer::WildMidiSetOption(int opt, int set)
|
||||
{
|
||||
if (MIDI != NULL)
|
||||
{
|
||||
MIDI->WildMidiSetOption(opt, set);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
// MIDIStreamer :: OutputVolume
|
||||
|
@ -1075,16 +1053,6 @@ void MIDIDevice::ChangeSettingString(const char *setting, const char *value)
|
|||
{
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
// MIDIDevice :: WildMidiSetOption
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
void MIDIDevice::WildMidiSetOption(int opt, int set)
|
||||
{
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
// MIDIDevice :: GetStats
|
||||
|
|
|
@ -37,8 +37,15 @@
|
|||
static bool OPL_Active;
|
||||
|
||||
EXTERN_CVAR (Int, opl_numchips)
|
||||
EXTERN_CVAR(Int, opl_core)
|
||||
|
||||
int getOPLCore(const char* args)
|
||||
{
|
||||
int current_opl_core = opl_core;
|
||||
if (args != NULL && *args >= '0' && *args < '4') current_opl_core = *args - '0';
|
||||
return current_opl_core;
|
||||
}
|
||||
|
||||
int getOPLCore(const char* args);
|
||||
|
||||
OPLMUSSong::OPLMUSSong (FileReader &reader, const char *args)
|
||||
{
|
||||
|
@ -81,9 +88,10 @@ bool OPLMUSSong::IsValid () const
|
|||
return m_Stream != NULL;
|
||||
}
|
||||
|
||||
void OPLMUSSong::ResetChips ()
|
||||
void OPLMUSSong::ChangeSettingInt(const char * name, int val)
|
||||
{
|
||||
Music->ResetChips (opl_numchips);
|
||||
if (!strcmp(name, "opl.numchips"))
|
||||
Music->ResetChips (val);
|
||||
}
|
||||
|
||||
bool OPLMUSSong::IsPlaying ()
|
||||
|
|
Loading…
Reference in a new issue