mirror of
https://github.com/ZDoom/qzdoom.git
synced 2024-11-27 22:42:57 +00:00
- Fixed: Actor-less sounds that aren't played on CHAN_AUTO should still be
subject to channel overriding. - Re-added priority selection based on sound usage. - Reduced the number of virtual channels to match the number of real channels. - Added customizable rolloff, including Doom's standard linear gain rolloff. SNDINFO commands are: $rolloff <sound> <min distance> <max distance> -- linear gain (like Doom) $rolloff <sound> linear <min distance> <max distance> -- linear volume $rolloff <sound> log <min distance> <rolloff factor> -- logarithmic $rolloff <sound> custom <min distance> <max distance> -- use SNDCURVE lump Anything closer than min distance is full volume and anything further than max distance is inaudible. Logarithmic rolloff does not have a maximum distance; it has a scalar that controls how quickly the volume drops off instead. SVN r834 (trunk)
This commit is contained in:
parent
cab572c008
commit
84d125cf21
8 changed files with 328 additions and 139 deletions
|
@ -1,3 +1,20 @@
|
||||||
|
March 21, 2008
|
||||||
|
- Fixed: Actor-less sounds that aren't played on CHAN_AUTO should still be
|
||||||
|
subject to channel overriding.
|
||||||
|
- Re-added priority selection based on sound usage.
|
||||||
|
- Reduced the number of virtual channels to match the number of real
|
||||||
|
channels.
|
||||||
|
- Added customizable rolloff, including Doom's standard linear gain rolloff.
|
||||||
|
SNDINFO commands are:
|
||||||
|
$rolloff <sound> <min distance> <max distance> -- linear gain (like Doom)
|
||||||
|
$rolloff <sound> linear <min distance> <max distance> -- linear volume
|
||||||
|
$rolloff <sound> log <min distance> <rolloff factor> -- logarithmic
|
||||||
|
$rolloff <sound> custom <min distance> <max distance> -- use SNDCURVE lump
|
||||||
|
Anything closer than min distance is full volume and anything further than
|
||||||
|
max distance is inaudible. Logarithmic rolloff does not have a maximum
|
||||||
|
distance; it has a scalar that controls how quickly the volume drops off
|
||||||
|
instead.
|
||||||
|
|
||||||
March 21, 2008 (Changes by Graf Zahl)
|
March 21, 2008 (Changes by Graf Zahl)
|
||||||
- Disabled scrolling of 3DMIDTEX textures. Due to the special needs this
|
- Disabled scrolling of 3DMIDTEX textures. Due to the special needs this
|
||||||
cannot work properly.
|
cannot work properly.
|
||||||
|
|
|
@ -3,7 +3,7 @@
|
||||||
** Routines for managing SNDINFO lumps and ambient sounds
|
** Routines for managing SNDINFO lumps and ambient sounds
|
||||||
**
|
**
|
||||||
**---------------------------------------------------------------------------
|
**---------------------------------------------------------------------------
|
||||||
** Copyright 1998-2007 Randy Heit
|
** Copyright 1998-2008 Randy Heit
|
||||||
** All rights reserved.
|
** All rights reserved.
|
||||||
**
|
**
|
||||||
** Redistribution and use in source and binary forms, with or without
|
** Redistribution and use in source and binary forms, with or without
|
||||||
|
@ -145,7 +145,8 @@ enum SICommands
|
||||||
SI_IfDoom,
|
SI_IfDoom,
|
||||||
SI_IfHeretic,
|
SI_IfHeretic,
|
||||||
SI_IfHexen,
|
SI_IfHexen,
|
||||||
SI_IfStrife
|
SI_IfStrife,
|
||||||
|
SI_Rolloff,
|
||||||
};
|
};
|
||||||
|
|
||||||
// Blood was a cool game. If Monolith ever releases the source for it,
|
// Blood was a cool game. If Monolith ever releases the source for it,
|
||||||
|
@ -240,6 +241,7 @@ static const char *SICommandStrings[] =
|
||||||
"$ifheretic",
|
"$ifheretic",
|
||||||
"$ifhexen",
|
"$ifhexen",
|
||||||
"$ifstrife",
|
"$ifstrife",
|
||||||
|
"$rolloff",
|
||||||
NULL
|
NULL
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -450,7 +452,10 @@ int S_AddSoundLump (const char *logicalname, int lump)
|
||||||
newsfx.bUsed = false;
|
newsfx.bUsed = false;
|
||||||
newsfx.bSingular = false;
|
newsfx.bSingular = false;
|
||||||
newsfx.bTentative = false;
|
newsfx.bTentative = false;
|
||||||
|
newsfx.RolloffType = ROLLOFF_Doom;
|
||||||
newsfx.link = sfxinfo_t::NO_LINK;
|
newsfx.link = sfxinfo_t::NO_LINK;
|
||||||
|
newsfx.MinDistance = 0;
|
||||||
|
newsfx.MaxDistance = 0;
|
||||||
|
|
||||||
return (int)S_sfx.Push (newsfx);
|
return (int)S_sfx.Push (newsfx);
|
||||||
}
|
}
|
||||||
|
@ -1136,6 +1141,62 @@ static void S_AddSNDINFO (int lump)
|
||||||
CurrentPitchMask = (1 << clamp (sc.Number, 0, 7)) - 1;
|
CurrentPitchMask = (1 << clamp (sc.Number, 0, 7)) - 1;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case SI_Rolloff: {
|
||||||
|
// $rolloff *|<logical name> [linear|log|custom] <min dist> <max dist/rolloff factor>
|
||||||
|
// Using * for the name makes it the default for sounds that don't specify otherwise.
|
||||||
|
float *min, *max;
|
||||||
|
int type;
|
||||||
|
int sfx;
|
||||||
|
|
||||||
|
sc.MustGetString();
|
||||||
|
if (sc.Compare("*"))
|
||||||
|
{
|
||||||
|
sfx = -1;
|
||||||
|
min = &S_MinDistance;
|
||||||
|
max = &S_MaxDistanceOrRolloffFactor;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
sfx = S_FindSoundTentative(sc.String);
|
||||||
|
min = &S_sfx[sfx].MinDistance;
|
||||||
|
max = &S_sfx[sfx].MaxDistance;
|
||||||
|
}
|
||||||
|
type = ROLLOFF_Doom;
|
||||||
|
if (!sc.CheckFloat())
|
||||||
|
{
|
||||||
|
sc.MustGetString();
|
||||||
|
if (sc.Compare("linear"))
|
||||||
|
{
|
||||||
|
type = ROLLOFF_Linear;
|
||||||
|
}
|
||||||
|
else if (sc.Compare("log"))
|
||||||
|
{
|
||||||
|
type = ROLLOFF_Log;
|
||||||
|
}
|
||||||
|
else if (sc.Compare("custom"))
|
||||||
|
{
|
||||||
|
type = ROLLOFF_Custom;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
sc.ScriptError("Unknown rolloff type '%s'", sc.String);
|
||||||
|
}
|
||||||
|
sc.MustGetFloat();
|
||||||
|
}
|
||||||
|
if (sfx < 0)
|
||||||
|
{
|
||||||
|
S_RolloffType = type;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
S_sfx[sfx].RolloffType = type;
|
||||||
|
}
|
||||||
|
*min = sc.Float;
|
||||||
|
sc.MustGetFloat();
|
||||||
|
*max = sc.Float;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
case SI_Random: {
|
case SI_Random: {
|
||||||
// $random <logical name> { <logical name> ... }
|
// $random <logical name> { <logical name> ... }
|
||||||
FRandomSoundList random;
|
FRandomSoundList random;
|
||||||
|
|
134
src/s_sound.cpp
134
src/s_sound.cpp
|
@ -74,17 +74,6 @@
|
||||||
#define S_PITCH_PERTURB 1
|
#define S_PITCH_PERTURB 1
|
||||||
#define S_STEREO_SWING 0.75
|
#define S_STEREO_SWING 0.75
|
||||||
|
|
||||||
/* Sound curve parameters for Doom */
|
|
||||||
|
|
||||||
// Maximum sound distance
|
|
||||||
const int S_CLIPPING_DIST = 1200;
|
|
||||||
|
|
||||||
// Sounds closer than this to the listener are maxed out.
|
|
||||||
// Originally: 200.
|
|
||||||
const int S_CLOSE_DIST = 160;
|
|
||||||
|
|
||||||
const float S_ATTENUATOR = S_CLIPPING_DIST - S_CLOSE_DIST;
|
|
||||||
|
|
||||||
// TYPES -------------------------------------------------------------------
|
// TYPES -------------------------------------------------------------------
|
||||||
|
|
||||||
struct MusPlayingInfo
|
struct MusPlayingInfo
|
||||||
|
@ -112,12 +101,10 @@ static void CalcPosVel (fixed_t *pt, AActor *mover, int constz, float pos[3],
|
||||||
|
|
||||||
// PRIVATE DATA DEFINITIONS ------------------------------------------------
|
// PRIVATE DATA DEFINITIONS ------------------------------------------------
|
||||||
|
|
||||||
int MAX_SND_DIST;
|
|
||||||
static bool SoundPaused; // whether sound effects are paused
|
static bool SoundPaused; // whether sound effects are paused
|
||||||
static bool MusicPaused; // whether music is paused
|
static bool MusicPaused; // whether music is paused
|
||||||
static MusPlayingInfo mus_playing; // music currently being played
|
static MusPlayingInfo mus_playing; // music currently being played
|
||||||
static FString LastSong; // last music that was played
|
static FString LastSong; // last music that was played
|
||||||
static float *SoundCurve;
|
|
||||||
static FPlayList *PlayList;
|
static FPlayList *PlayList;
|
||||||
|
|
||||||
// PUBLIC DATA DEFINITIONS -------------------------------------------------
|
// PUBLIC DATA DEFINITIONS -------------------------------------------------
|
||||||
|
@ -127,6 +114,12 @@ int sfx_empty;
|
||||||
FSoundChan *Channels;
|
FSoundChan *Channels;
|
||||||
FSoundChan *FreeChannels;
|
FSoundChan *FreeChannels;
|
||||||
|
|
||||||
|
int S_RolloffType;
|
||||||
|
float S_MinDistance;
|
||||||
|
float S_MaxDistanceOrRolloffFactor;
|
||||||
|
BYTE *S_SoundCurve;
|
||||||
|
int S_SoundCurveSize;
|
||||||
|
|
||||||
CVAR (Bool, snd_surround, true, CVAR_ARCHIVE|CVAR_GLOBALCONFIG) // [RH] Use surround sounds?
|
CVAR (Bool, snd_surround, true, CVAR_ARCHIVE|CVAR_GLOBALCONFIG) // [RH] Use surround sounds?
|
||||||
FBoolCVar noisedebug ("noise", false, 0); // [RH] Print sound debugging info?
|
FBoolCVar noisedebug ("noise", false, 0); // [RH] Print sound debugging info?
|
||||||
CVAR (Int, snd_channels, 32, CVAR_ARCHIVE|CVAR_GLOBALCONFIG) // number of channels available
|
CVAR (Int, snd_channels, 32, CVAR_ARCHIVE|CVAR_GLOBALCONFIG) // number of channels available
|
||||||
|
@ -251,43 +244,23 @@ void S_AddLocalSndInfo(int lump);
|
||||||
|
|
||||||
void S_Init ()
|
void S_Init ()
|
||||||
{
|
{
|
||||||
int i;
|
|
||||||
int curvelump;
|
int curvelump;
|
||||||
|
|
||||||
atterm (S_Shutdown);
|
atterm (S_Shutdown);
|
||||||
|
|
||||||
// remove old data (S_Init can be called multiple times!)
|
// remove old data (S_Init can be called multiple times!)
|
||||||
if (SoundCurve)
|
if (S_SoundCurve != NULL)
|
||||||
{
|
{
|
||||||
delete[] SoundCurve;
|
delete[] S_SoundCurve;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Heretic and Hexen have sound curve lookup tables. Doom does not.
|
// Heretic and Hexen have sound curve lookup tables. Doom does not.
|
||||||
curvelump = Wads.CheckNumForName ("SNDCURVE");
|
curvelump = Wads.CheckNumForName ("SNDCURVE");
|
||||||
if (curvelump >= 0)
|
if (curvelump >= 0)
|
||||||
{
|
{
|
||||||
MAX_SND_DIST = Wads.LumpLength (curvelump);
|
S_SoundCurveSize = Wads.LumpLength (curvelump);
|
||||||
SoundCurve = new float[MAX_SND_DIST];
|
S_SoundCurve = new BYTE[S_SoundCurveSize];
|
||||||
FMemLump lump = Wads.ReadLump(curvelump);
|
Wads.ReadLump(curvelump, S_SoundCurve);
|
||||||
BYTE *lumpmem = (BYTE *)lump.GetMem();
|
|
||||||
|
|
||||||
// The maximum value in a SNDCURVE lump is 127, so scale it to
|
|
||||||
// fit our sound system's volume levels. Also, FMOD's volumes
|
|
||||||
// are linear, whereas we want the "dumb" logarithmic volumes
|
|
||||||
// for our "2D" sounds.
|
|
||||||
for (i = 0; i < S_CLIPPING_DIST; ++i)
|
|
||||||
{
|
|
||||||
SoundCurve[i] = (powf(10.f, (lumpmem[i] / 127.f)) - 1.f) / 9.f;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
MAX_SND_DIST = S_CLIPPING_DIST;
|
|
||||||
SoundCurve = new float[S_CLIPPING_DIST];
|
|
||||||
for (i = 0; i < S_CLIPPING_DIST; ++i)
|
|
||||||
{
|
|
||||||
SoundCurve[i] = (powf(10.f, MIN(1.f, (S_CLIPPING_DIST - i) / S_ATTENUATOR)) - 1.f) / 9.f;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Free all channels for use.
|
// Free all channels for use.
|
||||||
|
@ -348,10 +321,10 @@ void S_Shutdown ()
|
||||||
}
|
}
|
||||||
FreeChannels = NULL;
|
FreeChannels = NULL;
|
||||||
|
|
||||||
if (SoundCurve != NULL)
|
if (S_SoundCurve != NULL)
|
||||||
{
|
{
|
||||||
delete[] SoundCurve;
|
delete[] S_SoundCurve;
|
||||||
SoundCurve = NULL;
|
S_SoundCurve = NULL;
|
||||||
}
|
}
|
||||||
if (PlayList != NULL)
|
if (PlayList != NULL)
|
||||||
{
|
{
|
||||||
|
@ -734,72 +707,68 @@ static void S_StartSound (fixed_t *pt, AActor *mover, int channel,
|
||||||
{
|
{
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Select priority.
|
// Select priority.
|
||||||
if (attenuation <= 0)
|
if (attenuation <= 0 || mover == players[consoleplayer].camera)
|
||||||
{
|
{
|
||||||
basepriority = 200;
|
basepriority = 40;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
switch (channel)
|
switch (channel)
|
||||||
{
|
{
|
||||||
case CHAN_WEAPON:
|
case CHAN_WEAPON:
|
||||||
basepriority = 100;
|
basepriority = 20;
|
||||||
break;
|
break;
|
||||||
case CHAN_VOICE:
|
case CHAN_VOICE:
|
||||||
basepriority = 75;
|
basepriority = 10;
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
case CHAN_BODY:
|
case CHAN_BODY:
|
||||||
basepriority = 50;
|
basepriority = 0;
|
||||||
break;
|
break;
|
||||||
case CHAN_ITEM:
|
case CHAN_ITEM:
|
||||||
basepriority = 25;
|
basepriority = -10;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
if (attenuation == 1)
|
basepriority = int(basepriority * attenuation);
|
||||||
basepriority += 50;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (mover != NULL)
|
if (mover != NULL && channel == CHAN_AUTO)
|
||||||
{
|
{ // Select a channel that isn't already playing something.
|
||||||
if (channel == CHAN_AUTO)
|
BYTE mask = mover->SoundChans;
|
||||||
{ // Select a channel that isn't already playing something.
|
|
||||||
BYTE mask = mover->SoundChans;
|
|
||||||
|
|
||||||
// Try channel 0 first, then travel from channel 7 down.
|
// Try channel 0 first, then travel from channel 7 down.
|
||||||
if ((mask & 1) == 0)
|
if ((mask & 1) == 0)
|
||||||
{
|
|
||||||
channel = 0;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
for (channel = 7; channel > 0; --channel, mask <<= 1)
|
|
||||||
{
|
|
||||||
if ((mask & 0x80) == 0)
|
|
||||||
{
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (channel == 0)
|
|
||||||
{ // Crap. No free channels.
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
// If this actor is already playing something on the selected channel, stop it.
|
|
||||||
if (mover->SoundChans & (1 << channel))
|
|
||||||
{
|
{
|
||||||
for (chan = Channels; chan != NULL; chan = chan->NextChan)
|
channel = 0;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
for (channel = 7; channel > 0; --channel, mask <<= 1)
|
||||||
{
|
{
|
||||||
if (chan->Mover == mover && chan->EntChannel == channel)
|
if ((mask & 0x80) == 0)
|
||||||
{
|
{
|
||||||
GSnd->StopSound(chan);
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if (channel == 0)
|
||||||
|
{ // Crap. No free channels.
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// If this actor is already playing something on the selected channel, stop it.
|
||||||
|
if ((mover == NULL && channel != CHAN_AUTO) || (mover != NULL && mover->SoundChans & (1 << channel)))
|
||||||
|
{
|
||||||
|
for (chan = Channels; chan != NULL; chan = chan->NextChan)
|
||||||
|
{
|
||||||
|
if (chan->Mover == mover && chan->EntChannel == channel)
|
||||||
|
{
|
||||||
|
GSnd->StopSound(chan);
|
||||||
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -830,7 +799,7 @@ static void S_StartSound (fixed_t *pt, AActor *mover, int channel,
|
||||||
pt2[2] = z;
|
pt2[2] = z;
|
||||||
CalcPosVel (pt2, mover, chanflags & CHAN_LISTENERZ, pos, vel);
|
CalcPosVel (pt2, mover, chanflags & CHAN_LISTENERZ, pos, vel);
|
||||||
}
|
}
|
||||||
chan = GSnd->StartSound3D (sfx, volume, pitch, looping, pos, vel, !(chanflags & CHAN_NOPAUSE));
|
chan = GSnd->StartSound3D (sfx, volume, attenuation, pitch, basepriority, looping, pos, vel, !(chanflags & CHAN_NOPAUSE));
|
||||||
if (chan != NULL)
|
if (chan != NULL)
|
||||||
{
|
{
|
||||||
chan->ConstZ = !!(chanflags & CHAN_LISTENERZ);
|
chan->ConstZ = !!(chanflags & CHAN_LISTENERZ);
|
||||||
|
@ -1047,6 +1016,7 @@ void S_StopAllChannels ()
|
||||||
{
|
{
|
||||||
GSnd->StopSound(Channels);
|
GSnd->StopSound(Channels);
|
||||||
}
|
}
|
||||||
|
GSnd->UpdateSounds();
|
||||||
}
|
}
|
||||||
|
|
||||||
//==========================================================================
|
//==========================================================================
|
||||||
|
|
|
@ -54,14 +54,34 @@ struct sfxinfo_t
|
||||||
WORD bUsed:1;
|
WORD bUsed:1;
|
||||||
WORD bSingular:1;
|
WORD bSingular:1;
|
||||||
WORD bTentative:1;
|
WORD bTentative:1;
|
||||||
|
WORD RolloffType:2;
|
||||||
|
|
||||||
WORD link;
|
WORD link;
|
||||||
enum { NO_LINK = 0xffff };
|
enum { NO_LINK = 0xffff };
|
||||||
|
|
||||||
|
float MinDistance;
|
||||||
|
union { float MaxDistance, RolloffFactor; };
|
||||||
|
};
|
||||||
|
|
||||||
|
// Rolloff types
|
||||||
|
enum
|
||||||
|
{
|
||||||
|
ROLLOFF_Doom, // Linear rolloff with a logarithmic volume scale
|
||||||
|
ROLLOFF_Linear, // Linear rolloff with a linear volume scale
|
||||||
|
ROLLOFF_Log, // Logarithmic rolloff (standard hardware type)
|
||||||
|
ROLLOFF_Custom // Lookup volume from SNDCURVE
|
||||||
};
|
};
|
||||||
|
|
||||||
// the complete set of sound effects
|
// the complete set of sound effects
|
||||||
extern TArray<sfxinfo_t> S_sfx;
|
extern TArray<sfxinfo_t> S_sfx;
|
||||||
|
|
||||||
|
// Default rolloff information.
|
||||||
|
extern int S_RolloffType;
|
||||||
|
extern float S_MinDistance;
|
||||||
|
extern float S_MaxDistanceOrRolloffFactor;
|
||||||
|
extern BYTE *S_SoundCurve;
|
||||||
|
extern int S_SoundCurveSize;
|
||||||
|
|
||||||
// Information about one playing sound.
|
// Information about one playing sound.
|
||||||
struct FSoundChan
|
struct FSoundChan
|
||||||
{
|
{
|
||||||
|
@ -75,6 +95,7 @@ struct FSoundChan
|
||||||
int SoundID; // Sound ID of playing sound
|
int SoundID; // Sound ID of playing sound
|
||||||
int OrgID; // Sound ID of sound used to start this channel
|
int OrgID; // Sound ID of sound used to start this channel
|
||||||
float Volume;
|
float Volume;
|
||||||
|
float DistanceScale;
|
||||||
BYTE EntChannel; // Actor's sound channel.
|
BYTE EntChannel; // Actor's sound channel.
|
||||||
bool Loop;
|
bool Loop;
|
||||||
bool Is3D;
|
bool Is3D;
|
||||||
|
|
|
@ -94,8 +94,6 @@ static const char *Enum_NameForNum(const FEnumList *list, int num);
|
||||||
|
|
||||||
// EXTERNAL DATA DECLARATIONS ----------------------------------------------
|
// EXTERNAL DATA DECLARATIONS ----------------------------------------------
|
||||||
|
|
||||||
extern int MAX_SND_DIST;
|
|
||||||
|
|
||||||
EXTERN_CVAR (String, snd_output)
|
EXTERN_CVAR (String, snd_output)
|
||||||
EXTERN_CVAR (Float, snd_musicvolume)
|
EXTERN_CVAR (Float, snd_musicvolume)
|
||||||
EXTERN_CVAR (Int, snd_buffersize)
|
EXTERN_CVAR (Int, snd_buffersize)
|
||||||
|
@ -116,10 +114,14 @@ CVAR (Bool, snd_dspnet, false, 0)
|
||||||
|
|
||||||
// PRIVATE DATA DEFINITIONS ------------------------------------------------
|
// PRIVATE DATA DEFINITIONS ------------------------------------------------
|
||||||
|
|
||||||
static const int S_CLIPPING_DIST = 1200;
|
|
||||||
static const int S_CLOSE_DIST = 160;
|
|
||||||
static const ReverbContainer *PrevEnvironment;
|
static const ReverbContainer *PrevEnvironment;
|
||||||
|
|
||||||
|
// The rolloff callback is called during FMOD::Sound::play, so we need this
|
||||||
|
// global variable to contain the sound info during that time for the
|
||||||
|
// callback.
|
||||||
|
static sfxinfo_t *GSfxInfo;
|
||||||
|
static float GDistScale;
|
||||||
|
|
||||||
// In the below lists, duplicate entries are for user selection. When
|
// In the below lists, duplicate entries are for user selection. When
|
||||||
// queried, only the first one for the particular value is shown.
|
// queried, only the first one for the particular value is shown.
|
||||||
static const FEnumList OutputNames[] =
|
static const FEnumList OutputNames[] =
|
||||||
|
@ -551,13 +553,13 @@ bool FMODSoundRenderer::Init()
|
||||||
{
|
{
|
||||||
initflags |= FMOD_INIT_ENABLE_DSPNET;
|
initflags |= FMOD_INIT_ENABLE_DSPNET;
|
||||||
}
|
}
|
||||||
result = Sys->init(MAX_CHANNELS, initflags, 0);
|
result = Sys->init(snd_channels + NUM_EXTRA_SOFTWARE_CHANNELS, initflags, 0);
|
||||||
if (result == FMOD_ERR_OUTPUT_CREATEBUFFER)
|
if (result == FMOD_ERR_OUTPUT_CREATEBUFFER)
|
||||||
{ // The speaker mode selected isn't supported by this soundcard. Switch it back to stereo.
|
{ // The speaker mode selected isn't supported by this soundcard. Switch it back to stereo.
|
||||||
result = Sys->setSpeakerMode(FMOD_SPEAKERMODE_STEREO);
|
result = Sys->setSpeakerMode(FMOD_SPEAKERMODE_STEREO);
|
||||||
ERRCHECK(result);
|
ERRCHECK(result);
|
||||||
|
|
||||||
result = Sys->init(MAX_CHANNELS, initflags, 0);
|
result = Sys->init(snd_channels + NUM_EXTRA_SOFTWARE_CHANNELS, initflags, 0);
|
||||||
ERRCHECK(result);
|
ERRCHECK(result);
|
||||||
}
|
}
|
||||||
if (result != FMOD_OK)
|
if (result != FMOD_OK)
|
||||||
|
@ -580,21 +582,8 @@ bool FMODSoundRenderer::Init()
|
||||||
|
|
||||||
result = SPC_CreateCodec(Sys);
|
result = SPC_CreateCodec(Sys);
|
||||||
|
|
||||||
float rolloff_factor;
|
Sys->set3DSettings(0.5f, 96.f, 1.f);
|
||||||
|
Sys->set3DRolloffCallback(RolloffCallback);
|
||||||
if (gameinfo.gametype == GAME_Doom || gameinfo.gametype == GAME_Strife)
|
|
||||||
{
|
|
||||||
rolloff_factor = 1.7f;
|
|
||||||
}
|
|
||||||
else if (gameinfo.gametype == GAME_Heretic)
|
|
||||||
{
|
|
||||||
rolloff_factor = 1.24f;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
rolloff_factor = 0.96f;
|
|
||||||
}
|
|
||||||
Sys->set3DSettings(1.f, 100.f, rolloff_factor);
|
|
||||||
snd_sfxvolume.Callback ();
|
snd_sfxvolume.Callback ();
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
@ -933,6 +922,7 @@ FSoundChan *FMODSoundRenderer::StartSound(sfxinfo_t *sfx, float vol, int pitch,
|
||||||
|
|
||||||
freq = PITCH(sfx->frequency, pitch);
|
freq = PITCH(sfx->frequency, pitch);
|
||||||
|
|
||||||
|
GSfxInfo = sfx;
|
||||||
result = Sys->playSound(FMOD_CHANNEL_FREE, (FMOD::Sound *)sfx->data, true, &chan);
|
result = Sys->playSound(FMOD_CHANNEL_FREE, (FMOD::Sound *)sfx->data, true, &chan);
|
||||||
if (FMOD_OK == result)
|
if (FMOD_OK == result)
|
||||||
{
|
{
|
||||||
|
@ -967,18 +957,40 @@ FSoundChan *FMODSoundRenderer::StartSound(sfxinfo_t *sfx, float vol, int pitch,
|
||||||
//
|
//
|
||||||
//==========================================================================
|
//==========================================================================
|
||||||
|
|
||||||
FSoundChan *FMODSoundRenderer::StartSound3D(sfxinfo_t *sfx, float vol, int pitch,
|
FSoundChan *FMODSoundRenderer::StartSound3D(sfxinfo_t *sfx, float vol, float distscale,
|
||||||
bool looping, float pos[3], float vel[3], bool pausable)
|
int pitch, int priority, bool looping, float pos[3], float vel[3], bool pausable)
|
||||||
{
|
{
|
||||||
int id = int(sfx - &S_sfx[0]);
|
int id = int(sfx - &S_sfx[0]);
|
||||||
FMOD_RESULT result;
|
FMOD_RESULT result;
|
||||||
FMOD_MODE mode;
|
FMOD_MODE mode;
|
||||||
FMOD::Channel *chan;
|
FMOD::Channel *chan;
|
||||||
float freq;
|
float freq;
|
||||||
|
float def_freq, def_vol, def_pan;
|
||||||
|
int def_priority;
|
||||||
|
|
||||||
freq = PITCH(sfx->frequency, pitch);
|
freq = PITCH(sfx->frequency, pitch);
|
||||||
|
|
||||||
|
// Change the sound's default priority before playing it.
|
||||||
|
if (FMOD_OK == ((FMOD::Sound *)sfx->data)->getDefaults(&def_freq, &def_vol, &def_pan, &def_priority))
|
||||||
|
{
|
||||||
|
((FMOD::Sound *)sfx->data)->setDefaults(def_freq, def_vol, def_pan, clamp(def_priority - priority, 1, 256));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
def_priority = -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Play it.
|
||||||
|
GSfxInfo = sfx;
|
||||||
|
GDistScale = distscale;
|
||||||
result = Sys->playSound(FMOD_CHANNEL_FREE, (FMOD::Sound *)sfx->data, true, &chan);
|
result = Sys->playSound(FMOD_CHANNEL_FREE, (FMOD::Sound *)sfx->data, true, &chan);
|
||||||
|
|
||||||
|
// Then set the priority back.
|
||||||
|
if (def_priority >= 0)
|
||||||
|
{
|
||||||
|
((FMOD::Sound *)sfx->data)->setDefaults(def_freq, def_vol, def_pan, def_priority);
|
||||||
|
}
|
||||||
|
|
||||||
if (FMOD_OK == result)
|
if (FMOD_OK == result)
|
||||||
{
|
{
|
||||||
result = chan->getMode(&mode);
|
result = chan->getMode(&mode);
|
||||||
|
@ -1013,7 +1025,9 @@ FSoundChan *FMODSoundRenderer::StartSound3D(sfxinfo_t *sfx, float vol, int pitch
|
||||||
chan->setVolume(vol);
|
chan->setVolume(vol);
|
||||||
chan->set3DAttributes((FMOD_VECTOR *)pos, (FMOD_VECTOR *)vel);
|
chan->set3DAttributes((FMOD_VECTOR *)pos, (FMOD_VECTOR *)vel);
|
||||||
chan->setPaused(false);
|
chan->setPaused(false);
|
||||||
return CommonChannelSetup(chan, true);
|
FSoundChan *schan = CommonChannelSetup(chan, true);
|
||||||
|
schan->DistanceScale = distscale;
|
||||||
|
return schan;
|
||||||
}
|
}
|
||||||
|
|
||||||
DPrintf ("Sound %s failed to play: %d\n", sfx->name.GetChars(), result);
|
DPrintf ("Sound %s failed to play: %d\n", sfx->name.GetChars(), result);
|
||||||
|
@ -1035,6 +1049,7 @@ FSoundChan *FMODSoundRenderer::CommonChannelSetup(FMOD::Channel *chan, bool is3d
|
||||||
chan->setUserData(schan);
|
chan->setUserData(schan);
|
||||||
chan->setCallback(FMOD_CHANNEL_CALLBACKTYPE_END, ChannelEndCallback, 0);
|
chan->setCallback(FMOD_CHANNEL_CALLBACKTYPE_END, ChannelEndCallback, 0);
|
||||||
schan->Is3D = is3d;
|
schan->Is3D = is3d;
|
||||||
|
GSfxInfo = NULL;
|
||||||
return schan;
|
return schan;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1051,33 +1066,8 @@ void FMODSoundRenderer::StopSound(FSoundChan *chan)
|
||||||
|
|
||||||
if (chan->SysChannel != NULL)
|
if (chan->SysChannel != NULL)
|
||||||
{
|
{
|
||||||
((FMOD::Channel *)chan->SysChannel)->setCallback(FMOD_CHANNEL_CALLBACKTYPE_END, 0, 0);
|
|
||||||
((FMOD::Channel *)chan->SysChannel)->stop();
|
((FMOD::Channel *)chan->SysChannel)->stop();
|
||||||
}
|
}
|
||||||
S_ReturnChannel(chan);
|
|
||||||
}
|
|
||||||
|
|
||||||
//==========================================================================
|
|
||||||
//
|
|
||||||
// FMODSoundRenderer :: ChannelEndCallback static
|
|
||||||
//
|
|
||||||
// Called when the channel finishes playing.
|
|
||||||
//
|
|
||||||
//==========================================================================
|
|
||||||
|
|
||||||
FMOD_RESULT F_CALLBACK FMODSoundRenderer::ChannelEndCallback
|
|
||||||
(FMOD_CHANNEL *channel, FMOD_CHANNEL_CALLBACKTYPE type,
|
|
||||||
int cmd, unsigned int data1, unsigned int data2)
|
|
||||||
{
|
|
||||||
assert(type == FMOD_CHANNEL_CALLBACKTYPE_END);
|
|
||||||
FMOD::Channel *chan = (FMOD::Channel *)channel;
|
|
||||||
FSoundChan *schan;
|
|
||||||
|
|
||||||
if (chan->getUserData((void **)&schan) == FMOD_OK && schan != NULL)
|
|
||||||
{
|
|
||||||
S_ReturnChannel(schan);
|
|
||||||
}
|
|
||||||
return FMOD_OK;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
//==========================================================================
|
//==========================================================================
|
||||||
|
@ -1305,8 +1295,24 @@ void FMODSoundRenderer::DoLoad(void **slot, sfxinfo_t *sfx)
|
||||||
FMOD_MODE samplemode;
|
FMOD_MODE samplemode;
|
||||||
FMOD_CREATESOUNDEXINFO exinfo = { sizeof(exinfo), };
|
FMOD_CREATESOUNDEXINFO exinfo = { sizeof(exinfo), };
|
||||||
FMOD::Sound *sample;
|
FMOD::Sound *sample;
|
||||||
|
int rolloff;
|
||||||
|
float mindist, maxdist;
|
||||||
|
|
||||||
samplemode = FMOD_3D | FMOD_OPENMEMORY | FMOD_SOFTWARE;
|
samplemode = FMOD_3D | FMOD_OPENMEMORY | FMOD_SOFTWARE;
|
||||||
|
|
||||||
|
if (sfx->MaxDistance == 0)
|
||||||
|
{
|
||||||
|
mindist = S_MinDistance;
|
||||||
|
maxdist = S_MaxDistanceOrRolloffFactor;
|
||||||
|
rolloff = S_RolloffType;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
mindist = sfx->MinDistance;
|
||||||
|
maxdist = sfx->MaxDistance;
|
||||||
|
rolloff = sfx->RolloffType;
|
||||||
|
}
|
||||||
|
|
||||||
sfxdata = NULL;
|
sfxdata = NULL;
|
||||||
|
|
||||||
errcount = 0;
|
errcount = 0;
|
||||||
|
@ -1401,11 +1407,14 @@ void FMODSoundRenderer::DoLoad(void **slot, sfxinfo_t *sfx)
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (sfx->data)
|
if (sample != NULL)
|
||||||
{
|
{
|
||||||
// Match s_sound.cpp min distance.
|
if (rolloff == ROLLOFF_Log)
|
||||||
// Max distance is irrelevant.
|
{
|
||||||
sample->set3DMinMaxDistance(float(S_CLOSE_DIST), 10000.f);
|
maxdist = 10000.f;
|
||||||
|
}
|
||||||
|
sample->set3DMinMaxDistance(mindist, maxdist);
|
||||||
|
sample->setUserData(sfx);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (sfxdata != NULL)
|
if (sfxdata != NULL)
|
||||||
|
@ -1445,3 +1454,105 @@ void FMODSoundRenderer::getsfx(sfxinfo_t *sfx)
|
||||||
}
|
}
|
||||||
DoLoad(&sfx->data, sfx);
|
DoLoad(&sfx->data, sfx);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//==========================================================================
|
||||||
|
//
|
||||||
|
// FMODSoundRenderer :: ChannelEndCallback static
|
||||||
|
//
|
||||||
|
// Called when the channel finishes playing.
|
||||||
|
//
|
||||||
|
//==========================================================================
|
||||||
|
|
||||||
|
FMOD_RESULT F_CALLBACK FMODSoundRenderer::ChannelEndCallback
|
||||||
|
(FMOD_CHANNEL *channel, FMOD_CHANNEL_CALLBACKTYPE type,
|
||||||
|
int cmd, unsigned int data1, unsigned int data2)
|
||||||
|
{
|
||||||
|
assert(type == FMOD_CHANNEL_CALLBACKTYPE_END);
|
||||||
|
FMOD::Channel *chan = (FMOD::Channel *)channel;
|
||||||
|
FSoundChan *schan;
|
||||||
|
|
||||||
|
if (chan->getUserData((void **)&schan) == FMOD_OK && schan != NULL)
|
||||||
|
{
|
||||||
|
S_ReturnChannel(schan);
|
||||||
|
}
|
||||||
|
return FMOD_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//==========================================================================
|
||||||
|
//
|
||||||
|
// FMODSoundRenderer :: RolloffCallback static
|
||||||
|
//
|
||||||
|
// Calculates a volume for the sound based on distance.
|
||||||
|
//
|
||||||
|
//==========================================================================
|
||||||
|
|
||||||
|
float F_CALLBACK FMODSoundRenderer::RolloffCallback(FMOD_CHANNEL *channel, float distance)
|
||||||
|
{
|
||||||
|
FMOD::Channel *chan = (FMOD::Channel *)channel;
|
||||||
|
FSoundChan *schan;
|
||||||
|
// Defaults for Doom.
|
||||||
|
int type = ROLLOFF_Doom;
|
||||||
|
sfxinfo_t *sfx;
|
||||||
|
float min;
|
||||||
|
float max;
|
||||||
|
float factor;
|
||||||
|
float volume;
|
||||||
|
|
||||||
|
type = S_RolloffType;
|
||||||
|
factor = S_MaxDistanceOrRolloffFactor;
|
||||||
|
min = S_MinDistance;
|
||||||
|
max = S_MaxDistanceOrRolloffFactor;
|
||||||
|
|
||||||
|
if (GSfxInfo != NULL)
|
||||||
|
{
|
||||||
|
sfx = GSfxInfo;
|
||||||
|
distance *= GDistScale;
|
||||||
|
}
|
||||||
|
else if (chan->getUserData((void **)&schan) == FMOD_OK && schan != NULL)
|
||||||
|
{
|
||||||
|
sfx = schan->SfxInfo;
|
||||||
|
distance *= schan->DistanceScale;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
if (sfx == NULL)
|
||||||
|
{
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (sfx->MaxDistance == 0)
|
||||||
|
{
|
||||||
|
type = sfx->RolloffType;
|
||||||
|
factor = sfx->RolloffFactor;
|
||||||
|
}
|
||||||
|
chan->get3DMinMaxDistance(&min, &max);
|
||||||
|
|
||||||
|
if (distance <= min)
|
||||||
|
{
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
if (type == ROLLOFF_Log)
|
||||||
|
{ // Logarithmic rolloff has no max distance where it goes silent.
|
||||||
|
return min / (min + factor * (distance - min));
|
||||||
|
}
|
||||||
|
if (distance >= max)
|
||||||
|
{
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
volume = (max - distance) / (max - min);
|
||||||
|
if (type == ROLLOFF_Custom && S_SoundCurve != NULL)
|
||||||
|
{
|
||||||
|
volume = S_SoundCurve[int(S_SoundCurveSize * (1 - volume))] / 127.f;
|
||||||
|
}
|
||||||
|
if (type == ROLLOFF_Linear)
|
||||||
|
{
|
||||||
|
return volume;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return (powf(10.f, volume) - 1.f) / 9.f;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -25,7 +25,7 @@ public:
|
||||||
|
|
||||||
// Starts a sound.
|
// Starts a sound.
|
||||||
FSoundChan *StartSound (sfxinfo_t *sfx, float vol, int pitch, bool looping, bool pauseable);
|
FSoundChan *StartSound (sfxinfo_t *sfx, float vol, int pitch, bool looping, bool pauseable);
|
||||||
FSoundChan *StartSound3D (sfxinfo_t *sfx, float vol, int pitch, bool looping, float pos[3], float vel[3], bool pauseable);
|
FSoundChan *StartSound3D (sfxinfo_t *sfx, float vol, float distscale, int pitch, int priority, bool looping, float pos[3], float vel[3], bool pauseable);
|
||||||
|
|
||||||
// Stops a sound channel.
|
// Stops a sound channel.
|
||||||
void StopSound (FSoundChan *chan);
|
void StopSound (FSoundChan *chan);
|
||||||
|
@ -56,6 +56,7 @@ private:
|
||||||
|
|
||||||
static FMOD_RESULT F_CALLBACK ChannelEndCallback
|
static FMOD_RESULT F_CALLBACK ChannelEndCallback
|
||||||
(FMOD_CHANNEL *channel, FMOD_CHANNEL_CALLBACKTYPE type, int cmd, unsigned int data1, unsigned int data2);
|
(FMOD_CHANNEL *channel, FMOD_CHANNEL_CALLBACKTYPE type, int cmd, unsigned int data1, unsigned int data2);
|
||||||
|
static float F_CALLBACK RolloffCallback(FMOD_CHANNEL *channel, float distance);
|
||||||
|
|
||||||
FSoundChan *CommonChannelSetup(FMOD::Channel *chan, bool is3d);
|
FSoundChan *CommonChannelSetup(FMOD::Channel *chan, bool is3d);
|
||||||
void DoLoad (void **slot, sfxinfo_t *sfx);
|
void DoLoad (void **slot, sfxinfo_t *sfx);
|
||||||
|
|
|
@ -79,7 +79,7 @@ public:
|
||||||
|
|
||||||
// Starts a sound.
|
// Starts a sound.
|
||||||
virtual FSoundChan *StartSound (sfxinfo_t *sfx, float vol, int pitch, bool looping, bool pauseable) = 0;
|
virtual FSoundChan *StartSound (sfxinfo_t *sfx, float vol, int pitch, bool looping, bool pauseable) = 0;
|
||||||
virtual FSoundChan *StartSound3D (sfxinfo_t *sfx, float vol, int pitch, bool looping, float pos[3], float vel[3], bool pauseable) = 0;
|
virtual FSoundChan *StartSound3D (sfxinfo_t *sfx, float vol, float distscale, int pitch, int priority, bool looping, float pos[3], float vel[3], bool pauseable) = 0;
|
||||||
|
|
||||||
// Stops a sound channel.
|
// Stops a sound channel.
|
||||||
virtual void StopSound (FSoundChan *chan) = 0;
|
virtual void StopSound (FSoundChan *chan) = 0;
|
||||||
|
|
|
@ -46,6 +46,9 @@ world/quake dsquake
|
||||||
misc/freeze icedth1
|
misc/freeze icedth1
|
||||||
misc/icebreak icebrk1a
|
misc/icebreak icebrk1a
|
||||||
|
|
||||||
|
// The released source code used a min distance of 160. Why?
|
||||||
|
// Retail Doom and Strife use 200.
|
||||||
|
$rolloff * 200 1200
|
||||||
|
|
||||||
/***************************************************************************/
|
/***************************************************************************/
|
||||||
/* */
|
/* */
|
||||||
|
@ -55,6 +58,7 @@ misc/icebreak icebrk1a
|
||||||
|
|
||||||
$ifdoom
|
$ifdoom
|
||||||
|
|
||||||
|
|
||||||
// BOOM has pitch shifting equivalent to a range of 4. I never got to hear
|
// BOOM has pitch shifting equivalent to a range of 4. I never got to hear
|
||||||
// Doom when it used pitch shifting, so I don't know if this is correct or not.
|
// Doom when it used pitch shifting, so I don't know if this is correct or not.
|
||||||
$pitchshiftrange 4
|
$pitchshiftrange 4
|
||||||
|
@ -483,6 +487,8 @@ $endif // ifdoom
|
||||||
|
|
||||||
$ifheretic
|
$ifheretic
|
||||||
|
|
||||||
|
$rolloff * custom 0 1600
|
||||||
|
|
||||||
$pitchshiftrange 2
|
$pitchshiftrange 2
|
||||||
|
|
||||||
$playersound player male *wimpydeath plrwdth
|
$playersound player male *wimpydeath plrwdth
|
||||||
|
@ -731,6 +737,8 @@ $endif // ifheretic
|
||||||
|
|
||||||
$ifhexen
|
$ifhexen
|
||||||
|
|
||||||
|
$rolloff * custom 0 2025
|
||||||
|
|
||||||
$pitchshiftrange 3
|
$pitchshiftrange 3
|
||||||
|
|
||||||
$random PlayerFighterExtremeDeathPicker { PlayerFighterExtreme1Death
|
$random PlayerFighterExtremeDeathPicker { PlayerFighterExtreme1Death
|
||||||
|
|
Loading…
Reference in a new issue