2019-12-12 18:21:36 +00:00
# pragma once
# include "backend/i_sound.h"
struct FRandomSoundList
{
TArray < uint32_t > Choices ;
uint32_t Owner = 0 ;
} ;
extern int sfx_empty ;
//
// SoundFX struct.
//
struct sfxinfo_t
{
// Next field is for use by the system sound interface.
// A non-null data means the sound has been loaded.
SoundHandle data ;
// Also for the sound interface. Used for 3D positional
// sounds, may be the same as data.
SoundHandle data3d ;
FString name ; // [RH] Sound name defined in SNDINFO
int lumpnum ; // lump number of sfx
unsigned int next , index ; // [RH] For hashing
float Volume ;
int ResourceId ; // Resource ID as implemented by Blood. Not used by Doom but added for completeness.
uint8_t PitchMask ;
int16_t NearLimit ; // 0 means unlimited
float LimitRange ; // Range for sound limiting (squared for faster computations)
unsigned bRandomHeader : 1 ;
unsigned bLoadRAW : 1 ;
unsigned b16bit : 1 ;
unsigned bUsed : 1 ;
unsigned bSingular : 1 ;
unsigned bTentative : 1 ;
2019-12-15 12:34:00 +00:00
TArray < uint8_t > UserData ;
2019-12-12 18:21:36 +00:00
int RawRate ; // Sample rate to use when bLoadRAW is true
int LoopStart ; // -1 means no specific loop defined
unsigned int link ;
enum { NO_LINK = 0xffffffff } ;
FRolloffInfo Rolloff ;
float Attenuation ; // Multiplies the attenuation passed to S_Sound.
void MarkUsed ( ) ; // Marks this sound as used.
2019-12-15 12:34:00 +00:00
void Clear ( )
{
data . Clear ( ) ;
data3d . Clear ( ) ;
lumpnum = - 1 ; // lump number of sfx
next = - 1 ;
index = 0 ; // [RH] For hashing
Volume = 1.f ;
ResourceId = - 1 ;
PitchMask = 0 ;
NearLimit = 4 ; // 0 means unlimited
LimitRange = 256 * 256 ;
bRandomHeader = false ;
bLoadRAW = false ;
b16bit = false ;
bUsed = false ;
bSingular = false ;
bTentative = true ;
RawRate = 0 ; // Sample rate to use when bLoadRAW is true
LoopStart = 0 ; // -1 means no specific loop defined
link = NO_LINK ;
Rolloff = { } ;
Attenuation = 1.f ;
}
2019-12-12 18:21:36 +00:00
} ;
// 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
} ;
2019-12-19 10:47:47 +00:00
int S_FindSound ( const char * logicalname ) ;
int S_FindSoundByResID ( int snd_id ) ;
2019-12-12 18:21:36 +00:00
// An index into the S_sfx[] array.
class FSoundID
{
public :
FSoundID ( ) = default ;
static FSoundID byResId ( int ndx )
{
return FSoundID ( S_FindSoundByResID ( ndx ) ) ;
}
FSoundID ( int id )
{
ID = id ;
}
FSoundID ( const char * name )
{
ID = S_FindSound ( name ) ;
}
FSoundID ( const FString & name )
{
ID = S_FindSound ( name . GetChars ( ) ) ;
}
FSoundID ( const FSoundID & other ) = default ;
FSoundID & operator = ( const FSoundID & other ) = default ;
FSoundID & operator = ( const char * name )
{
ID = S_FindSound ( name ) ;
return * this ;
}
FSoundID & operator = ( const FString & name )
{
ID = S_FindSound ( name . GetChars ( ) ) ;
return * this ;
}
bool operator ! = ( FSoundID other ) const
{
return ID ! = other . ID ;
}
bool operator ! = ( int other ) const
{
return ID ! = other ;
}
operator int ( ) const
{
return ID ;
}
private :
int ID ;
protected :
enum EDummy { NoInit } ;
FSoundID ( EDummy ) { }
} ;
class FSoundIDNoInit : public FSoundID
{
public :
FSoundIDNoInit ( ) : FSoundID ( NoInit ) { }
using FSoundID : : operator = ;
} ;
struct FSoundChan : public FISoundChannel
{
FSoundChan * NextChan ; // Next channel in this list.
FSoundChan * * PrevChan ; // Previous channel in this list.
FSoundID SoundID ; // Sound ID of playing sound.
FSoundID OrgID ; // Sound ID of sound used to start this channel.
float Volume ;
2019-12-19 10:47:47 +00:00
int EntChannel ; // Actor's sound channel.
2019-12-12 18:21:36 +00:00
int16_t Pitch ; // Pitch variation.
int16_t NearLimit ;
2019-12-19 10:47:47 +00:00
int8_t Priority ;
2019-12-12 18:21:36 +00:00
uint8_t SourceType ;
float LimitRange ;
2019-12-17 18:37:05 +00:00
const void * Source ;
2019-12-19 00:20:43 +00:00
float Point [ 3 ] ; // Sound is not attached to any source.
2019-12-12 18:21:36 +00:00
} ;
// sound channels
// channel 0 never willingly overrides
// other channels (1-7) always override a playing sound on that channel
//
// CHAN_AUTO searches down from channel 7 until it finds a channel not in use
// CHAN_WEAPON is for weapons
// CHAN_VOICE is for oof, sight, or other voice sounds
// CHAN_ITEM is for small things and item pickup
// CHAN_BODY is for generic body sounds
// CHAN_PICKUP can optionally be set as a local sound only for "compatibility"
2019-12-16 23:29:38 +00:00
enum EChannel
2019-12-12 18:21:36 +00:00
{
2019-12-16 23:29:38 +00:00
CHAN_AUTO = 0 ,
CHAN_WEAPON = 1 ,
CHAN_VOICE = 2 ,
CHAN_ITEM = 3 ,
CHAN_BODY = 4 ,
CHAN_5 = 5 ,
CHAN_6 = 6 ,
CHAN_7 = 7 ,
2019-12-12 18:21:36 +00:00
} ;
2019-12-16 23:29:38 +00:00
2019-12-12 18:21:36 +00:00
// sound attenuation values
# define ATTN_NONE 0.f // full volume the entire level
# define ATTN_NORM 1.f
# define ATTN_IDLE 1.001f
# define ATTN_STATIC 3.f // diminish very rapidly with distance
enum // This cannot be remain as this, but for now it has to suffice.
{
2019-12-12 20:42:58 +00:00
SOURCE_Any = - 1 , // Input for check functions meaning 'any source'
2019-12-12 18:21:36 +00:00
SOURCE_None , // Sound is always on top of the listener.
SOURCE_Actor , // Sound is coming from an actor.
2019-12-17 18:37:05 +00:00
SOURCE_Ambient , // Sound is coming from a blood ambient definition.
2019-12-12 18:21:36 +00:00
SOURCE_Unattached , // Sound is not attached to any particular emitter.
2019-12-18 21:13:19 +00:00
SOURCE_Player , // SW player sound (player in SW maintains its own position separately from the sprite so needs to be special.)
2019-12-12 18:21:36 +00:00
} ;
extern ReverbContainer * Environments ;
extern ReverbContainer * DefaultEnvironments [ 26 ] ;
void S_ParseReverbDef ( ) ;
void S_UnloadReverbDef ( ) ;
void S_SetEnvironment ( const ReverbContainer * settings ) ;
ReverbContainer * S_FindEnvironment ( const char * name ) ;
ReverbContainer * S_FindEnvironment ( int id ) ;
void S_AddEnvironment ( ReverbContainer * settings ) ;
class SoundEngine
{
protected :
bool SoundPaused = false ; // whether sound is paused
int RestartEvictionsAt = 0 ; // do not restart evicted channels before this time
SoundListener listener { } ;
FSoundChan * Channels = nullptr ;
FSoundChan * FreeChannels = nullptr ;
// the complete set of sound effects
TArray < sfxinfo_t > S_sfx ;
FRolloffInfo S_Rolloff ;
TArray < uint8_t > S_SoundCurve ;
TMap < int , int > ResIdMap ;
TArray < FRandomSoundList > S_rnd ;
private :
void LoadSound3D ( sfxinfo_t * sfx , FSoundLoadBuffer * pBuffer ) ;
void LinkChannel ( FSoundChan * chan , FSoundChan * * head ) ;
void UnlinkChannel ( FSoundChan * chan ) ;
void ReturnChannel ( FSoundChan * chan ) ;
2019-12-19 00:20:43 +00:00
void RestartChannel ( FSoundChan * chan ) ;
2019-12-12 18:21:36 +00:00
void RestoreEvictedChannel ( FSoundChan * chan ) ;
bool IsChannelUsed ( int sourcetype , const void * actor , int channel , int * seen ) ;
// This is the actual sound positioning logic which needs to be provided by the client.
2019-12-18 10:09:01 +00:00
virtual void CalcPosVel ( int type , const void * source , const float pt [ 3 ] , int channel , int chanflags , FSoundID chanSound , FVector3 * pos , FVector3 * vel , FSoundChan * chan ) = 0 ;
2019-12-12 18:21:36 +00:00
// This can be overridden by the clent to provide some diagnostics. The default lets everything pass.
virtual bool ValidatePosVel ( int sourcetype , const void * source , const FVector3 & pos , const FVector3 & vel ) { return true ; }
bool ValidatePosVel ( const FSoundChan * const chan , const FVector3 & pos , const FVector3 & vel ) ;
// Checks if a copy of this sound is already playing.
bool CheckSingular ( int sound_id ) ;
bool CheckSoundLimit ( sfxinfo_t * sfx , const FVector3 & pos , int near_limit , float limit_range , int sourcetype , const void * actor , int channel ) ;
virtual TArray < uint8_t > ReadSound ( int lumpnum ) = 0 ;
protected :
virtual FSoundID ResolveSound ( const void * ent , int srctype , FSoundID soundid , float & attenuation ) ;
public :
virtual ~ SoundEngine ( ) = default ;
void EvictAllChannels ( ) ;
void StopChannel ( FSoundChan * chan ) ;
sfxinfo_t * LoadSound ( sfxinfo_t * sfx , FSoundLoadBuffer * pBuffer ) ;
// Initializes sound stuff, including volume
// Sets channels, SFX and music volume,
// allocates channel buffer, sets S_sfx lookup.
//
void Init ( TArray < uint8_t > & sndcurve ) ;
void InitData ( ) ;
void Clear ( ) ;
void Shutdown ( ) ;
void StopAllChannels ( void ) ;
void SetPitch ( FSoundChan * chan , float dpitch ) ;
2019-12-18 21:13:19 +00:00
void SetVolume ( FSoundChan * chan , float vol ) ;
2019-12-12 18:21:36 +00:00
FSoundChan * GetChannel ( void * syschan ) ;
void RestoreEvictedChannels ( ) ;
void CalcPosVel ( FSoundChan * chan , FVector3 * pos , FVector3 * vel ) ;
// Loads a sound, including any random sounds it might reference.
void CacheSound ( sfxinfo_t * sfx ) ;
void CacheSound ( int sfx ) { CacheSound ( & S_sfx [ sfx ] ) ; }
void UnloadSound ( sfxinfo_t * sfx ) ;
void UpdateSounds ( int time ) ;
FSoundChan * StartSound ( int sourcetype , const void * source ,
2019-12-16 23:29:38 +00:00
const FVector3 * pt , int channel , EChanFlags flags , FSoundID sound_id , float volume , float attenuation , FRolloffInfo * rolloff = nullptr , float spitch = 0.0f ) ;
2019-12-12 18:21:36 +00:00
// Stops an origin-less sound from playing from this channel.
2019-12-12 20:42:58 +00:00
void StopSoundID ( int sound_id ) ;
void StopSound ( int channel , int sound_id = - 1 ) ;
void StopSound ( int sourcetype , const void * actor , int channel , int sound_id = - 1 ) ;
2019-12-12 18:21:36 +00:00
void RelinkSound ( int sourcetype , const void * from , const void * to , const FVector3 * optpos ) ;
void ChangeSoundVolume ( int sourcetype , const void * source , int channel , double dvolume ) ;
2019-12-12 20:42:58 +00:00
void ChangeSoundPitch ( int sourcetype , const void * source , int channel , double pitch , int sound_id = - 1 ) ;
2019-12-17 22:25:07 +00:00
bool IsSourcePlayingSomething ( int sourcetype , const void * actor , int channel , int sound_id = - 1 ) ;
2019-12-12 18:21:36 +00:00
// Stop and resume music, during game PAUSE.
2019-12-15 12:34:00 +00:00
int GetSoundPlayingInfo ( int sourcetype , const void * source , int sound_id ) ;
2019-12-12 18:21:36 +00:00
void UnloadAllSounds ( ) ;
void Reset ( ) ;
void MarkUsed ( int num ) ;
void CacheMarkedSounds ( ) ;
2019-12-15 19:16:36 +00:00
FString NoiseDebug ( ) ;
2019-12-12 18:21:36 +00:00
TArray < FSoundChan * > AllActiveChannels ( ) ;
void MarkAllUnused ( )
{
for ( auto & s : S_sfx ) s . bUsed = false ;
}
bool isListener ( const void * object ) const
{
return object & & listener . ListenerObject = = object ;
}
void SetListener ( SoundListener & l )
{
listener = l ;
}
void SetRestartTime ( int time )
{
RestartEvictionsAt = time ;
}
void SetPaused ( bool on )
{
SoundPaused = on ;
}
FSoundChan * GetChannels ( )
{
return Channels ;
}
const char * GetSoundName ( FSoundID id )
{
return id = = 0 ? " " : S_sfx [ id ] . name . GetChars ( ) ;
}
TArray < sfxinfo_t > & GetSounds ( ) //Thio should only be used for constructing the sound list or for diagnostics code prinring information about the sound list.
{
return S_sfx ;
}
FRolloffInfo & GlobalRolloff ( ) // like GetSounds this is meant for sound list generators, not for gaining cheap access to the sound engine's innards.
{
return S_Rolloff ;
}
FRandomSoundList * ResolveRandomSound ( sfxinfo_t * sfx )
{
return & S_rnd [ sfx - > link ] ;
}
void ClearRandoms ( )
{
S_rnd . Clear ( ) ;
}
2019-12-15 12:34:00 +00:00
void * GetUserData ( int snd )
2019-12-12 20:42:58 +00:00
{
2019-12-15 12:34:00 +00:00
return S_sfx [ snd ] . UserData . Data ( ) ;
2019-12-12 20:42:58 +00:00
}
2019-12-15 12:34:00 +00:00
bool isValidSoundId ( int id )
2019-12-12 20:42:58 +00:00
{
2019-12-17 22:25:07 +00:00
return id > 0 & & id < ( int ) S_sfx . Size ( ) & & ! S_sfx [ id ] . bTentative & & S_sfx [ id ] . lumpnum ! = sfx_empty ;
2019-12-12 20:42:58 +00:00
}
2019-12-15 12:34:00 +00:00
template < class func > bool EnumerateChannels ( func callback )
2019-12-12 20:42:58 +00:00
{
2019-12-15 12:34:00 +00:00
for ( FSoundChan * chan = Channels ; chan ; chan = chan - > NextChan )
{
2019-12-17 18:37:05 +00:00
int res = callback ( chan ) ;
if ( res ) return res > 0 ;
2019-12-15 12:34:00 +00:00
}
return false ;
2019-12-12 20:42:58 +00:00
}
2019-12-12 18:21:36 +00:00
2019-12-15 15:32:39 +00:00
void SetDefaultRolloff ( FRolloffInfo * ro )
{
S_Rolloff = * ro ;
}
2019-12-12 18:21:36 +00:00
void ChannelVirtualChanged ( FISoundChannel * ichan , bool is_virtual ) ;
FString ListSoundChannels ( ) ;
// Allow this to be overridden for special needs.
virtual float GetRolloff ( const FRolloffInfo * rolloff , float distance ) ;
virtual void ChannelEnded ( FISoundChannel * ichan ) ; // allows the client to do bookkeeping on the sound.
// Lookup utilities.
int FindSound ( const char * logicalname ) ;
int FindSoundByResID ( int rid ) ;
int FindSoundNoHash ( const char * logicalname ) ;
int FindSoundByLump ( int lump ) ;
2019-12-15 15:32:39 +00:00
int AddSoundLump ( const char * logicalname , int lump , int CurrentPitchMask , int resid = - 1 , int nearlimit = 2 ) ;
2019-12-17 18:37:05 +00:00
int AddSfx ( sfxinfo_t & sfx ) ;
2019-12-12 18:21:36 +00:00
int FindSoundTentative ( const char * name ) ;
void CacheRandomSound ( sfxinfo_t * sfx ) ;
unsigned int GetMSLength ( FSoundID sound ) ;
int PickReplacement ( int refid ) ;
void HashSounds ( ) ;
void AddRandomSound ( int Owner , TArray < uint32_t > list ) ;
} ;
extern SoundEngine * soundEngine ;
struct FReverbField
{
int Min , Max ;
float REVERB_PROPERTIES : : * Float ;
int REVERB_PROPERTIES : : * Int ;
unsigned int Flag ;
} ;
2019-12-16 15:18:47 +00:00
inline void FX_StopAllSounds ( void )
{
soundEngine - > StopAllChannels ( ) ;
}
2019-12-12 18:21:36 +00:00
2019-12-22 16:43:39 +00:00
void FX_SetReverb ( int strength ) ;
2019-12-17 18:37:05 +00:00
inline void FX_SetReverbDelay ( int delay )
{
}
inline int S_FindSoundByResID ( int ndx )
{
return soundEngine - > FindSoundByResID ( ndx ) ;
}
inline int S_FindSound ( const char * name )
{
return soundEngine - > FindSound ( name ) ;
}