ref: ef1ba7ed5da0ddfd59b1b6d828c44db598dcca4f
dir: /s_sound.c/
//**************************************************************************
//**
//** S_SOUND.C: MUSIC & SFX API
//**
//** $Revision: 590 $
//** $Date: 2012-10-23 23:55:31 +0300 (Tue, 23 Oct 2012) $
//**
//**************************************************************************
// HEADER FILES ------------------------------------------------------------
#include "h2stdinc.h"
#include "h2def.h"
#include "p_local.h" /* P_AproxDistance() */
#include "sounds.h"
#include "i_sound.h"
#include "i_cdmus.h"
#include "soundst.h"
// MACROS ------------------------------------------------------------------
#define DEFAULT_ARCHIVEPATH "o:\\sound\\archive\\"
#define PRIORITY_MAX_ADJUST 10
#define DIST_ADJUST (MAX_SND_DIST/PRIORITY_MAX_ADJUST)
// TYPES -------------------------------------------------------------------
// EXTERNAL FUNCTION PROTOTYPES --------------------------------------------
// PUBLIC FUNCTION PROTOTYPES ----------------------------------------------
// PRIVATE FUNCTION PROTOTYPES ---------------------------------------------
static boolean S_StopSoundID(int sound_id, int priority);
// EXTERNAL DATA DECLARATIONS ----------------------------------------------
extern int snd_MaxVolume;
extern int snd_MusicVolume;
extern int snd_Channels;
#ifdef __WATCOMC__
extern int snd_SfxDevice;
extern int snd_MusicDevice;
extern int snd_DesiredSfxDevice;
extern int snd_DesiredMusicDevice;
extern int tsm_ID;
#endif
extern void **lumpcache;
extern int startepisode;
extern int startmap;
// PUBLIC DATA DEFINITIONS -------------------------------------------------
/* Sound info */
sfxinfo_t S_sfx[] =
{
/* tagname, lumpname, priority, usefulness, snd_ptr, lumpnum, numchannels, */
/* pitchshift */
{ "", "", 0, -1, NULL, 0, 0, 0 },
{ "PlayerFighterNormalDeath", "", 256, -1, NULL, 0, 2, 1 },
{ "PlayerFighterCrazyDeath", "", 256, -1, NULL, 0, 2, 1 },
{ "PlayerFighterExtreme1Death", "", 256, -1, NULL, 0, 2, 1 },
{ "PlayerFighterExtreme2Death", "", 256, -1, NULL, 0, 2, 1 },
{ "PlayerFighterExtreme3Death", "", 256, -1, NULL, 0, 2, 1 },
{ "PlayerFighterBurnDeath", "", 256, -1, NULL, 0, 2, 1 },
{ "PlayerClericNormalDeath", "", 256, -1, NULL, 0, 2, 1 },
{ "PlayerClericCrazyDeath", "", 256, -1, NULL, 0, 2, 1 },
{ "PlayerClericExtreme1Death", "", 256, -1, NULL, 0, 2, 1 },
{ "PlayerClericExtreme2Death", "", 256, -1, NULL, 0, 2, 1 },
{ "PlayerClericExtreme3Death", "", 256, -1, NULL, 0, 2, 1 },
{ "PlayerClericBurnDeath", "", 256, -1, NULL, 0, 2, 1 },
{ "PlayerMageNormalDeath", "", 256, -1, NULL, 0, 2, 0 },
{ "PlayerMageCrazyDeath", "", 256, -1, NULL, 0, 2, 0 },
{ "PlayerMageExtreme1Death", "", 256, -1, NULL, 0, 2, 0 },
{ "PlayerMageExtreme2Death", "", 256, -1, NULL, 0, 2, 0 },
{ "PlayerMageExtreme3Death", "", 256, -1, NULL, 0, 2, 0 },
{ "PlayerMageBurnDeath", "", 256, -1, NULL, 0, 2, 0 },
{ "PlayerFighterPain", "", 256, -1, NULL, 0, 2, 1 },
{ "PlayerClericPain", "", 256, -1, NULL, 0, 2, 1 },
{ "PlayerMagePain", "", 256, -1, NULL, 0, 2, 0 },
{ "PlayerFighterGrunt", "", 256, -1, NULL, 0, 2, 1 },
{ "PlayerClericGrunt", "", 256, -1, NULL, 0, 2, 1 },
{ "PlayerMageGrunt", "", 256, -1, NULL, 0, 2, 0 },
{ "PlayerLand", "", 32, -1, NULL, 0, 2, 1 },
{ "PlayerPoisonCough", "", 256, -1, NULL, 0, 2, 1 },
{ "PlayerFighterFallingScream", "", 256, -1, NULL, 0, 2, 1 },
{ "PlayerClericFallingScream", "", 256, -1, NULL, 0, 2, 1 },
{ "PlayerMageFallingScream", "", 256, -1, NULL, 0, 2, 0 },
{ "PlayerFallingSplat", "", 256, -1, NULL, 0, 2, 1 },
{ "PlayerFighterFailedUse", "", 256, -1, NULL, 0, 1, 1 },
{ "PlayerClericFailedUse", "", 256, -1, NULL, 0, 1, 1 },
{ "PlayerMageFailedUse", "", 256, -1, NULL, 0, 1, 0 },
{ "PlatformStart", "", 36, -1, NULL, 0, 2, 1 },
{ "PlatformStartMetal", "", 36, -1, NULL, 0, 2, 1 },
{ "PlatformStop", "", 40, -1, NULL, 0, 2, 1 },
{ "StoneMove", "", 32, -1, NULL, 0, 2, 1 },
{ "MetalMove", "", 32, -1, NULL, 0, 2, 1 },
{ "DoorOpen", "", 36, -1, NULL, 0, 2, 1 },
{ "DoorLocked", "", 36, -1, NULL, 0, 2, 1 },
{ "DoorOpenMetal", "", 36, -1, NULL, 0, 2, 1 },
{ "DoorCloseMetal", "", 36, -1, NULL, 0, 2, 1 },
{ "DoorCloseLight", "", 36, -1, NULL, 0, 2, 1 },
{ "DoorCloseHeavy", "", 36, -1, NULL, 0, 2, 1 },
{ "DoorCreak", "", 36, -1, NULL, 0, 2, 1 },
{ "PickupWeapon", "", 36, -1, NULL, 0, 2, 0 },
{ "PickupArtifact", "", 36, -1, NULL, 0, 2, 1 },
{ "PickupKey", "", 36, -1, NULL, 0, 2, 1 },
{ "PickupItem", "", 36, -1, NULL, 0, 2, 1 },
{ "PickupPiece", "", 36, -1, NULL, 0, 2, 0 },
{ "WeaponBuild", "", 36, -1, NULL, 0, 2, 0 },
{ "UseArtifact", "", 36, -1, NULL, 0, 2, 1 },
{ "BlastRadius", "", 36, -1, NULL, 0, 2, 1 },
{ "Teleport", "", 256, -1, NULL, 0, 2, 1 },
{ "ThunderCrash", "", 30, -1, NULL, 0, 2, 1 },
{ "FighterPunchMiss", "", 80, -1, NULL, 0, 2, 1 },
{ "FighterPunchHitThing", "", 80, -1, NULL, 0, 2, 1 },
{ "FighterPunchHitWall", "", 80, -1, NULL, 0, 2, 1 },
{ "FighterGrunt", "", 80, -1, NULL, 0, 2, 1 },
{ "FighterAxeHitThing", "", 80, -1, NULL, 0, 2, 1 },
{ "FighterHammerMiss", "", 80, -1, NULL, 0, 2, 1 },
{ "FighterHammerHitThing", "", 80, -1, NULL, 0, 2, 1 },
{ "FighterHammerHitWall", "", 80, -1, NULL, 0, 2, 1 },
{ "FighterHammerContinuous", "", 32, -1, NULL, 0, 2, 1 },
{ "FighterHammerExplode", "", 80, -1, NULL, 0, 2, 1 },
{ "FighterSwordFire", "", 80, -1, NULL, 0, 2, 1 },
{ "FighterSwordExplode", "", 80, -1, NULL, 0, 2, 1 },
{ "ClericCStaffFire", "", 80, -1, NULL, 0, 2, 1 },
{ "ClericCStaffExplode", "", 40, -1, NULL, 0, 2, 1 },
{ "ClericCStaffHitThing", "", 80, -1, NULL, 0, 2, 1 },
{ "ClericFlameFire", "", 80, -1, NULL, 0, 2, 1 },
{ "ClericFlameExplode", "", 80, -1, NULL, 0, 2, 1 },
{ "ClericFlameCircle", "", 80, -1, NULL, 0, 2, 1 },
{ "MageWandFire", "", 80, -1, NULL, 0, 2, 1 },
{ "MageLightningFire", "", 80, -1, NULL, 0, 2, 1 },
{ "MageLightningZap", "", 32, -1, NULL, 0, 2, 1 },
{ "MageLightningContinuous", "", 32, -1, NULL, 0, 2, 1 },
{ "MageLightningReady", "", 30, -1, NULL, 0, 2, 1 },
{ "MageShardsFire","", 80, -1, NULL, 0, 2, 1 },
{ "MageShardsExplode","", 36, -1, NULL, 0, 2, 1 },
{ "MageStaffFire","", 80, -1, NULL, 0, 2, 1 },
{ "MageStaffExplode","", 40, -1, NULL, 0, 2, 1 },
{ "Switch1", "", 32, -1, NULL, 0, 2, 1 },
{ "Switch2", "", 32, -1, NULL, 0, 2, 1 },
{ "SerpentSight", "", 32, -1, NULL, 0, 2, 1 },
{ "SerpentActive", "", 32, -1, NULL, 0, 2, 1 },
{ "SerpentPain", "", 32, -1, NULL, 0, 2, 1 },
{ "SerpentAttack", "", 32, -1, NULL, 0, 2, 1 },
{ "SerpentMeleeHit", "", 32, -1, NULL, 0, 2, 1 },
{ "SerpentDeath", "", 40, -1, NULL, 0, 2, 1 },
{ "SerpentBirth", "", 32, -1, NULL, 0, 2, 1 },
{ "SerpentFXContinuous", "", 32, -1, NULL, 0, 2, 1 },
{ "SerpentFXHit", "", 32, -1, NULL, 0, 2, 1 },
{ "PotteryExplode", "", 32, -1, NULL, 0, 2, 1 },
{ "Drip", "", 32, -1, NULL, 0, 2, 1 },
{ "CentaurSight", "", 32, -1, NULL, 0, 2, 1 },
{ "CentaurActive", "", 32, -1, NULL, 0, 2, 1 },
{ "CentaurPain", "", 32, -1, NULL, 0, 2, 1 },
{ "CentaurAttack", "", 32, -1, NULL, 0, 2, 1 },
{ "CentaurDeath", "", 40, -1, NULL, 0, 2, 1 },
{ "CentaurLeaderAttack", "", 32, -1, NULL, 0, 2, 1 },
{ "CentaurMissileExplode", "", 32, -1, NULL, 0, 2, 1 },
{ "Wind", "", 1, -1, NULL, 0, 2, 1 },
{ "BishopSight", "", 32, -1, NULL, 0, 2, 1 },
{ "BishopActive", "", 32, -1, NULL, 0, 2, 1 },
{ "BishopPain", "", 32, -1, NULL, 0, 2, 1 },
{ "BishopAttack", "", 32, -1, NULL, 0, 2, 1 },
{ "BishopDeath", "", 40, -1, NULL, 0, 2, 1 },
{ "BishopMissileExplode", "", 32, -1, NULL, 0, 2, 1 },
{ "BishopBlur", "", 32, -1, NULL, 0, 2, 1 },
{ "DemonSight", "", 32, -1, NULL, 0, 2, 1 },
{ "DemonActive", "", 32, -1, NULL, 0, 2, 1 },
{ "DemonPain", "", 32, -1, NULL, 0, 2, 1 },
{ "DemonAttack", "", 32, -1, NULL, 0, 2, 1 },
{ "DemonMissileFire", "", 32, -1, NULL, 0, 2, 1 },
{ "DemonMissileExplode", "", 32, -1, NULL, 0, 2, 1 },
{ "DemonDeath", "", 40, -1, NULL, 0, 2, 1 },
{ "WraithSight", "", 32, -1, NULL, 0, 2, 1 },
{ "WraithActive", "", 32, -1, NULL, 0, 2, 1 },
{ "WraithPain", "", 32, -1, NULL, 0, 2, 1 },
{ "WraithAttack", "", 32, -1, NULL, 0, 2, 1 },
{ "WraithMissileFire", "", 32, -1, NULL, 0, 2, 1 },
{ "WraithMissileExplode", "", 32, -1, NULL, 0, 2, 1 },
{ "WraithDeath", "", 40, -1, NULL, 0, 2, 1 },
{ "PigActive1", "", 32, -1, NULL, 0, 2, 1 },
{ "PigActive2", "", 32, -1, NULL, 0, 2, 1 },
{ "PigPain", "", 32, -1, NULL, 0, 2, 1 },
{ "PigAttack", "", 32, -1, NULL, 0, 2, 1 },
{ "PigDeath", "", 40, -1, NULL, 0, 2, 1 },
{ "MaulatorSight", "", 32, -1, NULL, 0, 2, 1 },
{ "MaulatorActive", "", 32, -1, NULL, 0, 2, 1 },
{ "MaulatorPain", "", 32, -1, NULL, 0, 2, 1 },
{ "MaulatorHamSwing", "", 32, -1, NULL, 0, 2, 1 },
{ "MaulatorHamHit", "", 32, -1, NULL, 0, 2, 1 },
{ "MaulatorMissileHit", "", 32, -1, NULL, 0, 2, 1 },
{ "MaulatorDeath", "", 40, -1, NULL, 0, 2, 1 },
{ "FreezeDeath", "", 40, -1, NULL, 0, 2, 1 },
{ "FreezeShatter", "", 40, -1, NULL, 0, 2, 1 },
{ "EttinSight", "", 32, -1, NULL, 0, 2, 1 },
{ "EttinActive", "", 32, -1, NULL, 0, 2, 1 },
{ "EttinPain", "", 32, -1, NULL, 0, 2, 1 },
{ "EttinAttack", "", 32, -1, NULL, 0, 2, 1 },
{ "EttinDeath", "", 40, -1, NULL, 0, 2, 1 },
{ "FireDemonSpawn", "", 32, -1, NULL, 0, 2, 1 },
{ "FireDemonActive", "", 32, -1, NULL, 0, 2, 1 },
{ "FireDemonPain", "", 32, -1, NULL, 0, 2, 1 },
{ "FireDemonAttack", "", 32, -1, NULL, 0, 2, 1 },
{ "FireDemonMissileHit", "", 32, -1, NULL, 0, 2, 1 },
{ "FireDemonDeath", "", 40, -1, NULL, 0, 2, 1 },
{ "IceGuySight", "", 32, -1, NULL, 0, 2, 1 },
{ "IceGuyActive", "", 32, -1, NULL, 0, 2, 1 },
{ "IceGuyAttack", "", 32, -1, NULL, 0, 2, 1 },
{ "IceGuyMissileExplode", "", 32, -1, NULL, 0, 2, 1 },
{ "SorcererSight", "", 256, -1, NULL, 0, 2, 1 },
{ "SorcererActive", "", 256, -1, NULL, 0, 2, 1 },
{ "SorcererPain", "", 256, -1, NULL, 0, 2, 1 },
{ "SorcererSpellCast", "", 256, -1, NULL, 0, 2, 1 },
{ "SorcererBallWoosh", "", 256, -1, NULL, 0, 4, 1 },
{ "SorcererDeathScream", "", 256, -1, NULL, 0, 2, 1 },
{ "SorcererBishopSpawn", "", 80, -1, NULL, 0, 2, 1 },
{ "SorcererBallPop", "", 80, -1, NULL, 0, 2, 1 },
{ "SorcererBallBounce", "", 80, -1, NULL, 0, 3, 1 },
{ "SorcererBallExplode", "", 80, -1, NULL, 0, 3, 1 },
{ "SorcererBigBallExplode", "", 80, -1, NULL, 0, 3, 1 },
{ "SorcererHeadScream", "", 256, -1, NULL, 0, 2, 1 },
{ "DragonSight", "", 64, -1, NULL, 0, 2, 1 },
{ "DragonActive", "", 64, -1, NULL, 0, 2, 1 },
{ "DragonWingflap", "", 64, -1, NULL, 0, 2, 1 },
{ "DragonAttack", "", 64, -1, NULL, 0, 2, 1 },
{ "DragonPain", "", 64, -1, NULL, 0, 2, 1 },
{ "DragonDeath", "", 64, -1, NULL, 0, 2, 1 },
{ "DragonFireballExplode", "", 32, -1, NULL, 0, 2, 1 },
{ "KoraxSight", "", 256, -1, NULL, 0, 2, 1 },
{ "KoraxActive", "", 256, -1, NULL, 0, 2, 1 },
{ "KoraxPain", "", 256, -1, NULL, 0, 2, 1 },
{ "KoraxAttack", "", 256, -1, NULL, 0, 2, 1 },
{ "KoraxCommand", "", 256, -1, NULL, 0, 2, 1 },
{ "KoraxDeath", "", 256, -1, NULL, 0, 2, 1 },
{ "KoraxStep", "", 128, -1, NULL, 0, 2, 1 },
{ "ThrustSpikeRaise", "", 32, -1, NULL, 0, 2, 1 },
{ "ThrustSpikeLower", "", 32, -1, NULL, 0, 2, 1 },
{ "GlassShatter", "", 32, -1, NULL, 0, 2, 1 },
{ "FlechetteBounce", "", 32, -1, NULL, 0, 2, 1 },
{ "FlechetteExplode", "", 32, -1, NULL, 0, 2, 1 },
{ "LavaMove", "", 36, -1, NULL, 0, 2, 1 },
{ "WaterMove", "", 36, -1, NULL, 0, 2, 1 },
{ "IceStartMove", "", 36, -1, NULL, 0, 2, 1 },
{ "EarthStartMove", "", 36, -1, NULL, 0, 2, 1 },
{ "WaterSplash", "", 32, -1, NULL, 0, 2, 1 },
{ "LavaSizzle", "", 32, -1, NULL, 0, 2, 1 },
{ "SludgeGloop", "", 32, -1, NULL, 0, 2, 1 },
{ "HolySymbolFire", "", 64, -1, NULL, 0, 2, 1 },
{ "SpiritActive", "", 32, -1, NULL, 0, 2, 1 },
{ "SpiritAttack", "", 32, -1, NULL, 0, 2, 1 },
{ "SpiritDie", "", 32, -1, NULL, 0, 2, 1 },
{ "ValveTurn", "", 36, -1, NULL, 0, 2, 1 },
{ "RopePull", "", 36, -1, NULL, 0, 2, 1 },
{ "FlyBuzz", "", 20, -1, NULL, 0, 2, 1 },
{ "Ignite", "", 32, -1, NULL, 0, 2, 1 },
{ "PuzzleSuccess", "", 256, -1, NULL, 0, 2, 1 },
{ "PuzzleFailFighter", "", 256, -1, NULL, 0, 2, 1 },
{ "PuzzleFailCleric", "", 256, -1, NULL, 0, 2, 1 },
{ "PuzzleFailMage", "", 256, -1, NULL, 0, 2, 1 },
{ "Earthquake", "", 32, -1, NULL, 0, 2, 1 },
{ "BellRing", "", 32, -1, NULL, 0, 2, 0 },
{ "TreeBreak", "", 32, -1, NULL, 0, 2, 1 },
{ "TreeExplode", "", 32, -1, NULL, 0, 2, 1 },
{ "SuitofArmorBreak", "", 32, -1, NULL, 0, 2, 1 },
{ "PoisonShroomPain", "", 20, -1, NULL, 0, 2, 1 },
{ "PoisonShroomDeath", "", 32, -1, NULL, 0, 2, 1 },
{ "Ambient1", "", 1, -1, NULL, 0, 1, 1 },
{ "Ambient2", "", 1, -1, NULL, 0, 1, 1 },
{ "Ambient3", "", 1, -1, NULL, 0, 1, 1 },
{ "Ambient4", "", 1, -1, NULL, 0, 1, 1 },
{ "Ambient5", "", 1, -1, NULL, 0, 1, 1 },
{ "Ambient6", "", 1, -1, NULL, 0, 1, 1 },
{ "Ambient7", "", 1, -1, NULL, 0, 1, 1 },
{ "Ambient8", "", 1, -1, NULL, 0, 1, 1 },
{ "Ambient9", "", 1, -1, NULL, 0, 1, 1 },
{ "Ambient10", "", 1, -1, NULL, 0, 1, 1 },
{ "Ambient11", "", 1, -1, NULL, 0, 1, 1 },
{ "Ambient12", "", 1, -1, NULL, 0, 1, 1 },
{ "Ambient13", "", 1, -1, NULL, 0, 1, 1 },
{ "Ambient14", "", 1, -1, NULL, 0, 1, 1 },
{ "Ambient15", "", 1, -1, NULL, 0, 1, 1 },
{ "StartupTick", "", 32, -1, NULL, 0, 2, 1 },
{ "SwitchOtherLevel", "", 32, -1, NULL, 0, 2, 1 },
{ "Respawn", "", 32, -1, NULL, 0, 2, 1 },
{ "KoraxVoiceGreetings", "", 512, -1, NULL, 0, 2, 1 },
{ "KoraxVoiceReady", "", 512, -1, NULL, 0, 2, 1 },
{ "KoraxVoiceBlood", "", 512, -1, NULL, 0, 2, 1 },
{ "KoraxVoiceGame", "", 512, -1, NULL, 0, 2, 1 },
{ "KoraxVoiceBoard", "", 512, -1, NULL, 0, 2, 1 },
{ "KoraxVoiceWorship", "", 512, -1, NULL, 0, 2, 1 },
{ "KoraxVoiceMaybe", "", 512, -1, NULL, 0, 2, 1 },
{ "KoraxVoiceStrong", "", 512, -1, NULL, 0, 2, 1 },
{ "KoraxVoiceFace", "", 512, -1, NULL, 0, 2, 1 },
{ "BatScream", "", 32, -1, NULL, 0, 2, 1 },
{ "Chat", "", 512, -1, NULL, 0, 2, 1 },
{ "MenuMove", "", 32, -1, NULL, 0, 2, 1 },
{ "ClockTick", "", 32, -1, NULL, 0, 2, 1 },
{ "Fireball", "", 32, -1, NULL, 0, 2, 1 },
{ "PuppyBeat", "", 30, -1, NULL, 0, 2, 1 },
{ "MysticIncant", "", 32, -1, NULL, 0, 4, 1 }
};
// PRIVATE DATA DEFINITIONS ------------------------------------------------
static channel_t Channel[MAX_CHANNELS];
static int RegisteredSong; /* the current registered song. */
static int isExternalSong;
static int NextCleanup;
static boolean MusicPaused;
static int Mus_Song = -1;
static int Mus_LumpNum;
static void *Mus_SndPtr;
static byte *SoundCurve;
static boolean UseSndScript;
static char ArchivePath[MAX_OSPATH];
// CODE --------------------------------------------------------------------
//==========================================================================
//
// S_Init
//
//==========================================================================
void S_Init(void)
{
SoundCurve = (byte *) W_CacheLumpName("SNDCURVE", PU_STATIC);
// SoundCurve = (byte *) Z_Malloc(MAX_SND_DIST, PU_STATIC, NULL);
I_StartupSound();
if (snd_Channels > 8)
{
snd_Channels = 8;
}
I_SetChannels(snd_Channels);
I_SetMusicVolume(snd_MusicVolume);
// Attempt to setup CD music
ST_Message("Initializing CD Audio: ");
i_CDMusic = (I_CDMusInit() != -1);
if (i_CDMusic)
{
ST_Message("success.\n");
}
else
{
ST_Message("failed.\n");
}
}
//==========================================================================
//
// S_InitScript
//
//==========================================================================
void S_InitScript(void)
{
int p;
int i;
strcpy(ArchivePath, DEFAULT_ARCHIVEPATH);
p = M_CheckParm("-devsnd");
if (p && p < myargc - 1)
{
UseSndScript = true;
SC_OpenFile(myargv[p+1]);
}
else
{
UseSndScript = false;
SC_OpenLump("sndinfo");
}
while (SC_GetString())
{
if (*sc_String == '$')
{
if (!cistrcmp(sc_String, "$ARCHIVEPATH"))
{
SC_MustGetString();
strcpy(ArchivePath, sc_String);
}
else if (!cistrcmp(sc_String, "$MAP"))
{
SC_MustGetNumber();
SC_MustGetString();
if (sc_Number)
{
P_PutMapSongLump(sc_Number, sc_String);
}
}
continue;
}
else
{
for (i = 0; i < NUMSFX; i++)
{
if (!strcmp(S_sfx[i].tagName, sc_String))
{
SC_MustGetString();
if (*sc_String != '?')
{
strcpy(S_sfx[i].lumpname, sc_String);
}
else
{
strcpy(S_sfx[i].lumpname, "default");
}
break;
}
}
if (i == NUMSFX)
{
SC_MustGetString();
}
}
}
SC_Close();
for (i = 0; i < NUMSFX; i++)
{
if (!strcmp(S_sfx[i].lumpname, ""))
{
strcpy(S_sfx[i].lumpname, "default");
}
}
}
//==========================================================================
//
// S_ShutDown
//
//==========================================================================
void S_ShutDown(void)
{
if (i_CDMusic)
{
I_CDMusStop();
}
I_CDMusShutdown();
#ifdef __WATCOMC__
if (tsm_ID == -1)
return;
#endif
if (RegisteredSong)
{
I_StopSong(RegisteredSong);
I_UnRegisterSong(RegisteredSong);
}
I_ShutdownSound();
}
//==========================================================================
//
// S_Start
//
//==========================================================================
void S_Start(void)
{
S_StopAllSound();
S_StartSong(gamemap, true);
}
//==========================================================================
//
// S_StartSong
//
//==========================================================================
void S_StartSong(int song, boolean loop)
{
const char *songLump;
int track;
if (i_CDMusic && cdaudio)
{ // Play a CD track, instead
if (i_CDTrack)
{ // Default to the player-chosen track
track = i_CDTrack;
}
else
{
track = P_GetMapCDTrack(gamemap);
}
if (track == i_CDCurrentTrack && i_CDMusicLength > 0)
{
return;
}
if (!I_CDMusPlay(track))
{
/*
if (loop)
{
// i_CDMusicLength = 35*I_CDMusTrackLength(track);
oldTic = gametic;
}
else
{
i_CDMusicLength = -1;
}
*/
i_CDCurrentTrack = track;
}
}
else
{
if (song == Mus_Song)
{ // don't replay an old song
return;
}
if (RegisteredSong)
{
I_StopSong(RegisteredSong);
I_UnRegisterSong(RegisteredSong);
if (!isExternalSong)
{
if (UseSndScript)
{
Z_Free(Mus_SndPtr);
}
else
{
Z_ChangeTag(lumpcache[Mus_LumpNum], PU_CACHE);
}
#ifdef __WATCOMC__
_dpmi_unlockregion(Mus_SndPtr, lumpinfo[Mus_LumpNum].size);
#endif
}
RegisteredSong = 0;
}
songLump = P_GetMapSongLump(song);
if (!songLump)
{
return;
}
isExternalSong = I_RegisterExternalSong(songLump);
if (isExternalSong)
{
RegisteredSong = isExternalSong;
I_PlaySong(RegisteredSong, loop);
Mus_Song = song;
return;
}
if (UseSndScript)
{
char name[MAX_OSPATH];
snprintf(name, sizeof(name), "%s%s.lmp", ArchivePath, songLump);
M_ReadFile(name, &Mus_SndPtr);
}
else
{
Mus_LumpNum = W_GetNumForName(songLump);
Mus_SndPtr = W_CacheLumpNum(Mus_LumpNum, PU_MUSIC);
}
#ifdef __WATCOMC__
_dpmi_lockregion(Mus_SndPtr, lumpinfo[Mus_LumpNum].size);
#endif
RegisteredSong = I_RegisterSong(Mus_SndPtr);
I_PlaySong(RegisteredSong, loop); // 'true' denotes endless looping.
Mus_Song = song;
}
}
//==========================================================================
//
// S_StartSongName
//
//==========================================================================
void S_StartSongName(const char *songLump, boolean loop)
{
int cdTrack;
if (!songLump)
{
return;
}
if (i_CDMusic && cdaudio)
{
cdTrack = 0;
if (!strcmp(songLump, "hexen"))
{
cdTrack = P_GetCDTitleTrack();
}
else if (!strcmp(songLump, "hub"))
{
cdTrack = P_GetCDIntermissionTrack();
}
else if (!strcmp(songLump, "hall"))
{
cdTrack = P_GetCDEnd1Track();
}
else if (!strcmp(songLump, "orb"))
{
cdTrack = P_GetCDEnd2Track();
}
else if (!strcmp(songLump, "chess") && !i_CDTrack)
{
cdTrack = P_GetCDEnd3Track();
}
/* Uncomment this, if Kevin writes a specific song for startup
else if (!strcmp(songLump, "start"))
{
cdTrack = P_GetCDStartTrack();
}
*/
if (!cdTrack || (cdTrack == i_CDCurrentTrack && i_CDMusicLength > 0))
{
return;
}
if (!I_CDMusPlay(cdTrack))
{
/*
if (loop)
{
i_CDMusicLength = 35*I_CDMusTrackLength(cdTrack);
oldTic = gametic;
}
else
{
i_CDMusicLength = -1;
}
*/
i_CDCurrentTrack = cdTrack;
i_CDTrack = false;
}
}
else
{
if (RegisteredSong)
{
I_StopSong(RegisteredSong);
I_UnRegisterSong(RegisteredSong);
if (!isExternalSong)
{
if (UseSndScript)
{
Z_Free(Mus_SndPtr);
}
else
{
Z_ChangeTag(lumpcache[Mus_LumpNum], PU_CACHE);
}
}
#ifdef __WATCOMC__
_dpmi_unlockregion(Mus_SndPtr, lumpinfo[Mus_LumpNum].size);
#endif
RegisteredSong = 0;
}
isExternalSong = I_RegisterExternalSong(songLump);
if (isExternalSong)
{
RegisteredSong = isExternalSong;
I_PlaySong(RegisteredSong, loop);
Mus_Song = -1;
return;
}
if (UseSndScript)
{
char name[MAX_OSPATH];
snprintf(name, sizeof(name), "%s%s.lmp", ArchivePath, songLump);
M_ReadFile(name, &Mus_SndPtr);
}
else
{
Mus_LumpNum = W_GetNumForName(songLump);
Mus_SndPtr = W_CacheLumpNum(Mus_LumpNum, PU_MUSIC);
}
#ifdef __WATCOMC__
_dpmi_lockregion(Mus_SndPtr, lumpinfo[Mus_LumpNum].size);
#endif
RegisteredSong = I_RegisterSong(Mus_SndPtr);
I_PlaySong(RegisteredSong, loop); // 'true' denotes endless looping.
Mus_Song = -1;
}
}
//==========================================================================
//
// S_GetSoundID
//
//==========================================================================
int S_GetSoundID(const char *name)
{
int i;
for (i = 0; i < NUMSFX; i++)
{
if (!strcmp(S_sfx[i].tagName, name))
{
return i;
}
}
return 0;
}
//==========================================================================
//
// S_StartSound
//
//==========================================================================
void S_StartSound(mobj_t *origin, int sound_id)
{
S_StartSoundAtVolume(origin, sound_id, 127);
}
//==========================================================================
//
// S_StartSoundAtVolume
//
//==========================================================================
void S_StartSoundAtVolume(mobj_t *origin, int sound_id, int volume)
{
static int sndcount = 0;
int i;
int dist, vol, chan;
int priority;
int angle, sep;
int absx, absy;
if (sound_id == 0 || snd_MaxVolume == 0)
return;
#if 0
if (origin == NULL)
{
origin = players[displayplayer].mo;
// this can be uninitialized when we are newly
// started before the demos start playing !...
}
#endif
if (volume == 0)
{
return;
}
// calculate the distance before other stuff so that we can throw out
// sounds that are beyond the hearing range.
if (origin)
{
absx = abs(origin->x - players[displayplayer].mo->x);
absy = abs(origin->y - players[displayplayer].mo->y);
}
else
{
absx = absy = 0;
}
dist = absx + absy - (absx > absy ? absy>>1 : absx>>1);
dist >>= FRACBITS;
if (dist >= MAX_SND_DIST)
{
return; // sound is beyond the hearing range...
}
if (dist < 0)
{
dist = 0;
}
priority = S_sfx[sound_id].priority;
priority *= (PRIORITY_MAX_ADJUST - (dist / DIST_ADJUST));
if (!S_StopSoundID(sound_id, priority))
{
return; // other sounds have greater priority
}
for (i = 0; i < snd_Channels; i++)
{
if (!origin || origin->player)
{
i = snd_Channels;
break; // let the player have more than one sound.
}
if (origin == Channel[i].mo)
{ // only allow other mobjs one sound
S_StopSound(Channel[i].mo);
break;
}
}
if (i >= snd_Channels)
{
for (i = 0; i < snd_Channels; i++)
{
if (Channel[i].mo == NULL)
{
break;
}
}
if (i >= snd_Channels)
{
// look for a lower priority sound to replace.
sndcount++;
if (sndcount >= snd_Channels)
{
sndcount = 0;
}
for (chan = 0; chan < snd_Channels; chan++)
{
i = (sndcount + chan) % snd_Channels;
if (priority >= Channel[i].priority)
{
chan = -1; // denote that sound should be replaced.
break;
}
}
if (chan != -1)
{
return; // no free channels.
}
else // replace the lower priority sound.
{
if (Channel[i].handle)
{
if (I_SoundIsPlaying(Channel[i].handle))
{
I_StopSound(Channel[i].handle);
}
if (S_sfx[Channel[i].sound_id].usefulness > 0)
{
S_sfx[Channel[i].sound_id].usefulness--;
}
}
}
}
}
if (S_sfx[sound_id].lumpnum == 0)
{
S_sfx[sound_id].lumpnum = I_GetSfxLumpNum(&S_sfx[sound_id]);
}
if (S_sfx[sound_id].snd_ptr == NULL)
{
if (UseSndScript)
{
char name[MAX_OSPATH];
int len;
snprintf(name, sizeof(name), "%s%s.lmp",
ArchivePath, S_sfx[sound_id].lumpname);
len = M_ReadFile(name, &S_sfx[sound_id].snd_ptr);
if (len <= 8)
{
I_Error("broken sound lump #%d (%s)\n",
S_sfx[sound_id].lumpnum, name);
}
}
else
{
if (W_LumpLength(S_sfx[sound_id].lumpnum) <= 8)
{
// I_Error("broken sound lump #%d (%s)\n",
fprintf(stderr, "broken sound lump #%d (%s)\n",
S_sfx[sound_id].lumpnum,
S_sfx[sound_id].lumpname);
return;
}
S_sfx[sound_id].snd_ptr =
W_CacheLumpNum(S_sfx[sound_id].lumpnum, PU_SOUND);
}
#ifdef __WATCOMC__
_dpmi_lockregion(S_sfx[sound_id].snd_ptr,
lumpinfo[S_sfx[sound_id].lumpnum].size);
#endif
}
vol = (SoundCurve[dist] * (snd_MaxVolume * 8) * volume)>>14;
if (!origin || origin == players[displayplayer].mo)
{
sep = 128;
// vol = (volume*(snd_MaxVolume+1)*8)>>7;
}
else
{
angle = R_PointToAngle2(players[displayplayer].mo->x,
players[displayplayer].mo->y,
origin->x, origin->y);
angle = (angle - viewangle)>>24;
sep = angle*2 - 128;
if (sep < 64)
sep = -sep;
if (sep > 192)
sep = 512-sep;
// vol = SoundCurve[dist];
}
if (S_sfx[sound_id].changePitch)
{
Channel[i].pitch = (byte)(127 + (M_Random() & 7) - (M_Random() & 7));
}
else
{
Channel[i].pitch = 127;
}
Channel[i].handle = I_StartSound(sound_id, S_sfx[sound_id].snd_ptr, vol,
sep, Channel[i].pitch, 0);
Channel[i].mo = origin;
Channel[i].sound_id = sound_id;
Channel[i].priority = priority;
Channel[i].volume = volume;
if (S_sfx[sound_id].usefulness < 0)
{
S_sfx[sound_id].usefulness = 1;
}
else
{
S_sfx[sound_id].usefulness++;
}
}
//==========================================================================
//
// S_StopSoundID
//
//==========================================================================
static boolean S_StopSoundID(int sound_id, int priority)
{
int i;
int lp; //least priority
int found;
if (S_sfx[sound_id].numchannels == -1)
{
return true;
}
lp = -1; //denote the argument sound_id
found = 0;
for (i = 0; i < snd_Channels; i++)
{
if (Channel[i].sound_id == sound_id && Channel[i].mo)
{
found++; //found one. Now, should we replace it??
if (priority >= Channel[i].priority)
{ // if we're gonna kill one, then this'll be it
lp = i;
priority = Channel[i].priority;
}
}
}
if (found < S_sfx[sound_id].numchannels)
{
return true;
}
else if (lp == -1)
{
return false; // don't replace any sounds
}
if (Channel[lp].handle)
{
if (I_SoundIsPlaying(Channel[lp].handle))
{
I_StopSound(Channel[lp].handle);
}
if (S_sfx[Channel[lp].sound_id].usefulness > 0)
{
S_sfx[Channel[lp].sound_id].usefulness--;
}
Channel[lp].mo = NULL;
}
return true;
}
//==========================================================================
//
// S_StopSound
//
//==========================================================================
void S_StopSound(mobj_t *origin)
{
int i;
for (i = 0; i < snd_Channels; i++)
{
if (Channel[i].mo == origin)
{
I_StopSound(Channel[i].handle);
if (S_sfx[Channel[i].sound_id].usefulness > 0)
{
S_sfx[Channel[i].sound_id].usefulness--;
}
Channel[i].handle = 0;
Channel[i].mo = NULL;
}
}
}
//==========================================================================
//
// S_StopAllSound
//
//==========================================================================
void S_StopAllSound(void)
{
int i;
//stop all sounds
for (i = 0; i < snd_Channels; i++)
{
if (Channel[i].handle)
{
S_StopSound(Channel[i].mo);
}
}
memset(Channel, 0, 8*sizeof(channel_t));
}
//==========================================================================
//
// S_SoundLink
//
//==========================================================================
void S_SoundLink(mobj_t *oldactor, mobj_t *newactor)
{
int i;
for (i = 0; i < snd_Channels; i++)
{
if (Channel[i].mo == oldactor)
Channel[i].mo = newactor;
}
}
//==========================================================================
//
// S_PauseSound
//
//==========================================================================
void S_PauseSound(void)
{
I_CDMusStop();
I_PauseSong(RegisteredSong);
}
//==========================================================================
//
// S_ResumeSound
//
//==========================================================================
void S_ResumeSound(void)
{
if (i_CDMusic && cdaudio)
{
I_CDMusResume();
}
else
{
I_ResumeSong(RegisteredSong);
}
}
//==========================================================================
//
// S_UpdateSounds
//
//==========================================================================
void S_UpdateSounds(mobj_t *listener)
{
int i, dist, vol;
int angle, sep;
int priority;
int absx, absy;
if (i_CDMusic)
{
I_CDMusUpdate();
}
if (snd_MaxVolume == 0)
{
return;
}
// Update any Sequences
SN_UpdateActiveSequences();
if (NextCleanup < gametic)
{
if (UseSndScript)
{
for (i = 0; i < NUMSFX; i++)
{
if (S_sfx[i].usefulness == 0 && S_sfx[i].snd_ptr)
{
S_sfx[i].usefulness = -1;
}
}
}
else
{
for (i = 0; i < NUMSFX; i++)
{
if (S_sfx[i].usefulness == 0 && S_sfx[i].snd_ptr)
{
if (lumpcache[S_sfx[i].lumpnum])
{
if (((memblock_t *) ((byte*)(lumpcache[S_sfx[i].lumpnum]) -
sizeof(memblock_t)))->id == ZONEID)
{ // taken directly from the Z_ChangeTag macro
Z_ChangeTag2(lumpcache[S_sfx[i].lumpnum], PU_CACHE);
#ifdef __WATCOMC__
_dpmi_unlockregion(S_sfx[i].snd_ptr,
lumpinfo[S_sfx[i].lumpnum].size);
#endif
}
}
S_sfx[i].usefulness = -1;
S_sfx[i].snd_ptr = NULL;
}
}
}
NextCleanup = gametic + 35*30; // every 30 seconds
}
for (i = 0; i < snd_Channels; i++)
{
if (!Channel[i].handle || S_sfx[Channel[i].sound_id].usefulness == -1)
{
continue;
}
if (!I_SoundIsPlaying(Channel[i].handle))
{
if (S_sfx[Channel[i].sound_id].usefulness > 0)
{
S_sfx[Channel[i].sound_id].usefulness--;
}
Channel[i].handle = 0;
Channel[i].mo = NULL;
Channel[i].sound_id = 0;
}
if (Channel[i].mo == NULL || Channel[i].sound_id == 0
|| Channel[i].mo == listener)
{
continue;
}
else
{
absx = abs(Channel[i].mo->x - listener->x);
absy = abs(Channel[i].mo->y - listener->y);
dist = absx+absy-(absx > absy ? absy>>1 : absx>>1);
dist >>= FRACBITS;
if (dist >= MAX_SND_DIST)
{
S_StopSound(Channel[i].mo);
continue;
}
if (dist < 0)
{
dist = 0;
}
//vol = SoundCurve[dist];
vol = (SoundCurve[dist] * (snd_MaxVolume * 8) * Channel[i].volume)>>14;
if (Channel[i].mo == listener)
{
sep = 128;
}
else
{
angle = R_PointToAngle2(listener->x, listener->y,
Channel[i].mo->x, Channel[i].mo->y);
angle = (angle-viewangle)>>24;
sep = angle*2-128;
if (sep < 64)
sep = -sep;
if (sep > 192)
sep = 512-sep;
}
I_UpdateSoundParams(Channel[i].handle, vol, sep, Channel[i].pitch);
priority = S_sfx[Channel[i].sound_id].priority;
priority *= PRIORITY_MAX_ADJUST - (dist / DIST_ADJUST);
Channel[i].priority = priority;
}
}
}
//==========================================================================
//
// S_GetChannelInfo
//
//==========================================================================
void S_GetChannelInfo(SoundInfo_t *s)
{
int i;
ChanInfo_t *c;
s->channelCount = snd_Channels;
s->musicVolume = snd_MusicVolume;
s->soundVolume = snd_MaxVolume;
for (i = 0; i < snd_Channels; i++)
{
c = &s->chan[i];
c->id = Channel[i].sound_id;
c->priority = Channel[i].priority;
c->name = S_sfx[c->id].lumpname;
c->mo = Channel[i].mo;
c->distance = P_AproxDistance(c->mo->x-viewx, c->mo->y-viewy)>>FRACBITS;
}
}
//==========================================================================
//
// S_GetSoundPlayingInfo
//
//==========================================================================
boolean S_GetSoundPlayingInfo(mobj_t *mobj, int sound_id)
{
int i;
for (i = 0; i < snd_Channels; i++)
{
if (Channel[i].sound_id == sound_id && Channel[i].mo == mobj)
{
if (I_SoundIsPlaying(Channel[i].handle))
{
return true;
}
}
}
return false;
}
//==========================================================================
//
// S_SetMusicVolume
//
//==========================================================================
void S_SetMusicVolume(void)
{
if (i_CDMusic)
I_CDMusSetVolume(snd_MusicVolume*16); // 0-255
I_SetMusicVolume(snd_MusicVolume);
if (snd_MusicVolume == 0)
{
I_PauseSong(RegisteredSong);
MusicPaused = true;
}
else if (MusicPaused)
{
if (!i_CDMusic || !cdaudio)
{
I_ResumeSong(RegisteredSong);
}
MusicPaused = false;
}
}