diff --git a/src/d_player.h b/src/d_player.h index e27bf1087..11611cded 100644 --- a/src/d_player.h +++ b/src/d_player.h @@ -221,7 +221,11 @@ enum WF_WEAPONRELOADOK = 1 << 5, // [XA] Okay to reload this weapon. WF_WEAPONZOOMOK = 1 << 6, // [XA] Okay to use weapon zoom function. WF_REFIRESWITCHOK = 1 << 7, // Mirror WF_WEAPONSWITCHOK for A_ReFire -}; + WF_USER1OK = 1 << 8, // [MC] Allow pushing of custom state buttons 1-4 + WF_USER2OK = 1 << 9, + WF_USER3OK = 1 << 10, + WF_USER4OK = 1 << 11, +}; #define WPIECE1 1 #define WPIECE2 2 @@ -405,7 +409,7 @@ public: int lastkilltime; // [RH] For multikills BYTE multicount; BYTE spreecount; // [RH] Keep track of killing sprees - BYTE WeaponState; + WORD WeaponState; AWeapon *ReadyWeapon; AWeapon *PendingWeapon; // WP_NOCHANGE if not changing diff --git a/src/g_shared/a_pickups.h b/src/g_shared/a_pickups.h index 74b10206b..413b01db3 100644 --- a/src/g_shared/a_pickups.h +++ b/src/g_shared/a_pickups.h @@ -305,8 +305,7 @@ public: virtual FState *GetReadyState (); virtual FState *GetAtkState (bool hold); virtual FState *GetAltAtkState (bool hold); - virtual FState *GetRelState (); - virtual FState *GetZoomState (); + virtual FState *GetStateForButtonName (FName button); virtual void PostMorphWeapon (); virtual void EndPowerup (); diff --git a/src/g_shared/a_weapons.cpp b/src/g_shared/a_weapons.cpp index fae232557..9c71ab0ea 100644 --- a/src/g_shared/a_weapons.cpp +++ b/src/g_shared/a_weapons.cpp @@ -683,25 +683,15 @@ FState *AWeapon::GetAltAtkState (bool hold) //=========================================================================== // -// AWeapon :: GetRelState +// AWeapon :: GetStateForButtonName // //=========================================================================== -FState *AWeapon::GetRelState () +FState *AWeapon::GetStateForButtonName (FName button) { - return FindState(NAME_Reload); + return FindState(button); } -//=========================================================================== -// -// AWeapon :: GetZoomState -// -//=========================================================================== - -FState *AWeapon::GetZoomState () -{ - return FindState(NAME_Zoom); -} /* Weapon giver ***********************************************************/ diff --git a/src/namedef.h b/src/namedef.h index 22dbe1b51..f9d436f28 100644 --- a/src/namedef.h +++ b/src/namedef.h @@ -221,6 +221,10 @@ xx(Flash) xx(AltFlash) xx(Reload) xx(Zoom) +xx(User1) +xx(User2) +xx(User3) +xx(User4) // State names used by ASwitchableDecoration xx(Active) diff --git a/src/oplsynth/mlopl_io.cpp b/src/oplsynth/mlopl_io.cpp index 691463470..4ec41d6c9 100644 --- a/src/oplsynth/mlopl_io.cpp +++ b/src/oplsynth/mlopl_io.cpp @@ -48,6 +48,7 @@ #define HALF_PI (PI*0.5) EXTERN_CVAR(Int, opl_core) +extern int current_opl_core; OPLio::~OPLio() { @@ -323,7 +324,7 @@ int OPLio::OPLinit(uint numchips, bool stereo, bool initopl3) { assert(numchips >= 1 && numchips <= countof(chips)); uint i; - IsOPL3 = (opl_core == 1 || opl_core == 2 || opl_core == 3); + IsOPL3 = (current_opl_core == 1 || current_opl_core == 2 || current_opl_core == 3); memset(chips, 0, sizeof(chips)); if (IsOPL3) @@ -332,7 +333,7 @@ int OPLio::OPLinit(uint numchips, bool stereo, bool initopl3) } for (i = 0; i < numchips; ++i) { - OPLEmul *chip = IsOPL3 ? (opl_core == 1 ? DBOPLCreate(stereo) : (opl_core == 2 ? JavaOPLCreate(stereo) : NukedOPL3Create(stereo))) : YM3812Create(stereo); + OPLEmul *chip = IsOPL3 ? (current_opl_core == 1 ? DBOPLCreate(stereo) : (current_opl_core == 2 ? JavaOPLCreate(stereo) : NukedOPL3Create(stereo))) : YM3812Create(stereo); if (chip == NULL) { break; diff --git a/src/oplsynth/music_opl_mididevice.cpp b/src/oplsynth/music_opl_mididevice.cpp index 79bb10226..aa6cda7ee 100644 --- a/src/oplsynth/music_opl_mididevice.cpp +++ b/src/oplsynth/music_opl_mididevice.cpp @@ -53,6 +53,7 @@ #endif // EXTERNAL FUNCTION PROTOTYPES -------------------------------------------- +void OPL_SetCore(const char *args); // PUBLIC FUNCTION PROTOTYPES ---------------------------------------------- @@ -76,8 +77,9 @@ CVAR(Bool, opl_fullpan, true, CVAR_ARCHIVE|CVAR_GLOBALCONFIG); // //========================================================================== -OPLMIDIDevice::OPLMIDIDevice() +OPLMIDIDevice::OPLMIDIDevice(const char *args) { + OPL_SetCore(args); FullPan = opl_fullpan; FWadLump data = Wads.OpenLumpName("GENMIDI"); OPLloadBank(data); diff --git a/src/oplsynth/music_opldumper_mididevice.cpp b/src/oplsynth/music_opldumper_mididevice.cpp index 46dcdfef2..e6684e1a6 100644 --- a/src/oplsynth/music_opldumper_mididevice.cpp +++ b/src/oplsynth/music_opldumper_mididevice.cpp @@ -262,6 +262,7 @@ protected: //========================================================================== OPLDumperMIDIDevice::OPLDumperMIDIDevice(const char *filename) + : OPLMIDIDevice(NULL) { // Replace the standard OPL device with a disk writer. delete io; diff --git a/src/p_pspr.cpp b/src/p_pspr.cpp index 63f3bc648..ed7d675d3 100644 --- a/src/p_pspr.cpp +++ b/src/p_pspr.cpp @@ -38,6 +38,30 @@ // TYPES ------------------------------------------------------------------- +struct FGenericButtons +{ + int ReadyFlag; // Flag passed to A_WeaponReady + int StateFlag; // Flag set in WeaponState + int ButtonFlag; // Button to press + ENamedName StateName; // Name of the button/state +}; + +enum EWRF_Options +{ + WRF_NoBob = 1, + WRF_NoSwitch = 1 << 1, + WRF_NoPrimary = 1 << 2, + WRF_NoSecondary = 1 << 3, + WRF_NoFire = WRF_NoPrimary | WRF_NoSecondary, + WRF_AllowReload = 1 << 4, + WRF_AllowZoom = 1 << 5, + WRF_DisableSwitch = 1 << 6, + WRF_AllowUser1 = 1 << 7, + WRF_AllowUser2 = 1 << 8, + WRF_AllowUser3 = 1 << 9, + WRF_AllowUser4 = 1 << 10, +}; + // EXTERNAL FUNCTION PROTOTYPES -------------------------------------------- // PUBLIC FUNCTION PROTOTYPES ---------------------------------------------- @@ -57,6 +81,16 @@ CVAR(Int, sv_fastweapons, false, CVAR_SERVERINFO); static FRandom pr_wpnreadysnd ("WpnReadySnd"); static FRandom pr_gunshot ("GunShot"); +static const FGenericButtons ButtonChecks[] = +{ + { WRF_AllowReload, WF_WEAPONZOOMOK, BT_ZOOM, NAME_Zoom }, + { WRF_AllowZoom, WF_WEAPONRELOADOK, BT_RELOAD, NAME_Reload }, + { WRF_AllowUser1, WF_USER1OK, BT_USER1, NAME_User1 }, + { WRF_AllowUser2, WF_USER2OK, BT_USER2, NAME_User2 }, + { WRF_AllowUser3, WF_USER3OK, BT_USER3, NAME_User3 }, + { WRF_AllowUser4, WF_USER4OK, BT_USER4, NAME_User4 }, +}; + // CODE -------------------------------------------------------------------- //--------------------------------------------------------------------------- @@ -95,7 +129,8 @@ void P_SetPsprite (player_t *player, int position, FState *state, bool nofunctio if (position == ps_weapon && !nofunction) { // A_WeaponReady will re-set these as needed - player->WeaponState &= ~(WF_WEAPONREADY | WF_WEAPONREADYALT | WF_WEAPONBOBBING | WF_WEAPONSWITCHOK | WF_WEAPONRELOADOK | WF_WEAPONZOOMOK); + player->WeaponState &= ~(WF_WEAPONREADY | WF_WEAPONREADYALT | WF_WEAPONBOBBING | WF_WEAPONSWITCHOK | WF_WEAPONRELOADOK | WF_WEAPONZOOMOK | + WF_USER1OK | WF_USER2OK | WF_USER3OK | WF_USER4OK); } psp = &player->psprites[position]; @@ -289,66 +324,6 @@ void P_FireWeaponAlt (player_t *player, FState *state) } } -//--------------------------------------------------------------------------- -// -// PROC P_ReloadWeapon -// -//--------------------------------------------------------------------------- - -void P_ReloadWeapon (player_t *player, FState *state) -{ - AWeapon *weapon; - if (player->Bot == NULL && bot_observer) - { - return; - } - - weapon = player->ReadyWeapon; - if (weapon == NULL) - { - return; - } - - if (state == NULL) - { - state = weapon->GetRelState(); - } - // [XA] don't change state if still null, so if the modder sets - // WRF_RELOAD to true but forgets to define the Reload state, the weapon - // won't disappear. ;) - if (state != NULL) - P_SetPsprite (player, ps_weapon, state); -} - -//--------------------------------------------------------------------------- -// -// PROC P_ZoomWeapon -// -//--------------------------------------------------------------------------- - -void P_ZoomWeapon (player_t *player, FState *state) -{ - AWeapon *weapon; - if (player->Bot == NULL && bot_observer) - { - return; - } - - weapon = player->ReadyWeapon; - if (weapon == NULL) - { - return; - } - - if (state == NULL) - { - state = weapon->GetZoomState(); - } - // [XA] don't change state if still null. Same reasons as above. - if (state != NULL) - P_SetPsprite (player, ps_weapon, state); -} - //--------------------------------------------------------------------------- // // PROC P_DropWeapon @@ -562,22 +537,21 @@ void DoReadyWeaponToBob (AActor *self) } } -void DoReadyWeaponToReload (AActor *self) +void DoReadyWeaponToGeneric(AActor *self, int paramflags) { - // Prepare for reload action. - player_t *player; - if (self && (player = self->player)) - player->WeaponState |= WF_WEAPONRELOADOK; - return; -} + int flags = 0; -void DoReadyWeaponToZoom (AActor *self) -{ - // Prepare for reload action. - player_t *player; - if (self && (player = self->player)) - player->WeaponState |= WF_WEAPONZOOMOK; - return; + for (size_t i = 0; i < countof(ButtonChecks); ++i) + { + if (paramflags & ButtonChecks[i].ReadyFlag) + { + flags |= ButtonChecks[i].StateFlag; + } + } + if (self != NULL && self->player != NULL) + { + self->player->WeaponState |= flags; + } } // This function replaces calls to A_WeaponReady in other codepointers. @@ -586,22 +560,9 @@ void DoReadyWeapon(AActor *self) DoReadyWeaponToBob(self); DoReadyWeaponToFire(self); DoReadyWeaponToSwitch(self); - DoReadyWeaponToReload(self); - DoReadyWeaponToZoom(self); + DoReadyWeaponToGeneric(self, ~0); } -enum EWRF_Options -{ - WRF_NoBob = 1, - WRF_NoSwitch = 2, - WRF_NoPrimary = 4, - WRF_NoSecondary = 8, - WRF_NoFire = WRF_NoPrimary + WRF_NoSecondary, - WRF_AllowReload = 16, - WRF_AllowZoom = 32, - WRF_DisableSwitch = 64, -}; - DEFINE_ACTION_FUNCTION_PARAMS(AInventory, A_WeaponReady) { ACTION_PARAM_START(1); @@ -610,10 +571,8 @@ DEFINE_ACTION_FUNCTION_PARAMS(AInventory, A_WeaponReady) DoReadyWeaponToSwitch(self, !(paramflags & WRF_NoSwitch)); if ((paramflags & WRF_NoFire) != WRF_NoFire) DoReadyWeaponToFire(self, !(paramflags & WRF_NoPrimary), !(paramflags & WRF_NoSecondary)); if (!(paramflags & WRF_NoBob)) DoReadyWeaponToBob(self); - if ((paramflags & WRF_AllowReload)) DoReadyWeaponToReload(self); - if ((paramflags & WRF_AllowZoom)) DoReadyWeaponToZoom(self); - - DoReadyWeaponDisableSwitch(self, paramflags & WRF_DisableSwitch); + DoReadyWeaponToGeneric(self, paramflags); + DoReadyWeaponDisableSwitch(self, paramflags & WRF_DisableSwitch); } //--------------------------------------------------------------------------- @@ -690,45 +649,40 @@ void P_CheckWeaponSwitch (player_t *player) //--------------------------------------------------------------------------- // -// PROC P_CheckWeaponReload +// PROC P_CheckWeaponButtons // -// The player can reload the weapon. +// Check extra button presses for weapons. // //--------------------------------------------------------------------------- -void P_CheckWeaponReload (player_t *player) +static void P_CheckWeaponButtons (player_t *player) { - AWeapon *weapon = player->ReadyWeapon; - - if (weapon == NULL) - return; - - // Check for reload. - if ((player->WeaponState & WF_WEAPONRELOADOK) && (player->cmd.ucmd.buttons & BT_RELOAD)) + if (player->Bot == NULL && bot_observer) { - P_ReloadWeapon (player, NULL); + return; } -} - -//--------------------------------------------------------------------------- -// -// PROC P_CheckWeaponZoom -// -// The player can use the weapon's zoom function. -// -//--------------------------------------------------------------------------- - -void P_CheckWeaponZoom (player_t *player) -{ AWeapon *weapon = player->ReadyWeapon; - if (weapon == NULL) - return; - - // Check for zoom. - if ((player->WeaponState & WF_WEAPONZOOMOK) && (player->cmd.ucmd.buttons & BT_ZOOM)) { - P_ZoomWeapon (player, NULL); + return; + } + // The button checks are ordered by precedence. The first one to match a + // button press and affect a state change wins. + for (size_t i = 0; i < countof(ButtonChecks); ++i) + { + if ((player->WeaponState & ButtonChecks[i].StateFlag) && + (player->cmd.ucmd.buttons & ButtonChecks[i].ButtonFlag)) + { + FState *state = weapon->GetStateForButtonName(ButtonChecks[i].StateName); + // [XA] don't change state if still null, so if the modder + // sets WRF_xxx to true but forgets to define the corresponding + // state, the weapon won't disappear. ;) + if (state != NULL) + { + P_SetPsprite(player, ps_weapon, state); + return; + } + } } } @@ -1095,14 +1049,9 @@ void P_MovePsprites (player_t *player) { P_CheckWeaponFire (player); } - if (player->WeaponState & WF_WEAPONRELOADOK) - { - P_CheckWeaponReload (player); - } - if (player->WeaponState & WF_WEAPONZOOMOK) - { - P_CheckWeaponZoom (player); - } + + // Check custom buttons + P_CheckWeaponButtons(player); } } diff --git a/src/p_user.cpp b/src/p_user.cpp index 331a978b7..1eb838176 100644 --- a/src/p_user.cpp +++ b/src/p_user.cpp @@ -3043,6 +3043,12 @@ void player_t::Serialize (FArchive &arc) WeaponState = ((cheats >> 14) & 1) | ((cheats & (0x37 << 24)) >> (24 - 1)); cheats &= ~((1 << 14) | (0x37 << 24)); } + if (SaveVersion < 4527) + { + BYTE oldWeaponState; + arc << oldWeaponState; + WeaponState = oldWeaponState; + } else { arc << WeaponState; diff --git a/src/s_advsound.cpp b/src/s_advsound.cpp index cb0f26ae6..8170c1a30 100644 --- a/src/s_advsound.cpp +++ b/src/s_advsound.cpp @@ -1364,16 +1364,36 @@ static void S_AddSNDINFO (int lump) case SI_MidiDevice: { sc.MustGetString(); FName nm = sc.String; + FScanner::SavedPos save = sc.SavePos(); + + sc.SetCMode(true); sc.MustGetString(); - if (sc.Compare("timidity")) MidiDevices[nm] = MDEV_TIMIDITY; - else if (sc.Compare("fmod") || sc.Compare("sndsys")) MidiDevices[nm] = MDEV_SNDSYS; - else if (sc.Compare("standard")) MidiDevices[nm] = MDEV_MMAPI; - else if (sc.Compare("opl")) MidiDevices[nm] = MDEV_OPL; - else if (sc.Compare("default")) MidiDevices[nm] = MDEV_DEFAULT; - else if (sc.Compare("fluidsynth")) MidiDevices[nm] = MDEV_FLUIDSYNTH; - else if (sc.Compare("gus")) MidiDevices[nm] = MDEV_GUS; - else if (sc.Compare("wildmidi")) MidiDevices[nm] = MDEV_WILDMIDI; + MidiDeviceSetting devset; + if (sc.Compare("timidity")) devset.device = MDEV_TIMIDITY; + else if (sc.Compare("fmod") || sc.Compare("sndsys")) devset.device = MDEV_SNDSYS; + else if (sc.Compare("standard")) devset.device = MDEV_MMAPI; + else if (sc.Compare("opl")) devset.device = MDEV_OPL; + else if (sc.Compare("default")) devset.device = MDEV_DEFAULT; + else if (sc.Compare("fluidsynth")) devset.device = MDEV_FLUIDSYNTH; + else if (sc.Compare("gus")) devset.device = MDEV_GUS; + else if (sc.Compare("wildmidi")) devset.device = MDEV_WILDMIDI; else sc.ScriptError("Unknown MIDI device %s\n", sc.String); + + if (sc.CheckString(",")) + { + sc.SetCMode(false); + sc.MustGetString(); + devset.args = sc.String; + } + else + { + // This does not really do what one might expect, because the next token has already been parsed and can be a '$'. + // So in order to continue parsing without C-Mode, we need to reset and parse the last token again. + sc.SetCMode(false); + sc.RestorePos(save); + sc.MustGetString(); + } + MidiDevices[nm] = devset; } break; diff --git a/src/s_sound.cpp b/src/s_sound.cpp index 7b38e816c..f388246a9 100644 --- a/src/s_sound.cpp +++ b/src/s_sound.cpp @@ -2421,11 +2421,8 @@ bool S_ChangeMusic (const char *musicname, int order, bool looping, bool force) { int lumpnum = -1; int length = 0; - int device = MDEV_DEFAULT; MusInfo *handle = NULL; - - int *devp = MidiDevices.CheckKey(musicname); - if (devp != NULL) device = *devp; + MidiDeviceSetting *devp = MidiDevices.CheckKey(musicname); // Strip off any leading file:// component. if (strncmp(musicname, "file://", 7) == 0) @@ -2495,7 +2492,7 @@ bool S_ChangeMusic (const char *musicname, int order, bool looping, bool force) } else { - mus_playing.handle = I_RegisterSong (reader, device); + mus_playing.handle = I_RegisterSong (reader, devp); } } diff --git a/src/s_sound.h b/src/s_sound.h index 16aa8b333..a72f3be0c 100644 --- a/src/s_sound.h +++ b/src/s_sound.h @@ -397,8 +397,19 @@ enum EMidiDevice MDEV_WILDMIDI = 6, }; +struct MidiDeviceSetting +{ + int device; + FString args; + + MidiDeviceSetting() + { + device = MDEV_DEFAULT; + } +}; + typedef TMap MusicAliasMap; -typedef TMap MidiDeviceMap; +typedef TMap MidiDeviceMap; extern MusicAliasMap MusicAliases; extern MidiDeviceMap MidiDevices; diff --git a/src/sound/i_music.cpp b/src/sound/i_music.cpp index a46401f3e..5723a18dc 100644 --- a/src/sound/i_music.cpp +++ b/src/sound/i_music.cpp @@ -311,21 +311,21 @@ MusInfo *MusInfo::GetWaveDumper(const char *filename, int rate) // //========================================================================== -static MIDIStreamer *CreateMIDIStreamer(FileReader &reader, EMidiDevice devtype, EMIDIType miditype) +static MIDIStreamer *CreateMIDIStreamer(FileReader &reader, EMidiDevice devtype, EMIDIType miditype, const char *args) { switch (miditype) { case MIDI_MUS: - return new MUSSong2(reader, devtype); + return new MUSSong2(reader, devtype, args); case MIDI_MIDI: - return new MIDISong2(reader, devtype); + return new MIDISong2(reader, devtype, args); case MIDI_HMI: - return new HMISong(reader, devtype); + return new HMISong(reader, devtype, args); case MIDI_XMI: - return new XMISong(reader, devtype); + return new XMISong(reader, devtype, args); default: return NULL; @@ -387,7 +387,7 @@ static EMIDIType IdentifyMIDIType(DWORD *id, int size) // //========================================================================== -MusInfo *I_RegisterSong (FileReader *reader, int device) +MusInfo *I_RegisterSong (FileReader *reader, MidiDeviceSetting *device) { MusInfo *info = NULL; const char *fmt; @@ -405,12 +405,6 @@ MusInfo *I_RegisterSong (FileReader *reader, int device) return 0; } -#ifndef _WIN32 - // non-Windows platforms don't support MDEV_MMAPI so map to MDEV_SNDSYS - if (device == MDEV_MMAPI) - device = MDEV_SNDSYS; -#endif - // Check for gzip compression. Some formats are expected to have players // that can handle it, so it simplifies things if we make all songs // gzippable. @@ -447,10 +441,15 @@ MusInfo *I_RegisterSong (FileReader *reader, int device) EMIDIType miditype = IdentifyMIDIType(id, sizeof(id)); if (miditype != MIDI_NOTMIDI) { - EMidiDevice devtype = (EMidiDevice)device; + EMidiDevice devtype = device == NULL? MDEV_DEFAULT : (EMidiDevice)device->device; +#ifndef _WIN32 + // non-Windows platforms don't support MDEV_MMAPI so map to MDEV_SNDSYS + if (devtype == MDEV_MMAPI) + devtype = MDEV_SNDSYS; +#endif retry_as_sndsys: - info = CreateMIDIStreamer(*reader, devtype, miditype); + info = CreateMIDIStreamer(*reader, devtype, miditype, device != NULL? device->args.GetChars() : ""); if (info != NULL && !info->IsValid()) { delete info; @@ -464,7 +463,7 @@ retry_as_sndsys: #ifdef _WIN32 if (info == NULL && devtype != MDEV_MMAPI && snd_mididevice >= 0) { - info = CreateMIDIStreamer(*reader, MDEV_MMAPI, miditype); + info = CreateMIDIStreamer(*reader, MDEV_MMAPI, miditype, ""); } #endif } @@ -475,7 +474,7 @@ retry_as_sndsys: (id[0] == MAKE_ID('D','B','R','A') && id[1] == MAKE_ID('W','O','P','L')) || // DosBox Raw OPL (id[0] == MAKE_ID('A','D','L','I') && *((BYTE *)id + 4) == 'B')) // Martin Fernandez's modified IMF { - info = new OPLMUSSong (*reader); + info = new OPLMUSSong (*reader, device != NULL? device->args.GetChars() : ""); } // Check for game music else if ((fmt = GME_CheckFormat(id[0])) != NULL && fmt[0] != '\0') diff --git a/src/sound/i_music.h b/src/sound/i_music.h index 03e0a3212..514400e5d 100644 --- a/src/sound/i_music.h +++ b/src/sound/i_music.h @@ -53,7 +53,8 @@ void I_SetMusicVolume (float volume); // Registers a song handle to song data. class MusInfo; -MusInfo *I_RegisterSong (FileReader *reader, int device); +struct MidiDeviceSetting; +MusInfo *I_RegisterSong (FileReader *reader, MidiDeviceSetting *device); MusInfo *I_RegisterCDSong (int track, int cdid = 0); MusInfo *I_RegisterURLSong (const char *url); diff --git a/src/sound/i_musicinterns.h b/src/sound/i_musicinterns.h index 275253d84..52364ab58 100644 --- a/src/sound/i_musicinterns.h +++ b/src/sound/i_musicinterns.h @@ -185,7 +185,7 @@ public: class TimidityPPMIDIDevice : public PseudoMIDIDevice { public: - TimidityPPMIDIDevice(); + TimidityPPMIDIDevice(const char *args); ~TimidityPPMIDIDevice(); int Open(void (*callback)(unsigned int, void *, DWORD, DWORD), void *userdata); @@ -270,7 +270,7 @@ protected: class OPLMIDIDevice : public SoftSynthMIDIDevice, protected OPLmusicBlock { public: - OPLMIDIDevice(); + OPLMIDIDevice(const char *args); int Open(void (*callback)(unsigned int, void *, DWORD, DWORD), void *userdata); void Close(); int GetTechnology() const; @@ -303,7 +303,7 @@ namespace Timidity { struct Renderer; } class TimidityMIDIDevice : public SoftSynthMIDIDevice { public: - TimidityMIDIDevice(); + TimidityMIDIDevice(const char *args); ~TimidityMIDIDevice(); int Open(void (*callback)(unsigned int, void *, DWORD, DWORD), void *userdata); @@ -337,7 +337,7 @@ protected: class WildMIDIDevice : public SoftSynthMIDIDevice { public: - WildMIDIDevice(); + WildMIDIDevice(const char *args); ~WildMIDIDevice(); int Open(void (*callback)(unsigned int, void *, DWORD, DWORD), void *userdata); @@ -366,7 +366,7 @@ struct fluid_synth_t; class FluidSynthMIDIDevice : public SoftSynthMIDIDevice { public: - FluidSynthMIDIDevice(); + FluidSynthMIDIDevice(const char *args); ~FluidSynthMIDIDevice(); int Open(void (*callback)(unsigned int, void *, DWORD, DWORD), void *userdata); @@ -431,7 +431,7 @@ protected: class MIDIStreamer : public MusInfo { public: - MIDIStreamer(EMidiDevice type); + MIDIStreamer(EMidiDevice type, const char *args); ~MIDIStreamer(); void MusicVolumeChanged(); @@ -517,6 +517,7 @@ protected: bool CallbackIsThreaded; int LoopLimit; FString DumpFilename; + FString Args; }; // MUS file played with a MIDI stream --------------------------------------- @@ -524,7 +525,7 @@ protected: class MUSSong2 : public MIDIStreamer { public: - MUSSong2(FileReader &reader, EMidiDevice type); + MUSSong2(FileReader &reader, EMidiDevice type, const char *args); ~MUSSong2(); MusInfo *GetOPLDumper(const char *filename); @@ -550,7 +551,7 @@ protected: class MIDISong2 : public MIDIStreamer { public: - MIDISong2(FileReader &reader, EMidiDevice type); + MIDISong2(FileReader &reader, EMidiDevice type, const char *args); ~MIDISong2(); MusInfo *GetOPLDumper(const char *filename); @@ -607,7 +608,7 @@ protected: class HMISong : public MIDIStreamer { public: - HMISong(FileReader &reader, EMidiDevice type); + HMISong(FileReader &reader, EMidiDevice type, const char *args); ~HMISong(); MusInfo *GetOPLDumper(const char *filename); @@ -650,7 +651,7 @@ protected: class XMISong : public MIDIStreamer { public: - XMISong(FileReader &reader, EMidiDevice type); + XMISong(FileReader &reader, EMidiDevice type, const char *args); ~XMISong(); MusInfo *GetOPLDumper(const char *filename); @@ -713,7 +714,7 @@ protected: class OPLMUSSong : public StreamSong { public: - OPLMUSSong (FileReader &reader); + OPLMUSSong (FileReader &reader, const char *args); ~OPLMUSSong (); void Play (bool looping, int subsong); bool IsPlaying (); diff --git a/src/sound/music_fluidsynth_mididevice.cpp b/src/sound/music_fluidsynth_mididevice.cpp index af8fe6667..3be4de56b 100644 --- a/src/sound/music_fluidsynth_mididevice.cpp +++ b/src/sound/music_fluidsynth_mididevice.cpp @@ -255,7 +255,7 @@ CUSTOM_CVAR(Int, fluid_chorus_type, FLUID_CHORUS_DEFAULT_TYPE, CVAR_ARCHIVE|CVAR // //========================================================================== -FluidSynthMIDIDevice::FluidSynthMIDIDevice() +FluidSynthMIDIDevice::FluidSynthMIDIDevice(const char *args) { FluidSynth = NULL; FluidSettings = NULL; @@ -293,7 +293,15 @@ FluidSynthMIDIDevice::FluidSynthMIDIDevice() 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); - if (0 == LoadPatchSets(fluid_patchset)) + + // try loading a patch set that got specified with $mididevice. + int res = 0; + if (args != NULL && *args != 0) + { + res = LoadPatchSets(args); + } + + if (res == 0 && 0 == LoadPatchSets(fluid_patchset)) { #ifdef __unix__ // This is the standard location on Ubuntu. diff --git a/src/sound/music_hmi_midiout.cpp b/src/sound/music_hmi_midiout.cpp index 5fef706dd..ca3ae0905 100644 --- a/src/sound/music_hmi_midiout.cpp +++ b/src/sound/music_hmi_midiout.cpp @@ -128,8 +128,8 @@ extern char MIDI_CommonLengths[15]; // //========================================================================== -HMISong::HMISong (FileReader &reader, EMidiDevice type) -: MIDIStreamer(type), MusHeader(0), Tracks(0) +HMISong::HMISong (FileReader &reader, EMidiDevice type, const char *args) +: MIDIStreamer(type, args), MusHeader(0), Tracks(0) { #ifdef _WIN32 if (ExitEvent == NULL) diff --git a/src/sound/music_midi_timidity.cpp b/src/sound/music_midi_timidity.cpp index dbc56cc56..9f50b4155 100644 --- a/src/sound/music_midi_timidity.cpp +++ b/src/sound/music_midi_timidity.cpp @@ -72,7 +72,7 @@ CUSTOM_CVAR (Int, timidity_frequency, 22050, CVAR_ARCHIVE|CVAR_GLOBALCONFIG) // //========================================================================== -TimidityPPMIDIDevice::TimidityPPMIDIDevice() +TimidityPPMIDIDevice::TimidityPPMIDIDevice(const char *args) : DiskName("zmid"), #ifdef _WIN32 ReadWavePipe(INVALID_HANDLE_VALUE), WriteWavePipe(INVALID_HANDLE_VALUE), @@ -85,7 +85,13 @@ TimidityPPMIDIDevice::TimidityPPMIDIDevice() #ifndef _WIN32 WavePipe[0] = WavePipe[1] = -1; #endif - + + if (args == NULL || *args == 0) args = timidity_exe; + + CommandLine.Format("%s %s -EFchorus=%s -EFreverb=%s -s%d ", + args, *timidity_extargs, + *timidity_chorus, *timidity_reverb, *timidity_frequency); + if (DiskName == NULL) { Printf(PRINT_BOLD, "Could not create temp music file\n"); @@ -187,10 +193,6 @@ int TimidityPPMIDIDevice::Open(void (*callback)(unsigned int, void *, DWORD, DWO Validated = true; #endif // WIN32 - CommandLine.Format("%s %s -EFchorus=%s -EFreverb=%s -s%d ", - *timidity_exe, *timidity_extargs, - *timidity_chorus, *timidity_reverb, *timidity_frequency); - pipeSize = (timidity_pipe * timidity_frequency / 1000) << (timidity_stereo + !timidity_8bit); diff --git a/src/sound/music_midistream.cpp b/src/sound/music_midistream.cpp index a6fb5f4d8..579fd7851 100644 --- a/src/sound/music_midistream.cpp +++ b/src/sound/music_midistream.cpp @@ -89,12 +89,12 @@ static const BYTE StaticMIDIhead[] = // //========================================================================== -MIDIStreamer::MIDIStreamer(EMidiDevice type) +MIDIStreamer::MIDIStreamer(EMidiDevice type, const char *args) : #ifdef _WIN32 PlayerThread(0), ExitEvent(0), BufferDoneEvent(0), #endif - MIDI(0), Division(0), InitialTempo(500000), DeviceType(type) + MIDI(0), Division(0), InitialTempo(500000), DeviceType(type), Args(args) { #ifdef _WIN32 BufferDoneEvent = CreateEvent(NULL, FALSE, FALSE, NULL); @@ -269,19 +269,19 @@ MIDIDevice *MIDIStreamer::CreateMIDIDevice(EMidiDevice devtype) const #ifdef HAVE_FLUIDSYNTH case MDEV_FLUIDSYNTH: - return new FluidSynthMIDIDevice; + return new FluidSynthMIDIDevice(Args); #endif case MDEV_SNDSYS: return new SndSysMIDIDevice; case MDEV_GUS: - return new TimidityMIDIDevice; + return new TimidityMIDIDevice(Args); case MDEV_OPL: try { - return new OPLMIDIDevice; + return new OPLMIDIDevice(Args); } catch (CRecoverableError &err) { @@ -291,10 +291,10 @@ MIDIDevice *MIDIStreamer::CreateMIDIDevice(EMidiDevice devtype) const } case MDEV_TIMIDITY: - return new TimidityPPMIDIDevice; + return new TimidityPPMIDIDevice(Args); case MDEV_WILDMIDI: - return new WildMIDIDevice; + return new WildMIDIDevice(Args); default: return NULL; diff --git a/src/sound/music_mus_midiout.cpp b/src/sound/music_mus_midiout.cpp index 5f7d2d503..bc810b4a8 100644 --- a/src/sound/music_mus_midiout.cpp +++ b/src/sound/music_mus_midiout.cpp @@ -43,6 +43,7 @@ #include "doomdef.h" #include "m_swap.h" #include "files.h" +#include "s_sound.h" // MACROS ------------------------------------------------------------------ @@ -92,8 +93,8 @@ static const BYTE CtrlTranslate[15] = // //========================================================================== -MUSSong2::MUSSong2 (FileReader &reader, EMidiDevice type) -: MIDIStreamer(type), MusHeader(0), MusBuffer(0) +MUSSong2::MUSSong2 (FileReader &reader, EMidiDevice type, const char *args) +: MIDIStreamer(type, args), MusHeader(0), MusBuffer(0) { #ifdef _WIN32 if (ExitEvent == NULL) @@ -210,23 +211,44 @@ bool MUSSong2::CheckDone() void MUSSong2::Precache() { - WORD *work = (WORD *)alloca(MusHeader->NumInstruments * sizeof(WORD)); - const WORD *used = (WORD *)MusHeader + sizeof(MUSHeader) / sizeof(WORD); - int i, j; + TArray work(MusHeader->NumInstruments); + const BYTE *used = (BYTE *)MusHeader + sizeof(MUSHeader) / sizeof(BYTE); + int i, k; - for (i = j = 0; i < MusHeader->NumInstruments; ++i) + for (i = k = 0; i < MusHeader->NumInstruments; ++i) { - WORD instr = LittleShort(used[i]); + BYTE instr = used[k++]; + WORD val; if (instr < 128) { - work[j++] = instr; + val = instr; } - else if (used[i] >= 135 && used[i] <= 181) + else if (instr >= 135 && instr <= 188) { // Percussions are 100-based, not 128-based, eh? - work[j++] = instr - 100 + (1 << 14); + val = instr - 100 + (1 << 14); + } + else + { + // skip it. + val = used[k++]; + k += val; + continue; + } + + int numbanks = used[k++]; + if (numbanks > 0) + { + for (int b = 0; b < numbanks; b++) + { + work.Push(val | (used[k++] << 7)); + } + } + else + { + work.Push(val); } } - MIDI->PrecacheInstruments(&work[0], j); + MIDI->PrecacheInstruments(&work[0], work.Size()); } //========================================================================== diff --git a/src/sound/music_mus_opl.cpp b/src/sound/music_mus_opl.cpp index 3b5012ad9..562330ef9 100644 --- a/src/sound/music_mus_opl.cpp +++ b/src/sound/music_mus_opl.cpp @@ -20,16 +20,25 @@ CUSTOM_CVAR (Int, opl_numchips, 2, CVAR_ARCHIVE|CVAR_GLOBALCONFIG) } } -CVAR(Int, opl_core, 0, CVAR_ARCHIVE|CVAR_GLOBALCONFIG) +CVAR(Int, opl_core, 0, CVAR_ARCHIVE | CVAR_GLOBALCONFIG) +int current_opl_core; -OPLMUSSong::OPLMUSSong (FileReader &reader) +// Get OPL core override from $mididevice +void OPL_SetCore(const char *args) +{ + current_opl_core = opl_core; + if (args != NULL && *args >= '0' && *args < '4') current_opl_core = *args - '0'; +} + +OPLMUSSong::OPLMUSSong (FileReader &reader, const char *args) { int samples = int(OPL_SAMPLE_RATE / 14); + OPL_SetCore(args); Music = new OPLmusicFile (&reader); m_Stream = GSnd->CreateStream (FillStream, samples*4, - (opl_core == 0 ? SoundStream::Mono : 0) | SoundStream::Float, int(OPL_SAMPLE_RATE), this); + (current_opl_core == 0 ? SoundStream::Mono : 0) | SoundStream::Float, int(OPL_SAMPLE_RATE), this); if (m_Stream == NULL) { Printf (PRINT_BOLD, "Could not create music stream.\n"); diff --git a/src/sound/music_smf_midiout.cpp b/src/sound/music_smf_midiout.cpp index 49fd12502..43755eb08 100644 --- a/src/sound/music_smf_midiout.cpp +++ b/src/sound/music_smf_midiout.cpp @@ -102,8 +102,8 @@ char MIDI_CommonLengths[15] = { 0, 1, 2, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; // //========================================================================== -MIDISong2::MIDISong2 (FileReader &reader, EMidiDevice type) -: MIDIStreamer(type), MusHeader(0), Tracks(0) +MIDISong2::MIDISong2 (FileReader &reader, EMidiDevice type, const char *args) +: MIDIStreamer(type, args), MusHeader(0), Tracks(0) { int p; int i; diff --git a/src/sound/music_timidity_mididevice.cpp b/src/sound/music_timidity_mididevice.cpp index 9e5be625b..a63e1d723 100644 --- a/src/sound/music_timidity_mididevice.cpp +++ b/src/sound/music_timidity_mididevice.cpp @@ -86,10 +86,10 @@ struct FmtChunk // //========================================================================== -TimidityMIDIDevice::TimidityMIDIDevice() +TimidityMIDIDevice::TimidityMIDIDevice(const char *args) { Renderer = NULL; - Renderer = new Timidity::Renderer((float)SampleRate); + Renderer = new Timidity::Renderer((float)SampleRate, args); } //========================================================================== @@ -245,6 +245,7 @@ FString TimidityMIDIDevice::GetStats() //========================================================================== TimidityWaveWriterMIDIDevice::TimidityWaveWriterMIDIDevice(const char *filename, int rate) + :TimidityMIDIDevice(NULL) { File = fopen(filename, "wb"); if (File != NULL) diff --git a/src/sound/music_wildmidi_mididevice.cpp b/src/sound/music_wildmidi_mididevice.cpp index c3fd674c9..88550226a 100644 --- a/src/sound/music_wildmidi_mididevice.cpp +++ b/src/sound/music_wildmidi_mididevice.cpp @@ -81,7 +81,7 @@ CUSTOM_CVAR(Bool, wildmidi_enhanced_resampling, true, CVAR_ARCHIVE | CVAR_GLOBAL // //========================================================================== -WildMIDIDevice::WildMIDIDevice() +WildMIDIDevice::WildMIDIDevice(const char *args) { Renderer = NULL; @@ -94,16 +94,18 @@ WildMIDIDevice::WildMIDIDevice() SampleRate = clamp(SampleRate, 11025, 65535); } - if (CurrentConfig.CompareNoCase(wildmidi_config) != 0 || SampleRate != WildMidi_GetSampleRate()) + if (args == NULL || *args == 0) args = wildmidi_config; + + if (CurrentConfig.CompareNoCase(args) != 0 || SampleRate != WildMidi_GetSampleRate()) { if (CurrentConfig.IsNotEmpty()) { WildMidi_Shutdown(); CurrentConfig = ""; } - if (!WildMidi_Init(wildmidi_config, SampleRate, 0)) + if (!WildMidi_Init(args, SampleRate, 0)) { - CurrentConfig = wildmidi_config; + CurrentConfig = args; } } if (CurrentConfig.IsNotEmpty()) diff --git a/src/sound/music_xmi_midiout.cpp b/src/sound/music_xmi_midiout.cpp index 6c179a16a..71246f518 100644 --- a/src/sound/music_xmi_midiout.cpp +++ b/src/sound/music_xmi_midiout.cpp @@ -108,8 +108,8 @@ extern char MIDI_CommonLengths[15]; // //========================================================================== -XMISong::XMISong (FileReader &reader, EMidiDevice type) -: MIDIStreamer(type), MusHeader(0), Songs(0) +XMISong::XMISong (FileReader &reader, EMidiDevice type, const char *args) +: MIDIStreamer(type, args), MusHeader(0), Songs(0) { #ifdef _WIN32 if (ExitEvent == NULL) diff --git a/src/timidity/timidity.cpp b/src/timidity/timidity.cpp index 09b5ae7b5..807bc07b7 100644 --- a/src/timidity/timidity.cpp +++ b/src/timidity/timidity.cpp @@ -678,8 +678,9 @@ int LoadDMXGUS() return 0; } -Renderer::Renderer(float sample_rate) +Renderer::Renderer(float sample_rate, const char *args) { + // 'args' should be used to load a custom config or DMXGUS, but since setup currently requires a snd_reset call, this will need some refactoring first rate = sample_rate; patches = NULL; resample_buffer_size = 0; diff --git a/src/timidity/timidity.h b/src/timidity/timidity.h index 59ba5f8ad..45e23a9f9 100644 --- a/src/timidity/timidity.h +++ b/src/timidity/timidity.h @@ -630,7 +630,7 @@ struct Renderer int voices; int lost_notes, cut_notes; - Renderer(float sample_rate); + Renderer(float sample_rate, const char *args); ~Renderer(); void HandleEvent(int status, int parm1, int parm2); diff --git a/src/version.h b/src/version.h index 3034e2c3e..31452b55d 100644 --- a/src/version.h +++ b/src/version.h @@ -76,7 +76,7 @@ const char *GetVersionString(); // Use 4500 as the base git save version, since it's higher than the // SVN revision ever got. -#define SAVEVER 4526 +#define SAVEVER 4527 #define SAVEVERSTRINGIFY2(x) #x #define SAVEVERSTRINGIFY(x) SAVEVERSTRINGIFY2(x) diff --git a/src/wildmidi/wildmidi_lib.cpp b/src/wildmidi/wildmidi_lib.cpp index 94a446e17..0a527ec2a 100644 --- a/src/wildmidi/wildmidi_lib.cpp +++ b/src/wildmidi/wildmidi_lib.cpp @@ -2719,14 +2719,14 @@ midi *WildMidi_NewMidi() { } } - if ((((_mdi*)ret)->reverb = _WM_init_reverb(_WM_SampleRate, reverb_room_width, - reverb_room_length, reverb_listen_posx, reverb_listen_posy)) - == NULL) { - _WM_ERROR(__FUNCTION__, __LINE__, WM_ERR_MEM, "to init reverb", 0); + if ((((_mdi*)ret)->reverb = _WM_init_reverb(_WM_SampleRate, reverb_room_width, + reverb_room_length, reverb_listen_posx, reverb_listen_posy)) + == NULL) { + _WM_ERROR(__FUNCTION__, __LINE__, WM_ERR_MEM, "to init reverb", 0); WildMidi_Close(ret); ret = NULL; - } - + } + return ret; } diff --git a/wadsrc/static/actors/constants.txt b/wadsrc/static/actors/constants.txt index 956ed119f..213e2109d 100644 --- a/wadsrc/static/actors/constants.txt +++ b/wadsrc/static/actors/constants.txt @@ -129,6 +129,10 @@ const int WRF_NOFIRE = WRF_NOPRIMARY | WRF_NOSECONDARY; const int WRF_ALLOWRELOAD = 16; const int WRF_ALLOWZOOM = 32; const int WRF_DISABLESWITCH = 64; +const int WRF_ALLOWUSER1 = 128; +const int WRF_ALLOWUSER2 = 256; +const int WRF_ALLOWUSER3 = 512; +const int WRF_ALLOWUSER4 = 1024; // Morph constants const int MRF_ADDSTAMINA = 1; diff --git a/wadsrc/static/menudef.txt b/wadsrc/static/menudef.txt index 53c2af6dc..84703101e 100644 --- a/wadsrc/static/menudef.txt +++ b/wadsrc/static/menudef.txt @@ -435,8 +435,12 @@ OptionMenu "CustomizeControls" StaticText "Controls", 1 Control "Fire", "+attack" Control "Secondary Fire", "+altattack" - Control "Weapon Reload", "+reload" - Control "Weapon Zoom", "+zoom" + Control "Weapon Reload", "+reload" + Control "Weapon Zoom", "+zoom" + Control "Weapon State 1", "+user1" + Control "Weapon State 2", "+user2" + Control "Weapon State 3", "+user3" + Control "Weapon State 4", "+user4" Control "Use / Open", "+use" Control "Move forward", "+forward" Control "Move backward", "+back"