- 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:
Randy Heit 2008-03-22 03:33:41 +00:00
parent cab572c008
commit 84d125cf21
8 changed files with 328 additions and 139 deletions

View file

@ -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.

View file

@ -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;

View file

@ -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();
} }
//========================================================================== //==========================================================================

View file

@ -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;

View file

@ -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;
}
}

View file

@ -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);

View file

@ -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;

View file

@ -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