2006-04-13 20:47:06 +00:00
//-------------------------------------------------------------------------
/*
2016-02-07 02:38:03 +00:00
Copyright ( C ) 2016 EDuke32 developers and contributors
2019-12-16 12:02:43 +00:00
Copyright ( C ) 2019 Christoph Oelckers
2006-04-13 20:47:06 +00:00
2019-12-16 12:02:43 +00:00
This is free software ; you can redistribute it and / or
2006-04-13 20:47:06 +00:00
modify it under the terms of the GNU General Public License version 2
as published by the Free Software Foundation .
This program is distributed in the hope that it will be useful ,
but WITHOUT ANY WARRANTY ; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE .
See the GNU General Public License for more details .
You should have received a copy of the GNU General Public License
along with this program ; if not , write to the Free Software
2014-07-20 08:55:56 +00:00
Foundation , Inc . , 51 Franklin Street , Fifth Floor , Boston , MA 02110 - 1301 , USA .
2006-04-13 20:47:06 +00:00
*/
//-------------------------------------------------------------------------
2019-09-21 18:59:54 +00:00
# include "ns.h" // Must come before everything else!
2017-02-25 08:15:45 +00:00
# include "compat.h"
2012-11-05 02:49:08 +00:00
2006-04-13 20:47:06 +00:00
# include "duke3d.h"
2019-11-10 22:58:51 +00:00
# include "z_music.h"
2019-12-09 23:01:45 +00:00
# include "mapinfo.h"
2019-12-12 20:42:58 +00:00
# include "sound/s_soundinternal.h"
2010-07-19 15:14:00 +00:00
2019-09-21 20:53:00 +00:00
BEGIN_DUKE_NS
2015-02-11 05:22:00 +00:00
2019-12-15 12:34:00 +00:00
class DukeSoundEngine : public SoundEngine
2006-04-16 03:42:36 +00:00
{
2019-12-15 12:34:00 +00:00
// client specific parts of the sound engine go in this class.
2019-12-18 10:09:01 +00:00
void CalcPosVel ( int type , const void * source , const float pt [ 3 ] , int channum , int chanflags , FSoundID chanSound , FVector3 * pos , FVector3 * vel , FSoundChan * chan ) override ;
2020-01-06 01:41:47 +00:00
TArray < uint8_t > ReadSound ( int lumpnum ) override ;
2009-08-06 10:12:13 +00:00
2019-12-15 12:34:00 +00:00
public :
2019-12-15 15:32:39 +00:00
DukeSoundEngine ( )
{
2019-12-15 19:55:15 +00:00
S_Rolloff . RolloffType = ROLLOFF_Doom ; // Seems like Duke uses the same rolloff type as Doom.
S_Rolloff . MinDistance = 144 ; // was originally 576 which looks like a bug and sounds like crap.
S_Rolloff . MaxDistance = 1088 ;
2019-12-15 15:32:39 +00:00
}
2019-12-15 12:34:00 +00:00
} ;
2009-07-27 05:33:12 +00:00
2019-12-15 16:16:11 +00:00
void S_InitSound ( )
{
soundEngine = new DukeSoundEngine ;
}
2019-12-15 12:34:00 +00:00
//==========================================================================
//
2019-12-16 12:02:43 +00:00
//
2019-12-15 12:34:00 +00:00
//
//==========================================================================
2006-04-13 20:47:06 +00:00
2019-12-15 12:34:00 +00:00
TArray < uint8_t > DukeSoundEngine : : ReadSound ( int lumpnum )
2006-04-16 03:42:36 +00:00
{
2019-12-15 12:34:00 +00:00
auto wlump = fileSystem . OpenFileReader ( lumpnum ) ;
return wlump . Read ( ) ;
2006-04-16 03:42:36 +00:00
}
2006-04-13 20:47:06 +00:00
2019-12-15 12:34:00 +00:00
//==========================================================================
//
//
//
//==========================================================================
2018-10-25 23:32:29 +00:00
void S_PauseSounds ( bool paused )
2016-02-02 06:39:22 +00:00
{
2019-12-15 12:34:00 +00:00
soundEngine - > SetPaused ( paused ) ;
}
2016-02-02 06:39:22 +00:00
2019-12-15 12:34:00 +00:00
//==========================================================================
//
//
//
//==========================================================================
2016-02-02 06:39:22 +00:00
2019-12-15 12:34:00 +00:00
void cacheAllSounds ( void )
{
2019-12-15 16:16:11 +00:00
auto & sfx = soundEngine - > GetSounds ( ) ;
int i = 0 ;
for ( auto & snd : sfx )
2016-02-02 06:39:22 +00:00
{
2019-12-15 16:16:11 +00:00
soundEngine - > CacheSound ( & snd ) ;
if ( ( ( + + i ) & 31 ) = = 0 )
2019-12-15 12:34:00 +00:00
gameHandleEvents ( ) ;
2016-02-02 06:39:22 +00:00
}
}
2019-12-15 12:34:00 +00:00
//==========================================================================
//
//
//
//==========================================================================
2006-04-13 20:47:06 +00:00
2019-12-15 12:34:00 +00:00
static inline int S_GetPitch ( int num )
{
2019-12-16 18:18:03 +00:00
auto const * snd = ( sound_t * ) soundEngine - > GetUserData ( num + 1 ) ;
if ( ! snd ) return 0 ;
2019-12-15 12:34:00 +00:00
int const range = abs ( snd - > pitchEnd - snd - > pitchStart ) ;
2010-01-05 21:53:14 +00:00
2019-12-15 12:34:00 +00:00
return ( range = = 0 ) ? snd - > pitchStart : min ( snd - > pitchStart , snd - > pitchEnd ) + rand ( ) % range ;
2006-04-13 20:47:06 +00:00
}
2019-12-15 12:34:00 +00:00
float S_ConvertPitch ( int lpitch )
2018-04-02 22:00:11 +00:00
{
2019-12-15 12:34:00 +00:00
return pow ( 2 , lpitch / 1200. ) ; // I hope I got this right that ASS uses a linear scale where 1200 is a full octave.
2018-04-02 22:00:11 +00:00
}
2012-08-13 18:25:48 +00:00
2019-12-16 18:18:03 +00:00
int S_GetUserFlags ( int num )
2012-08-13 18:25:48 +00:00
{
2020-01-12 08:32:30 +00:00
if ( ! soundEngine - > isValidSoundId ( num + 1 ) ) return 0 ;
2019-12-16 18:18:03 +00:00
auto const * snd = ( sound_t * ) soundEngine - > GetUserData ( num + 1 ) ;
if ( ! snd ) return 0 ;
return snd - > flags ;
2012-08-13 18:25:48 +00:00
}
2019-12-15 09:00:25 +00:00
//==========================================================================
//
//
//
//==========================================================================
2015-02-11 05:22:00 +00:00
2019-12-15 12:34:00 +00:00
int S_DefineSound ( unsigned index , const char * filename , int minpitch , int maxpitch , int priority , int type , int distance , float volume )
2019-12-15 09:00:25 +00:00
{
2019-12-15 12:34:00 +00:00
if ( ( unsigned ) index > = MAXSOUNDS )
return - 1 ;
auto & S_sfx = soundEngine - > GetSounds ( ) ;
index + + ;
unsigned oldindex = S_sfx . Size ( ) ;
if ( index > = S_sfx . Size ( ) )
{
S_sfx . Resize ( index + 1 ) ;
for ( ; oldindex < = index ; oldindex + + )
{
S_sfx [ oldindex ] . Clear ( ) ;
}
}
auto sfx = & S_sfx [ index ] ;
bool alreadydefined = ! sfx - > bTentative ;
sfx - > UserData . Resize ( sizeof ( sound_t ) ) ;
auto sndinf = ( sound_t * ) sfx - > UserData . Data ( ) ;
sndinf - > flags = type & ~ SF_ONEINST_INTERNAL ;
if ( sndinf - > flags & SF_LOOP )
sndinf - > flags | = SF_ONEINST_INTERNAL ;
2020-01-27 21:29:45 +00:00
sfx - > lumpnum = S_LookupSound ( filename ) ;
2019-12-15 12:34:00 +00:00
sndinf - > pitchStart = clamp ( minpitch , INT16_MIN , INT16_MAX ) ;
sndinf - > pitchEnd = clamp ( maxpitch , INT16_MIN , INT16_MAX ) ;
sndinf - > priority = priority & 255 ;
sndinf - > volAdjust = clamp ( distance , INT16_MIN , INT16_MAX ) ;
sfx - > Volume = volume ;
2019-12-16 12:41:57 +00:00
sfx - > NearLimit = 6 ;
2019-12-15 18:00:41 +00:00
sfx - > bTentative = false ;
2019-12-15 19:16:36 +00:00
sfx - > name = filename ;
2019-12-15 12:34:00 +00:00
return 0 ;
2019-12-15 09:00:25 +00:00
}
2018-10-25 23:32:29 +00:00
2019-12-15 12:34:00 +00:00
2019-12-15 09:00:25 +00:00
//==========================================================================
//
//
//
//==========================================================================
2012-08-13 18:25:48 +00:00
2019-12-15 12:34:00 +00:00
static int S_CalcDistAndAng ( int spriteNum , int soundNum , int sectNum ,
2019-12-15 09:00:25 +00:00
const vec3_t * cam , const vec3_t * pos , int * distPtr , FVector3 * sndPos )
{
2019-12-15 15:32:39 +00:00
// There's a lot of hackery going on here that could be mapped to rolloff and attenuation parameters.
// However, ultimately rolloff would also just reposition the sound source so this can remain as it is.
2019-12-15 09:00:25 +00:00
int orgsndist = 0 , sndang = 0 , sndist = 0 , explosion = 0 ;
2019-12-16 12:02:43 +00:00
auto const * snd = ( sound_t * ) soundEngine - > GetUserData ( soundNum + 1 ) ;
2019-12-16 18:18:03 +00:00
int userflags = snd ? snd - > flags : 0 ;
int dist_adjust = snd ? snd - > volAdjust : 0 ;
2018-10-25 23:32:29 +00:00
2019-12-15 15:32:39 +00:00
if ( PN ( spriteNum ) ! = APLAYER | | P_Get ( spriteNum ) ! = screenpeek )
{
orgsndist = sndist = FindDistance3D ( cam - > x - pos - > x , cam - > y - pos - > y , ( cam - > z - pos - > z ) ) ;
2018-10-25 23:32:29 +00:00
2019-12-15 15:32:39 +00:00
if ( ( userflags & ( SF_GLOBAL | SF_DTAG ) ) ! = SF_GLOBAL & & S_IsAmbientSFX ( spriteNum ) & & ( sector [ SECT ( spriteNum ) ] . lotag & 0xff ) < 9 ) // ST_9_SLIDING_ST_DOOR
sndist = divscale14 ( sndist , SHT ( spriteNum ) + 1 ) ;
}
2012-10-08 07:07:59 +00:00
2019-12-15 09:00:25 +00:00
sndist + = dist_adjust ;
if ( sndist < 0 )
sndist = 0 ;
2012-08-13 18:25:48 +00:00
2019-12-15 09:00:25 +00:00
if ( ! FURY & & sectNum > - 1 & & sndist & & PN ( spriteNum ) ! = MUSICANDSFX
& & ! cansee ( cam - > x , cam - > y , cam - > z - ( 24 < < 8 ) , sectNum , SX ( spriteNum ) , SY ( spriteNum ) , SZ ( spriteNum ) - ( 24 < < 8 ) , SECT ( spriteNum ) ) )
sndist + = sndist > > 5 ;
2012-10-08 07:07:17 +00:00
2019-12-15 15:32:39 +00:00
// Here the sound distance was clamped to a minimum of 144*4.
// It's better to handle rolloff in the backend instead of whacking the sound origin here.
// That way the lower end can be made customizable instead of losing all precision right here at the source.
if ( sndist < 0 ) sndist = 0 ;
2012-10-08 07:07:17 +00:00
2019-12-15 09:00:25 +00:00
if ( distPtr )
{
* distPtr = sndist ;
}
2012-10-08 07:07:17 +00:00
2019-12-15 09:00:25 +00:00
if ( sndPos )
{
2019-12-17 18:37:05 +00:00
FVector3 sndorg = GetSoundPos ( pos ) ;
FVector3 campos = GetSoundPos ( cam ) ;
2019-12-15 15:32:39 +00:00
// Now calculate the virtual position in sound system coordinates.
2019-12-16 12:02:43 +00:00
FVector3 sndvec = sndorg - campos ;
2019-12-15 18:00:41 +00:00
if ( orgsndist > 0 )
{
2019-12-16 12:02:43 +00:00
float scale = float ( sndist ) / orgsndist ; // adjust by what was calculated above;
* sndPos = campos + sndvec * scale ;
2019-12-15 18:00:41 +00:00
}
else * sndPos = campos ;
2019-12-15 09:00:25 +00:00
}
2012-10-08 07:07:17 +00:00
2019-12-16 12:41:57 +00:00
return false ;
2012-08-13 18:25:48 +00:00
}
2019-12-15 09:00:25 +00:00
//==========================================================================
//
//
//
//==========================================================================
2012-08-13 18:25:53 +00:00
2019-12-15 12:34:00 +00:00
void S_GetCamera ( vec3_t * * c , int32_t * ca , int32_t * cs )
2019-12-12 20:42:58 +00:00
{
if ( ud . camerasprite = = - 1 )
{
if ( ud . overhead_on ! = 2 )
{
2019-12-15 12:34:00 +00:00
if ( c ) * c = & CAMERA ( pos ) ;
if ( cs ) * cs = CAMERA ( sect ) ;
if ( ca ) * ca = fix16_to_int ( CAMERA ( q16ang ) ) ;
2019-12-12 20:42:58 +00:00
}
else
{
auto pPlayer = g_player [ screenpeek ] . ps ;
2019-12-15 12:34:00 +00:00
if ( c ) * c = & pPlayer - > pos ;
if ( cs ) * cs = pPlayer - > cursectnum ;
if ( ca ) * ca = fix16_to_int ( pPlayer - > q16ang ) ;
2019-12-12 20:42:58 +00:00
}
}
else
{
2019-12-15 12:34:00 +00:00
if ( c ) * c = & sprite [ ud . camerasprite ] . pos ;
if ( cs ) * cs = sprite [ ud . camerasprite ] . sectnum ;
if ( ca ) * ca = sprite [ ud . camerasprite ] . ang ;
2019-12-12 20:42:58 +00:00
}
2019-12-15 12:34:00 +00:00
}
2019-12-12 20:42:58 +00:00
2019-12-15 12:34:00 +00:00
//=========================================================================
//
// CalcPosVel
//
// The game specific part of the sound updater.
//
//=========================================================================
2019-12-12 20:42:58 +00:00
2019-12-18 10:09:01 +00:00
void DukeSoundEngine : : CalcPosVel ( int type , const void * source , const float pt [ 3 ] , int channum , int chanflags , FSoundID chanSound , FVector3 * pos , FVector3 * vel , FSoundChan * )
2019-12-15 12:34:00 +00:00
{
if ( pos ! = nullptr )
2019-12-12 20:42:58 +00:00
{
2019-12-15 12:34:00 +00:00
vec3_t * campos ;
int32_t camsect ;
S_GetCamera ( & campos , nullptr , & camsect ) ;
if ( vel ) vel - > Zero ( ) ;
2019-12-12 20:42:58 +00:00
2019-12-15 12:34:00 +00:00
if ( type = = SOURCE_Unattached )
2019-12-12 20:42:58 +00:00
{
2019-12-15 12:34:00 +00:00
pos - > X = pt [ 0 ] ;
2019-12-16 12:02:43 +00:00
pos - > Y = pt [ 1 ] ;
2019-12-15 12:34:00 +00:00
pos - > Z = pt [ 2 ] ;
}
2019-12-16 12:02:43 +00:00
else if ( type = = SOURCE_Actor )
2019-12-15 12:34:00 +00:00
{
2019-12-16 12:02:43 +00:00
auto actor = ( spritetype * ) source ;
assert ( actor ! = nullptr ) ;
if ( actor ! = nullptr )
2019-12-15 12:34:00 +00:00
{
2019-12-16 12:02:43 +00:00
S_CalcDistAndAng ( int ( actor - sprite ) , chanSound - 1 , camsect , campos , & actor - > pos , nullptr , pos ) ;
/*
if ( vel ) // DN3D does not properly maintain this.
2019-12-15 12:34:00 +00:00
{
2019-12-16 12:02:43 +00:00
vel - > X = float ( actor - > Vel . X * TICRATE ) ;
vel - > Y = float ( actor - > Vel . Z * TICRATE ) ;
vel - > Z = float ( actor - > Vel . Y * TICRATE ) ;
2019-12-15 12:34:00 +00:00
}
2019-12-16 12:02:43 +00:00
*/
2019-12-15 12:34:00 +00:00
}
}
2019-12-16 23:29:38 +00:00
if ( ( chanflags & CHANF_LISTENERZ ) & & campos ! = nullptr & & type ! = SOURCE_None )
2019-12-16 12:02:43 +00:00
{
pos - > Y = campos - > z / 256.f ;
}
2019-12-15 12:34:00 +00:00
}
}
2019-12-12 20:42:58 +00:00
2019-12-15 12:34:00 +00:00
//==========================================================================
//
//
//
//==========================================================================
2019-12-12 20:42:58 +00:00
2019-12-15 12:34:00 +00:00
void S_Update ( void )
{
SoundListener listener ;
vec3_t * c ;
int32_t ca , cs ;
2019-12-12 20:42:58 +00:00
2019-12-15 12:34:00 +00:00
S_GetCamera ( & c , & ca , & cs ) ;
2019-12-12 20:42:58 +00:00
2019-12-15 12:34:00 +00:00
if ( c ! = nullptr )
{
2019-12-16 12:02:43 +00:00
listener . angle = - ( float ) ca * pi : : pi ( ) / 1024 ; // Build uses a period of 2048.
2019-12-15 12:34:00 +00:00
listener . velocity . Zero ( ) ;
2019-12-17 18:37:05 +00:00
listener . position = GetSoundPos ( c ) ;
2019-12-15 12:34:00 +00:00
listener . underwater = false ;
// This should probably use a real environment instead of the pitch hacking in S_PlaySound3D.
// listenactor->waterlevel == 3;
//assert(primaryLevel->Zones.Size() > listenactor->Sector->ZoneNumber);
listener . Environment = 0 ; // primaryLevel->Zones[listenactor->Sector->ZoneNumber].Environment;
listener . valid = true ;
}
else
2019-12-16 12:02:43 +00:00
{
2019-12-15 12:34:00 +00:00
listener . angle = 0 ;
listener . position . Zero ( ) ;
listener . velocity . Zero ( ) ;
listener . underwater = false ;
listener . Environment = nullptr ;
listener . valid = false ;
}
listener . ListenerObject = ud . camerasprite = = - 1 ? nullptr : & sprite [ ud . camerasprite ] ;
soundEngine - > SetListener ( listener ) ;
2019-12-15 18:00:41 +00:00
soundEngine - > UpdateSounds ( ( int ) totalclock ) ;
2019-12-12 20:42:58 +00:00
}
2014-06-23 02:24:10 +00:00
2019-12-12 20:42:58 +00:00
//==========================================================================
//
//
//
//==========================================================================
2014-06-23 02:24:10 +00:00
2019-12-16 23:29:38 +00:00
int S_PlaySound3D ( int num , int spriteNum , const vec3_t * pos , int channel , EChanFlags flags )
2019-12-12 20:42:58 +00:00
{
int sndnum = VM_OnEventWithReturn ( EVENT_SOUND , spriteNum , screenpeek , num ) ;
2018-05-04 22:42:37 +00:00
2019-07-08 00:41:25 +00:00
auto const pPlayer = g_player [ myconnectindex ] . ps ;
2019-12-16 16:41:44 +00:00
if ( ! soundEngine - > isValidSoundId ( sndnum + 1 ) | | ! SoundEnabled ( ) | | ( unsigned ) spriteNum > = MAXSPRITES | | ( pPlayer - > gm & MODE_MENU ) | |
2019-12-12 20:42:58 +00:00
( pPlayer - > timebeforeexit > 0 & & pPlayer - > timebeforeexit < = GAMETICSPERSEC * 3 ) ) return - 1 ;
2015-02-11 05:22:00 +00:00
2019-12-15 12:34:00 +00:00
int userflags = S_GetUserFlags ( sndnum ) ;
2019-12-12 20:42:58 +00:00
if ( ( ! ( snd_speech & 1 ) & & ( userflags & SF_TALK ) ) | | ( ( userflags & SF_ADULT ) & & adult_lockout ) )
2013-03-31 18:58:17 +00:00
return - 1 ;
2006-04-13 20:47:06 +00:00
2018-05-04 22:42:37 +00:00
// Duke talk
2019-12-12 20:42:58 +00:00
if ( userflags & SF_TALK )
2018-05-04 22:42:37 +00:00
{
2018-10-25 23:32:29 +00:00
if ( ( g_netServer | | ud . multimode > 1 ) & & PN ( spriteNum ) = = APLAYER & & P_Get ( spriteNum ) ! = screenpeek ) // other player sound
2018-05-04 22:42:37 +00:00
{
2019-10-22 00:01:05 +00:00
if ( ( snd_speech & 4 ) ! = 4 )
2018-05-04 22:42:37 +00:00
return - 1 ;
}
2019-10-22 00:01:05 +00:00
else if ( ( snd_speech & 1 ) ! = 1 )
2018-05-04 22:42:37 +00:00
return - 1 ;
2015-02-11 05:22:00 +00:00
2019-12-15 12:34:00 +00:00
bool foundone = soundEngine - > EnumerateChannels ( [ & ] ( FSoundChan * chan )
{
2019-12-16 16:41:44 +00:00
auto sid = chan - > OrgID ;
2019-12-16 18:18:03 +00:00
auto flags = S_GetUserFlags ( sid - 1 ) ;
2019-12-15 12:34:00 +00:00
return ! ! ( flags & SF_TALK ) ;
} ) ;
2018-05-04 22:42:37 +00:00
// don't play if any Duke talk sounds are already playing
2019-12-15 12:34:00 +00:00
if ( foundone ) return - 1 ;
2018-05-04 22:42:37 +00:00
}
2019-12-12 20:42:58 +00:00
else if ( ( userflags & ( SF_DTAG | SF_GLOBAL ) ) = = SF_DTAG ) // Duke-Tag sound
2006-04-13 20:47:06 +00:00
{
2019-12-12 20:42:58 +00:00
return S_PlaySound ( sndnum ) ;
2018-05-04 22:42:37 +00:00
2006-04-13 20:47:06 +00:00
}
2019-12-15 09:00:25 +00:00
int32_t sndist ;
FVector3 sndpos ; // this is in sound engine space.
2019-12-15 12:34:00 +00:00
vec3_t * campos ;
int32_t camsect ;
S_GetCamera ( & campos , nullptr , & camsect ) ;
2019-12-16 12:41:57 +00:00
S_CalcDistAndAng ( spriteNum , sndnum , camsect , campos , pos , & sndist , & sndpos ) ;
2019-12-12 20:42:58 +00:00
int pitch = S_GetPitch ( sndnum ) ;
auto const pOther = g_player [ screenpeek ] . ps ;
2006-04-13 20:47:06 +00:00
2012-08-22 22:50:32 +00:00
2018-05-04 22:42:37 +00:00
if ( pOther - > sound_pitch )
pitch + = pOther - > sound_pitch ;
2012-08-13 18:25:51 +00:00
2019-12-16 12:41:57 +00:00
bool explosionp = ( ( userflags & ( SF_GLOBAL | SF_DTAG ) ) = = ( SF_GLOBAL | SF_DTAG ) ) | | ( ( ! FURY ) & & ( sndnum = = PIPEBOMB_EXPLODE | | sndnum = = LASERTRIP_EXPLODE | | sndnum = = RPG_EXPLODE ) ) ;
2012-08-13 18:25:51 +00:00
if ( explosionp )
2006-04-13 20:47:06 +00:00
{
2018-05-04 22:42:37 +00:00
if ( pOther - > cursectnum > - 1 & & sector [ pOther - > cursectnum ] . lotag = = ST_2_UNDERWATER )
2006-11-16 03:02:42 +00:00
pitch - = 1024 ;
2012-08-13 18:25:51 +00:00
}
else
{
2019-12-12 20:42:58 +00:00
if ( sndist > 32767 & & PN ( spriteNum ) ! = MUSICANDSFX & & ( userflags & ( SF_LOOP | SF_MSFX ) ) = = 0 )
2011-03-04 08:50:58 +00:00
return - 1 ;
2012-08-13 18:25:51 +00:00
2018-05-04 22:42:37 +00:00
if ( pOther - > cursectnum > - 1 & & sector [ pOther - > cursectnum ] . lotag = = ST_2_UNDERWATER
2019-12-12 20:42:58 +00:00
& & ( userflags & SF_TALK ) = = 0 )
2006-11-16 03:02:42 +00:00
pitch = - 768 ;
2006-04-13 20:47:06 +00:00
}
2019-12-15 12:34:00 +00:00
bool is_playing = soundEngine - > GetSoundPlayingInfo ( SOURCE_Any , nullptr , sndnum + 1 ) ;
2019-12-15 09:00:25 +00:00
if ( is_playing & & PN ( spriteNum ) ! = MUSICANDSFX )
S_StopEnvSound ( sndnum , spriteNum ) ;
2006-04-13 20:47:06 +00:00
2019-12-15 09:00:25 +00:00
int const repeatp = ( userflags & SF_LOOP ) ;
2006-04-13 20:47:06 +00:00
2019-12-15 09:00:25 +00:00
if ( repeatp & & ( userflags & SF_ONEINST_INTERNAL ) & & is_playing )
2010-03-01 09:09:26 +00:00
{
return - 1 ;
}
2010-01-05 21:53:14 +00:00
2019-12-16 12:41:57 +00:00
// These explosion sounds originally used some distance hackery to make them louder but due to how the rolloff was set up they always played at full volume as a result.
// I think it is better to lower their attenuation so that they are louder than the rest but still fade in the distance.
// For the original effect, attenuation needs to be set to ATTN_NONE here.
float attenuation ;
if ( explosionp ) attenuation = 0.5f ;
else attenuation = ( userflags & ( SF_GLOBAL | SF_DTAG ) ) = = SF_GLOBAL ? ATTN_NONE : ATTN_NORM ;
2019-12-16 23:29:38 +00:00
if ( userflags & SF_LOOP ) flags | = CHANF_LOOP ;
auto chan = soundEngine - > StartSound ( SOURCE_Actor , & sprite [ spriteNum ] , & sndpos , channel , flags , sndnum + 1 , attenuation = = ATTN_NONE ? 0.8f : 1.f , attenuation , nullptr , S_ConvertPitch ( pitch ) ) ;
2019-12-16 12:02:43 +00:00
return chan ? 0 : - 1 ;
2006-04-13 20:47:06 +00:00
}
2019-12-12 20:42:58 +00:00
//==========================================================================
//
//
//
//==========================================================================
2019-12-16 23:29:38 +00:00
int S_PlaySound ( int num , int channel , EChanFlags flags )
2006-04-13 20:47:06 +00:00
{
2018-10-25 23:32:29 +00:00
int sndnum = VM_OnEventWithReturn ( EVENT_SOUND , g_player [ screenpeek ] . ps - > i , screenpeek , num ) ;
2014-06-23 02:24:10 +00:00
2019-12-15 12:34:00 +00:00
if ( ! soundEngine - > isValidSoundId ( sndnum + 1 ) | | ! SoundEnabled ( ) ) return - 1 ;
2007-08-15 03:05:14 +00:00
2019-12-15 12:34:00 +00:00
int userflags = S_GetUserFlags ( sndnum ) ;
2019-12-12 20:42:58 +00:00
if ( ( ! ( snd_speech & 1 ) & & ( userflags & SF_TALK ) ) | | ( ( userflags & SF_ADULT ) & & adult_lockout ) )
2015-02-11 05:22:00 +00:00
return - 1 ;
2012-01-10 23:44:49 +00:00
2019-12-15 12:34:00 +00:00
int const pitch = S_GetPitch ( sndnum ) ;
2006-04-13 20:47:06 +00:00
2019-12-16 23:29:38 +00:00
if ( userflags & SF_LOOP ) flags | = CHANF_LOOP ;
auto chan = soundEngine - > StartSound ( SOURCE_None , nullptr , nullptr , channel , flags , sndnum + 1 , 0.8f , ATTN_NONE , nullptr , S_ConvertPitch ( pitch ) ) ;
2019-12-16 12:02:43 +00:00
return chan ? 0 : - 1 ;
2006-04-13 20:47:06 +00:00
}
2019-12-12 20:42:58 +00:00
//==========================================================================
//
//
//
//==========================================================================
2019-12-16 23:29:38 +00:00
int A_PlaySound ( int soundNum , int spriteNum , int channel , EChanFlags flags )
2006-04-13 20:47:06 +00:00
{
2019-12-28 11:59:19 +00:00
return ( unsigned ) spriteNum > = MAXSPRITES ? S_PlaySound ( soundNum , channel , flags ) :
S_PlaySound3D ( soundNum , spriteNum , & sprite [ spriteNum ] . pos , channel , flags ) ;
2006-04-13 20:47:06 +00:00
}
2019-12-16 23:29:38 +00:00
void S_StopEnvSound ( int sndNum , int sprNum , int channel )
2006-04-13 20:47:06 +00:00
{
2019-12-12 20:42:58 +00:00
if ( sprNum < - 1 | | sprNum > = MAXSPRITES ) return ;
2010-03-01 09:09:26 +00:00
2019-12-15 12:34:00 +00:00
if ( sprNum = = - 1 ) soundEngine - > StopSoundID ( sndNum + 1 ) ;
2019-12-28 11:59:19 +00:00
else
{
if ( channel = = - 1 ) soundEngine - > StopSound ( SOURCE_Actor , & sprite [ sprNum ] , - 1 , sndNum + 1 ) ;
else soundEngine - > StopSound ( SOURCE_Actor , & sprite [ sprNum ] , channel , - 1 ) ;
// StopSound kills the actor reference so this cannot be delayed until ChannelEnded gets called. At that point the actor may also not be valid anymore.
if ( S_IsAmbientSFX ( sprNum ) & & sector [ SECT ( sprNum ) ] . lotag < 3 ) // ST_2_UNDERWATER
actor [ sprNum ] . t_data [ 0 ] = 0 ;
}
2017-01-05 05:29:25 +00:00
}
2018-10-25 23:32:29 +00:00
void S_ChangeSoundPitch ( int soundNum , int spriteNum , int pitchoffset )
2011-11-03 23:08:54 +00:00
{
2019-12-12 20:42:58 +00:00
if ( spriteNum < - 1 | | spriteNum > = MAXSPRITES ) return ;
double expitch = pow ( 2 , pitchoffset / 1200. ) ; // I hope I got this right that ASS uses a linear scale where 1200 is a full octave.
if ( spriteNum = = - 1 )
2011-11-03 23:08:54 +00:00
{
2019-12-15 12:34:00 +00:00
soundEngine - > ChangeSoundPitch ( SOURCE_Unattached , nullptr , CHAN_AUTO , expitch , soundNum + 1 ) ;
2006-04-13 20:47:06 +00:00
}
else
{
2019-12-15 12:34:00 +00:00
soundEngine - > ChangeSoundPitch ( SOURCE_Actor , & sprite [ spriteNum ] , CHAN_AUTO , expitch , soundNum + 1 ) ;
2006-04-13 20:47:06 +00:00
}
}
2019-12-12 20:42:58 +00:00
//==========================================================================
//
//
//
//==========================================================================
2006-04-13 20:47:06 +00:00
2019-12-16 23:29:38 +00:00
int A_CheckSoundPlaying ( int spriteNum , int soundNum , int channel )
2006-04-16 03:42:36 +00:00
{
2019-12-15 12:34:00 +00:00
if ( spriteNum = = - 1 ) return soundEngine - > GetSoundPlayingInfo ( SOURCE_Any , nullptr , soundNum + 1 ) ;
2019-12-12 20:42:58 +00:00
if ( ( unsigned ) spriteNum > = MAXSPRITES ) return false ;
2019-12-16 23:29:38 +00:00
return soundEngine - > IsSourcePlayingSomething ( SOURCE_Actor , & sprite [ spriteNum ] , channel , soundNum + 1 ) ;
2006-04-16 03:42:36 +00:00
}
2013-01-02 22:33:32 +00:00
// Check if actor <i> is playing any sound.
2019-08-07 22:44:29 +00:00
int A_CheckAnySoundPlaying ( int spriteNum )
2013-01-02 22:33:32 +00:00
{
2019-12-12 20:42:58 +00:00
if ( ( unsigned ) spriteNum > = MAXSPRITES ) return false ;
return soundEngine - > IsSourcePlayingSomething ( SOURCE_Actor , & sprite [ spriteNum ] , CHAN_AUTO , 0 ) ;
2013-01-02 22:33:32 +00:00
}
2019-08-07 22:44:29 +00:00
int S_CheckSoundPlaying ( int soundNum )
2006-04-16 03:42:36 +00:00
{
2019-12-15 12:34:00 +00:00
return soundEngine - > GetSoundPlayingInfo ( SOURCE_Any , nullptr , soundNum + 1 ) ;
2006-04-16 03:42:36 +00:00
}
2019-12-12 17:43:27 +00:00
//==========================================================================
//
//
//
//==========================================================================
void S_MenuSound ( void )
{
static int SoundNum ;
int const menusnds [ ] = {
LASERTRIP_EXPLODE , DUKE_GRUNT , DUKE_LAND_HURT , CHAINGUN_FIRE , SQUISHED , KICK_HIT ,
PISTOL_RICOCHET , PISTOL_BODYHIT , PISTOL_FIRE , SHOTGUN_FIRE , BOS1_WALK , RPG_EXPLODE ,
PIPEBOMB_BOUNCE , PIPEBOMB_EXPLODE , NITEVISION_ONOFF , RPG_SHOOT , SELECT_WEAPON ,
} ;
int s = VM_OnEventWithReturn ( EVENT_OPENMENUSOUND , g_player [ screenpeek ] . ps - > i , screenpeek , FURY ? - 1 : menusnds [ SoundNum + + % ARRAY_SIZE ( menusnds ) ] ) ;
if ( s ! = - 1 )
S_PlaySound ( s ) ;
}
2019-12-12 20:42:58 +00:00
//==========================================================================
//
// Music
//
//==========================================================================
2019-12-12 17:43:27 +00:00
static void S_SetMusicIndex ( unsigned int m )
{
ud . music_episode = m / MAXLEVELS ;
ud . music_level = m % MAXLEVELS ;
}
void S_PlayLevelMusicOrNothing ( unsigned int m )
{
ud . returnvar [ 0 ] = m / MAXLEVELS ;
ud . returnvar [ 1 ] = m % MAXLEVELS ;
int retval = VM_OnEvent ( EVENT_PLAYLEVELMUSICSLOT , g_player [ myconnectindex ] . ps - > i , myconnectindex ) ;
if ( retval > = 0 )
{
auto & mr = m = = USERMAPMUSICFAKESLOT ? userMapRecord : mapList [ m ] ;
Mus_Play ( mr . labelName , mr . music , true ) ;
S_SetMusicIndex ( m ) ;
}
}
int S_TryPlaySpecialMusic ( unsigned int m )
{
auto & musicfn = mapList [ m ] . music ;
if ( musicfn . IsNotEmpty ( ) )
{
if ( ! Mus_Play ( nullptr , musicfn , true ) )
{
S_SetMusicIndex ( m ) ;
return 0 ;
}
}
return 1 ;
}
void S_PlaySpecialMusicOrNothing ( unsigned int m )
{
if ( S_TryPlaySpecialMusic ( m ) )
{
S_SetMusicIndex ( m ) ;
}
}
void S_ContinueLevelMusic ( void )
{
VM_OnEvent ( EVENT_CONTINUELEVELMUSICSLOT , g_player [ myconnectindex ] . ps - > i , myconnectindex ) ;
}
2019-09-21 20:53:00 +00:00
END_DUKE_NS