2014-03-15 16:59:03 +00:00
// SONIC ROBO BLAST 2
//-----------------------------------------------------------------------------
// Copyright (C) 1993-1996 by id Software, Inc.
// Copyright (C) 1998-2000 by DooM Legacy Team.
2016-07-06 04:09:17 +00:00
// Copyright (C) 1999-2016 by Sonic Team Junior.
2014-03-15 16:59:03 +00:00
//
// This program is free software distributed under the
// terms of the GNU General Public License, version 2.
// See the 'LICENSE' file for more details.
//-----------------------------------------------------------------------------
/// \file s_sound.c
/// \brief System-independent sound and music routines
# ifdef MUSSERV
# include <sys/msg.h>
struct musmsg
{
long msg_type ;
char msg_text [ 12 ] ;
} ;
extern INT32 msg_id ;
# endif
# include "doomdef.h"
# include "doomstat.h"
# include "command.h"
# include "g_game.h"
# include "m_argv.h"
# include "r_main.h" // R_PointToAngle2() used to calc stereo sep.
# include "r_things.h" // for skins
# include "i_system.h"
# include "i_sound.h"
# include "s_sound.h"
# include "w_wad.h"
# include "z_zone.h"
# include "d_main.h"
# include "r_sky.h" // skyflatnum
# include "p_local.h" // camera info
# ifdef HW3SOUND
// 3D Sound Interface
# include "hardware/hw3sound.h"
# else
static INT32 S_AdjustSoundParams ( const mobj_t * listener , const mobj_t * source , INT32 * vol , INT32 * sep , INT32 * pitch , sfxinfo_t * sfxinfo ) ;
# endif
CV_PossibleValue_t soundvolume_cons_t [ ] = { { 0 , " MIN " } , { 31 , " MAX " } , { 0 , NULL } } ;
static void SetChannelsNum ( void ) ;
// commands for music and sound servers
# ifdef MUSSERV
consvar_t musserver_cmd = { " musserver_cmd " , " musserver " , CV_SAVE , NULL , NULL , 0 , NULL , NULL , 0 , 0 , NULL } ;
consvar_t musserver_arg = { " musserver_arg " , " -t 20 -f -u 0 -i music.dta " , CV_SAVE , NULL , NULL , 0 , NULL , NULL , 0 , 0 , NULL } ;
# endif
# ifdef SNDSERV
consvar_t sndserver_cmd = { " sndserver_cmd " , " llsndserv " , CV_SAVE , NULL , 0 , NULL , NULL , 0 , 0 , NULL } ;
consvar_t sndserver_arg = { " sndserver_arg " , " -quiet " , CV_SAVE , NULL , 0 , NULL , NULL , 0 , 0 , NULL } ;
# endif
# if defined (_WINDOWS) && !defined (SURROUND) //&& defined (_X86_)
# define SURROUND
# endif
# if defined (_WIN32_WCE) || defined (DC) || defined(GP2X)
consvar_t cv_samplerate = { " samplerate " , " 11025 " , 0 , CV_Unsigned , NULL , 11025 , NULL , NULL , 0 , 0 , NULL } ; //Alam: For easy hacking?
# elif defined(_PSP) || defined(_WINDOWS)
consvar_t cv_samplerate = { " samplerate " , " 44100 " , 0 , CV_Unsigned , NULL , 44100 , NULL , NULL , 0 , 0 , NULL } ; //Alam: For easy hacking?
# elif defined(_WII)
consvar_t cv_samplerate = { " samplerate " , " 32000 " , 0 , CV_Unsigned , NULL , 32000 , NULL , NULL , 0 , 0 , NULL } ; //Alam: For easy hacking?
# else
consvar_t cv_samplerate = { " samplerate " , " 22050 " , 0 , CV_Unsigned , NULL , 22050 , NULL , NULL , 0 , 0 , NULL } ; //Alam: For easy hacking?
# endif
// stereo reverse
consvar_t stereoreverse = { " stereoreverse " , " Off " , CV_SAVE , CV_OnOff , NULL , 0 , NULL , NULL , 0 , 0 , NULL } ;
// if true, all sounds are loaded at game startup
static consvar_t precachesound = { " precachesound " , " Off " , CV_SAVE , CV_OnOff , NULL , 0 , NULL , NULL , 0 , 0 , NULL } ;
// actual general (maximum) sound & music volume, saved into the config
consvar_t cv_soundvolume = { " soundvolume " , " 31 " , CV_SAVE , soundvolume_cons_t , NULL , 0 , NULL , NULL , 0 , 0 , NULL } ;
consvar_t cv_digmusicvolume = { " digmusicvolume " , " 18 " , CV_SAVE , soundvolume_cons_t , NULL , 0 , NULL , NULL , 0 , 0 , NULL } ;
consvar_t cv_midimusicvolume = { " midimusicvolume " , " 18 " , CV_SAVE , soundvolume_cons_t , NULL , 0 , NULL , NULL , 0 , 0 , NULL } ;
// number of channels available
# if defined (_WIN32_WCE) || defined (DC) || defined (PSP) || defined(GP2X)
consvar_t cv_numChannels = { " snd_channels " , " 8 " , CV_SAVE | CV_CALL , CV_Unsigned , SetChannelsNum , 0 , NULL , NULL , 0 , 0 , NULL } ;
# else
consvar_t cv_numChannels = { " snd_channels " , " 32 " , CV_SAVE | CV_CALL , CV_Unsigned , SetChannelsNum , 0 , NULL , NULL , 0 , 0 , NULL } ;
# endif
static consvar_t surround = { " surround " , " Off " , CV_SAVE , CV_OnOff , NULL , 0 , NULL , NULL , 0 , 0 , NULL } ;
# define S_MAX_VOLUME 127
// when to clip out sounds
// Does not fit the large outdoor areas.
// added 2-2-98 in 8 bit volume control (before (1200*0x10000))
# define S_CLIPPING_DIST (1536*0x10000)
// Distance to origin when sounds should be maxed out.
// This should relate to movement clipping resolution
// (see BLOCKMAP handling).
// Originally: (200*0x10000).
// added 2-2-98 in 8 bit volume control (before (160*0x10000))
# define S_CLOSE_DIST (160*0x10000)
// added 2-2-98 in 8 bit volume control (before remove the +4)
# define S_ATTENUATOR ((S_CLIPPING_DIST-S_CLOSE_DIST)>>(FRACBITS+4))
// Adjustable by menu.
# define NORM_VOLUME snd_MaxVolume
# define NORM_PITCH 128
# define NORM_PRIORITY 64
# define NORM_SEP 128
# define S_PITCH_PERTURB 1
# define S_STEREO_SWING (96*0x10000)
# ifdef SURROUND
# define SURROUND_SEP -128
# endif
// percent attenuation from front to back
# define S_IFRACVOL 30
typedef struct
{
// sound information (if null, channel avail.)
sfxinfo_t * sfxinfo ;
// origin of sound
const void * origin ;
// handle of the sound being played
INT32 handle ;
} channel_t ;
// the set of channels available
static channel_t * channels = NULL ;
static INT32 numofchannels = 0 ;
//
// Internals.
//
static void S_StopChannel ( INT32 cnum ) ;
//
// S_getChannel
//
// If none available, return -1. Otherwise channel #.
//
static INT32 S_getChannel ( const void * origin , sfxinfo_t * sfxinfo )
{
// channel number to use
INT32 cnum ;
channel_t * c ;
// Find an open channel
for ( cnum = 0 ; cnum < numofchannels ; cnum + + )
{
if ( ! channels [ cnum ] . sfxinfo )
break ;
// Now checks if same sound is being played, rather
// than just one sound per mobj
else if ( sfxinfo = = channels [ cnum ] . sfxinfo & & ( sfxinfo - > pitch & SF_NOMULTIPLESOUND ) )
{
return - 1 ;
break ;
}
else if ( sfxinfo = = channels [ cnum ] . sfxinfo & & sfxinfo - > singularity = = true )
{
S_StopChannel ( cnum ) ;
break ;
}
else if ( origin & & channels [ cnum ] . origin = = origin & & channels [ cnum ] . sfxinfo = = sfxinfo )
{
if ( sfxinfo - > pitch & SF_NOINTERRUPT )
return - 1 ;
else
S_StopChannel ( cnum ) ;
break ;
}
2014-11-12 00:55:07 +00:00
else if ( origin & & channels [ cnum ] . origin = = origin
& & channels [ cnum ] . sfxinfo - > name ! = sfxinfo - > name
& & channels [ cnum ] . sfxinfo - > pitch = = SF_TOTALLYSINGLE & & sfxinfo - > pitch = = SF_TOTALLYSINGLE )
2014-03-15 16:59:03 +00:00
{
S_StopChannel ( cnum ) ;
break ;
}
}
// None available
if ( cnum = = numofchannels )
{
// Look for lower priority
for ( cnum = 0 ; cnum < numofchannels ; cnum + + )
if ( channels [ cnum ] . sfxinfo - > priority < = sfxinfo - > priority )
break ;
if ( cnum = = numofchannels )
{
// No lower priority. Sorry, Charlie.
return - 1 ;
}
else
{
// Otherwise, kick out lower priority.
S_StopChannel ( cnum ) ;
}
}
c = & channels [ cnum ] ;
// channel is decided to be cnum.
c - > sfxinfo = sfxinfo ;
c - > origin = origin ;
return cnum ;
}
void S_RegisterSoundStuff ( void )
{
if ( dedicated )
{
nosound = true ;
return ;
}
CV_RegisterVar ( & stereoreverse ) ;
CV_RegisterVar ( & precachesound ) ;
# ifdef SNDSERV
CV_RegisterVar ( & sndserver_cmd ) ;
CV_RegisterVar ( & sndserver_arg ) ;
# endif
# ifdef MUSSERV
CV_RegisterVar ( & musserver_cmd ) ;
CV_RegisterVar ( & musserver_arg ) ;
# endif
CV_RegisterVar ( & surround ) ;
CV_RegisterVar ( & cv_samplerate ) ;
2014-07-25 23:10:24 +00:00
# if defined (macintosh) && !defined (HAVE_SDL) // mp3 playlist stuff
2014-03-15 16:59:03 +00:00
{
INT32 i ;
for ( i = 0 ; i < PLAYLIST_LENGTH ; i + + )
{
user_songs [ i ] . name = malloc ( 7 ) ;
if ( ! user_songs [ i ] . name )
I_Error ( " No more free memory for mp3 playlist " ) ;
sprintf ( user_songs [ i ] . name , " song%d%d " , i / 10 , i % 10 ) ;
user_songs [ i ] . defaultvalue = malloc ( sizeof ( char ) ) ;
if ( user_songs [ i ] . defaultvalue )
I_Error ( " No more free memory for blank mp3 playerlist " ) ;
* user_songs [ i ] . defaultvalue = 0 ;
user_songs [ i ] . flags = CV_SAVE ;
user_songs [ i ] . PossibleValue = NULL ;
CV_RegisterVar ( & user_songs [ i ] ) ;
}
CV_RegisterVar ( & play_mode ) ;
}
# endif
}
static void SetChannelsNum ( void )
{
INT32 i ;
// Allocating the internal channels for mixing
// (the maximum number of sounds rendered
// simultaneously) within zone memory.
if ( channels )
S_StopSounds ( ) ;
Z_Free ( channels ) ;
channels = NULL ;
if ( cv_numChannels . value = = 999999999 ) //Alam_GBC: OH MY ROD!(ROD rimmiced with GOD!)
CV_StealthSet ( & cv_numChannels , cv_numChannels . defaultvalue ) ;
# ifdef HW3SOUND
if ( hws_mode ! = HWS_DEFAULT_MODE )
{
HW3S_SetSourcesNum ( ) ;
return ;
}
# endif
if ( cv_numChannels . value )
channels = ( channel_t * ) Z_Malloc ( cv_numChannels . value * sizeof ( channel_t ) , PU_STATIC , NULL ) ;
numofchannels = cv_numChannels . value ;
// Free all channels for use
for ( i = 0 ; i < numofchannels ; i + + )
channels [ i ] . sfxinfo = 0 ;
}
// Retrieve the lump number of sfx
//
lumpnum_t S_GetSfxLumpNum ( sfxinfo_t * sfx )
{
char namebuf [ 9 ] ;
lumpnum_t sfxlump ;
sprintf ( namebuf , " ds%s " , sfx - > name ) ;
sfxlump = W_CheckNumForName ( namebuf ) ;
if ( sfxlump ! = LUMPERROR )
return sfxlump ;
strlcpy ( namebuf , sfx - > name , sizeof namebuf ) ;
sfxlump = W_CheckNumForName ( namebuf ) ;
if ( sfxlump ! = LUMPERROR )
return sfxlump ;
return W_GetNumForName ( " dsthok " ) ;
}
// Stop all sounds, load level info, THEN start sounds.
void S_StopSounds ( void )
{
INT32 cnum ;
# ifdef HW3SOUND
if ( hws_mode ! = HWS_DEFAULT_MODE )
{
HW3S_StopSounds ( ) ;
return ;
}
# endif
// kill all playing sounds at start of level
for ( cnum = 0 ; cnum < numofchannels ; cnum + + )
if ( channels [ cnum ] . sfxinfo )
S_StopChannel ( cnum ) ;
}
void S_StopSoundByID ( void * origin , sfxenum_t sfx_id )
{
INT32 cnum ;
// Sounds without origin can have multiple sources, they shouldn't
// be stopped by new sounds.
if ( ! origin )
return ;
# ifdef HW3SOUND
if ( hws_mode ! = HWS_DEFAULT_MODE )
{
HW3S_StopSoundByID ( origin , sfx_id ) ;
return ;
}
# endif
for ( cnum = 0 ; cnum < numofchannels ; cnum + + )
{
if ( channels [ cnum ] . sfxinfo = = & S_sfx [ sfx_id ] & & channels [ cnum ] . origin = = origin )
{
S_StopChannel ( cnum ) ;
break ;
}
}
}
void S_StopSoundByNum ( sfxenum_t sfxnum )
{
INT32 cnum ;
# ifdef HW3SOUND
if ( hws_mode ! = HWS_DEFAULT_MODE )
{
HW3S_StopSoundByNum ( sfxnum ) ;
return ;
}
# endif
for ( cnum = 0 ; cnum < numofchannels ; cnum + + )
{
if ( channels [ cnum ] . sfxinfo = = & S_sfx [ sfxnum ] )
{
S_StopChannel ( cnum ) ;
break ;
}
}
}
void S_StartSoundAtVolume ( const void * origin_p , sfxenum_t sfx_id , INT32 volume )
{
INT32 sep , pitch , priority , cnum ;
sfxinfo_t * sfx ;
const mobj_t * origin = ( const mobj_t * ) origin_p ;
listener_t listener = { 0 , 0 , 0 , 0 } ;
listener_t listener2 = { 0 , 0 , 0 , 0 } ;
2017-12-17 03:32:43 +00:00
listener_t listener3 = { 0 , 0 , 0 , 0 } ;
listener_t listener4 = { 0 , 0 , 0 , 0 } ;
2014-03-15 16:59:03 +00:00
mobj_t * listenmobj = players [ displayplayer ] . mo ;
mobj_t * listenmobj2 = NULL ;
2017-12-17 03:32:43 +00:00
mobj_t * listenmobj3 = NULL ;
mobj_t * listenmobj4 = NULL ;
2014-03-15 16:59:03 +00:00
if ( sound_disabled | | ! sound_started | | nosound )
return ;
// Don't want a sound? Okay then...
if ( sfx_id = = sfx_None )
return ;
if ( players [ displayplayer ] . awayviewtics )
listenmobj = players [ displayplayer ] . awayviewmobj ;
2017-12-17 03:32:43 +00:00
if ( splitscreen | | splitscreen3 | | splitscreen4 )
2014-03-15 16:59:03 +00:00
{
listenmobj2 = players [ secondarydisplayplayer ] . mo ;
if ( players [ secondarydisplayplayer ] . awayviewtics )
listenmobj2 = players [ secondarydisplayplayer ] . awayviewmobj ;
}
2017-12-17 03:32:43 +00:00
if ( splitscreen3 | | splitscreen4 )
{
listenmobj3 = players [ thirddisplayplayer ] . mo ;
if ( players [ thirddisplayplayer ] . awayviewtics )
listenmobj3 = players [ thirddisplayplayer ] . awayviewmobj ;
}
if ( splitscreen4 )
{
listenmobj4 = players [ fourthdisplayplayer ] . mo ;
if ( players [ fourthdisplayplayer ] . awayviewtics )
listenmobj4 = players [ fourthdisplayplayer ] . awayviewmobj ;
}
2014-03-15 16:59:03 +00:00
# ifdef HW3SOUND
if ( hws_mode ! = HWS_DEFAULT_MODE )
{
HW3S_StartSound ( origin , sfx_id ) ;
return ;
} ;
# endif
if ( camera . chase & & ! players [ displayplayer ] . awayviewtics )
{
listener . x = camera . x ;
listener . y = camera . y ;
listener . z = camera . z ;
listener . angle = camera . angle ;
}
else if ( listenmobj )
{
listener . x = listenmobj - > x ;
listener . y = listenmobj - > y ;
listener . z = listenmobj - > z ;
listener . angle = listenmobj - > angle ;
}
else if ( origin )
return ;
if ( listenmobj2 )
{
if ( camera2 . chase & & ! players [ secondarydisplayplayer ] . awayviewtics )
{
listener2 . x = camera2 . x ;
listener2 . y = camera2 . y ;
listener2 . z = camera2 . z ;
listener2 . angle = camera2 . angle ;
}
else
{
listener2 . x = listenmobj2 - > x ;
listener2 . y = listenmobj2 - > y ;
listener2 . z = listenmobj2 - > z ;
listener2 . angle = listenmobj2 - > angle ;
}
}
2017-12-17 03:32:43 +00:00
if ( listenmobj3 )
{
if ( camera3 . chase & & ! players [ thirddisplayplayer ] . awayviewtics )
{
listener3 . x = camera3 . x ;
listener3 . y = camera3 . y ;
listener3 . z = camera3 . z ;
listener3 . angle = camera3 . angle ;
}
else
{
listener3 . x = listenmobj3 - > x ;
listener3 . y = listenmobj3 - > y ;
listener3 . z = listenmobj3 - > z ;
listener3 . angle = listenmobj3 - > angle ;
}
}
if ( listenmobj4 )
{
if ( camera4 . chase & & ! players [ fourthdisplayplayer ] . awayviewtics )
{
listener4 . x = camera4 . x ;
listener4 . y = camera4 . y ;
listener4 . z = camera4 . z ;
listener4 . angle = camera4 . angle ;
}
else
{
listener4 . x = listenmobj4 - > x ;
listener4 . y = listenmobj4 - > y ;
listener4 . z = listenmobj4 - > z ;
listener4 . angle = listenmobj4 - > angle ;
}
}
2014-03-15 16:59:03 +00:00
// check for bogus sound #
I_Assert ( sfx_id > = 1 ) ;
I_Assert ( sfx_id < NUMSFX ) ;
sfx = & S_sfx [ sfx_id ] ;
if ( sfx - > skinsound ! = - 1 & & origin & & origin - > skin )
{
// redirect player sound to the sound in the skin table
sfx_id = ( ( skin_t * ) origin - > skin ) - > soundsid [ sfx - > skinsound ] ;
sfx = & S_sfx [ sfx_id ] ;
}
// Initialize sound parameters
pitch = NORM_PITCH ;
priority = NORM_PRIORITY ;
2017-12-17 03:32:43 +00:00
if ( ( splitscreen | | splitscreen3 | | splitscreen4 ) & & listenmobj2 ) // Copy the sound for the split player
2014-03-15 16:59:03 +00:00
{
// Check to see if it is audible, and if not, modify the params
if ( origin & & origin ! = listenmobj2 )
{
INT32 rc ;
rc = S_AdjustSoundParams ( listenmobj2 , origin , & volume , & sep , & pitch , sfx ) ;
if ( ! rc )
goto dontplay ; // Maybe the other player can hear it...
if ( origin - > x = = listener2 . x & & origin - > y = = listener2 . y )
sep = NORM_SEP ;
}
else if ( ! origin )
// Do not play origin-less sounds for the second player.
// The first player will be able to hear it just fine,
// we really don't want it playing twice.
goto dontplay ;
else
sep = NORM_SEP ;
// try to find a channel
cnum = S_getChannel ( origin , sfx ) ;
if ( cnum < 0 )
return ; // If there's no free channels, it's not gonna be free for player 1, either.
// This is supposed to handle the loading/caching.
// For some odd reason, the caching is done nearly
// each time the sound is needed?
// cache data if necessary
// NOTE: set sfx->data NULL sfx->lump -1 to force a reload
if ( ! sfx - > data )
sfx - > data = I_GetSfx ( sfx ) ;
// increase the usefulness
if ( sfx - > usefulness + + < 0 )
sfx - > usefulness = - 1 ;
2017-12-17 03:32:43 +00:00
# ifdef SURROUND
// Avoid channel reverse if surround
if ( stereoreverse . value & & sep ! = SURROUND_SEP )
sep = ( ~ sep ) & 255 ;
# else
if ( stereoreverse . value )
sep = ( ~ sep ) & 255 ;
# endif
// Assigns the handle to one of the channels in the
// mix/output buffer.
channels [ cnum ] . handle = I_StartSound ( sfx_id , volume , sep , pitch , priority ) ;
}
if ( ( splitscreen3 | | splitscreen4 ) & & listenmobj3 ) // Copy the sound for the third player
{
// Check to see if it is audible, and if not, modify the params
if ( origin & & origin ! = listenmobj3 )
{
INT32 rc ;
rc = S_AdjustSoundParams ( listenmobj3 , origin , & volume , & sep , & pitch , sfx ) ;
if ( ! rc )
goto dontplay ; // Maybe the other player can hear it...
if ( origin - > x = = listener3 . x & & origin - > y = = listener3 . y )
sep = NORM_SEP ;
}
else if ( ! origin )
// Do not play origin-less sounds for the second player.
// The first player will be able to hear it just fine,
// we really don't want it playing twice.
goto dontplay ;
else
sep = NORM_SEP ;
// try to find a channel
cnum = S_getChannel ( origin , sfx ) ;
if ( cnum < 0 )
return ; // If there's no free channels, it's not gonna be free for player 1, either.
// This is supposed to handle the loading/caching.
// For some odd reason, the caching is done nearly
// each time the sound is needed?
// cache data if necessary
// NOTE: set sfx->data NULL sfx->lump -1 to force a reload
if ( ! sfx - > data )
sfx - > data = I_GetSfx ( sfx ) ;
// increase the usefulness
if ( sfx - > usefulness + + < 0 )
sfx - > usefulness = - 1 ;
# ifdef SURROUND
// Avoid channel reverse if surround
if ( stereoreverse . value & & sep ! = SURROUND_SEP )
sep = ( ~ sep ) & 255 ;
# else
if ( stereoreverse . value )
sep = ( ~ sep ) & 255 ;
# endif
// Assigns the handle to one of the channels in the
// mix/output buffer.
channels [ cnum ] . handle = I_StartSound ( sfx_id , volume , sep , pitch , priority ) ;
}
if ( splitscreen4 & & listenmobj4 ) // Copy the sound for the split player
{
// Check to see if it is audible, and if not, modify the params
if ( origin & & origin ! = listenmobj4 )
{
INT32 rc ;
rc = S_AdjustSoundParams ( listenmobj4 , origin , & volume , & sep , & pitch , sfx ) ;
if ( ! rc )
goto dontplay ; // Maybe the other player can hear it...
if ( origin - > x = = listener4 . x & & origin - > y = = listener4 . y )
sep = NORM_SEP ;
}
else if ( ! origin )
// Do not play origin-less sounds for the second player.
// The first player will be able to hear it just fine,
// we really don't want it playing twice.
goto dontplay ;
else
sep = NORM_SEP ;
// try to find a channel
cnum = S_getChannel ( origin , sfx ) ;
if ( cnum < 0 )
return ; // If there's no free channels, it's not gonna be free for player 1, either.
// This is supposed to handle the loading/caching.
// For some odd reason, the caching is done nearly
// each time the sound is needed?
// cache data if necessary
// NOTE: set sfx->data NULL sfx->lump -1 to force a reload
if ( ! sfx - > data )
sfx - > data = I_GetSfx ( sfx ) ;
// increase the usefulness
if ( sfx - > usefulness + + < 0 )
sfx - > usefulness = - 1 ;
2014-03-15 16:59:03 +00:00
# ifdef SURROUND
// Avoid channel reverse if surround
if ( stereoreverse . value & & sep ! = SURROUND_SEP )
sep = ( ~ sep ) & 255 ;
# else
if ( stereoreverse . value )
sep = ( ~ sep ) & 255 ;
# endif
// Assigns the handle to one of the channels in the
// mix/output buffer.
channels [ cnum ] . handle = I_StartSound ( sfx_id , volume , sep , pitch , priority ) ;
}
dontplay :
// Check to see if it is audible, and if not, modify the params
if ( origin & & origin ! = listenmobj )
{
INT32 rc ;
rc = S_AdjustSoundParams ( listenmobj , origin , & volume , & sep , & pitch , sfx ) ;
if ( ! rc )
return ;
if ( origin - > x = = listener . x & & origin - > y = = listener . y )
sep = NORM_SEP ;
}
else
sep = NORM_SEP ;
// try to find a channel
cnum = S_getChannel ( origin , sfx ) ;
if ( cnum < 0 )
return ;
// This is supposed to handle the loading/caching.
// For some odd reason, the caching is done nearly
// each time the sound is needed?
// cache data if necessary
// NOTE: set sfx->data NULL sfx->lump -1 to force a reload
if ( ! sfx - > data )
sfx - > data = I_GetSfx ( sfx ) ;
// increase the usefulness
if ( sfx - > usefulness + + < 0 )
sfx - > usefulness = - 1 ;
# ifdef SURROUND
// Avoid channel reverse if surround
if ( stereoreverse . value & & sep ! = SURROUND_SEP )
sep = ( ~ sep ) & 255 ;
# else
if ( stereoreverse . value )
sep = ( ~ sep ) & 255 ;
# endif
// Assigns the handle to one of the channels in the
// mix/output buffer.
channels [ cnum ] . handle = I_StartSound ( sfx_id , volume , sep , pitch , priority ) ;
}
void S_StartSound ( const void * origin , sfxenum_t sfx_id )
{
if ( sound_disabled )
return ;
2016-08-21 21:55:35 +00:00
if ( true ) // Sounds change in Mario mode! // SRB2kart - every sound is mario.
2014-03-15 16:59:03 +00:00
{
switch ( sfx_id )
{
// case sfx_altow1:
// case sfx_altow2:
// case sfx_altow3:
// case sfx_altow4:
// sfx_id = sfx_mario8;
// break;
case sfx_thok :
sfx_id = sfx_mario7 ;
break ;
case sfx_pop :
2016-11-21 04:23:00 +00:00
sfx_id = sfx_mkitem ; // SRB2kart
2014-03-15 16:59:03 +00:00
break ;
case sfx_jump :
sfx_id = sfx_mario6 ;
break ;
2016-11-21 04:23:00 +00:00
// case sfx_shield:
// sfx_id = sfx_mario3;
// break;
2014-03-15 16:59:03 +00:00
case sfx_itemup :
2016-11-21 04:23:00 +00:00
sfx_id = sfx_None ;
break ;
case sfx_tink :
sfx_id = sfx_mario1 ;
2014-03-15 16:59:03 +00:00
break ;
// case sfx_cgot:
// sfx_id = sfx_mario9;
// break;
2016-11-21 04:23:00 +00:00
case sfx_lose :
sfx_id = sfx_mario2 ;
break ;
case sfx_prloop :
sfx_id = sfx_bomb2 ;
break ;
2014-03-15 16:59:03 +00:00
default :
break ;
}
}
if ( maptol & TOL_XMAS ) // Some sounds change for xmas
{
switch ( sfx_id )
{
case sfx_ideya :
case sfx_nbmper :
case sfx_ncitem :
case sfx_ngdone :
+ + sfx_id ;
default :
break ;
}
}
// the volume is handled 8 bits
# ifdef HW3SOUND
if ( hws_mode ! = HWS_DEFAULT_MODE )
HW3S_StartSound ( origin , sfx_id ) ;
else
# endif
S_StartSoundAtVolume ( origin , sfx_id , 255 ) ;
}
void S_StopSound ( void * origin )
{
INT32 cnum ;
// Sounds without origin can have multiple sources, they shouldn't
// be stopped by new sounds.
if ( ! origin )
return ;
# ifdef HW3SOUND
if ( hws_mode ! = HWS_DEFAULT_MODE )
{
HW3S_StopSound ( origin ) ;
return ;
}
# endif
for ( cnum = 0 ; cnum < numofchannels ; cnum + + )
{
if ( channels [ cnum ] . sfxinfo & & channels [ cnum ] . origin = = origin )
{
S_StopChannel ( cnum ) ;
break ;
}
}
}
//
// Updates music & sounds
//
static INT32 actualsfxvolume ; // check for change through console
static INT32 actualdigmusicvolume ;
static INT32 actualmidimusicvolume ;
void S_UpdateSounds ( void )
{
INT32 audible , cnum , volume , sep , pitch ;
channel_t * c ;
listener_t listener ;
listener_t listener2 ;
2017-12-17 03:32:43 +00:00
listener_t listener3 ;
listener_t listener4 ;
2014-03-15 16:59:03 +00:00
mobj_t * listenmobj = players [ displayplayer ] . mo ;
mobj_t * listenmobj2 = NULL ;
2017-12-17 03:32:43 +00:00
mobj_t * listenmobj3 = NULL ;
mobj_t * listenmobj4 = NULL ;
2014-03-15 16:59:03 +00:00
memset ( & listener , 0 , sizeof ( listener_t ) ) ;
memset ( & listener2 , 0 , sizeof ( listener_t ) ) ;
2017-12-17 03:32:43 +00:00
memset ( & listener3 , 0 , sizeof ( listener_t ) ) ;
memset ( & listener4 , 0 , sizeof ( listener_t ) ) ;
2014-03-15 16:59:03 +00:00
// Update sound/music volumes, if changed manually at console
if ( actualsfxvolume ! = cv_soundvolume . value )
S_SetSfxVolume ( cv_soundvolume . value ) ;
if ( actualdigmusicvolume ! = cv_digmusicvolume . value )
S_SetDigMusicVolume ( cv_digmusicvolume . value ) ;
if ( actualmidimusicvolume ! = cv_midimusicvolume . value )
S_SetMIDIMusicVolume ( cv_midimusicvolume . value ) ;
// We're done now, if we're not in a level.
if ( gamestate ! = GS_LEVEL )
{
# ifndef NOMUMBLE
// Stop Mumble cutting out. I'm sick of it.
I_UpdateMumble ( NULL , listener ) ;
# endif
// Stop cutting FMOD out. WE'RE sick of it.
I_UpdateSound ( ) ;
return ;
}
if ( dedicated | | nosound )
return ;
if ( players [ displayplayer ] . awayviewtics )
listenmobj = players [ displayplayer ] . awayviewmobj ;
2017-12-17 03:32:43 +00:00
if ( splitscreen | | splitscreen3 | | splitscreen4 )
2014-03-15 16:59:03 +00:00
{
listenmobj2 = players [ secondarydisplayplayer ] . mo ;
if ( players [ secondarydisplayplayer ] . awayviewtics )
listenmobj2 = players [ secondarydisplayplayer ] . awayviewmobj ;
}
2017-12-17 03:32:43 +00:00
if ( splitscreen3 | | splitscreen4 )
{
listenmobj3 = players [ thirddisplayplayer ] . mo ;
if ( players [ thirddisplayplayer ] . awayviewtics )
listenmobj3 = players [ thirddisplayplayer ] . awayviewmobj ;
}
if ( splitscreen4 )
{
listenmobj4 = players [ fourthdisplayplayer ] . mo ;
if ( players [ fourthdisplayplayer ] . awayviewtics )
listenmobj4 = players [ fourthdisplayplayer ] . awayviewmobj ;
}
2014-03-15 16:59:03 +00:00
if ( camera . chase & & ! players [ displayplayer ] . awayviewtics )
{
listener . x = camera . x ;
listener . y = camera . y ;
listener . z = camera . z ;
listener . angle = camera . angle ;
}
else if ( listenmobj )
{
listener . x = listenmobj - > x ;
listener . y = listenmobj - > y ;
listener . z = listenmobj - > z ;
listener . angle = listenmobj - > angle ;
}
# ifndef NOMUMBLE
I_UpdateMumble ( players [ consoleplayer ] . mo , listener ) ;
# endif
# ifdef HW3SOUND
if ( hws_mode ! = HWS_DEFAULT_MODE )
{
HW3S_UpdateSources ( ) ;
I_UpdateSound ( ) ;
return ;
}
# endif
if ( listenmobj2 )
{
if ( camera2 . chase & & ! players [ secondarydisplayplayer ] . awayviewtics )
{
listener2 . x = camera2 . x ;
listener2 . y = camera2 . y ;
listener2 . z = camera2 . z ;
listener2 . angle = camera2 . angle ;
}
else
{
listener2 . x = listenmobj2 - > x ;
listener2 . y = listenmobj2 - > y ;
listener2 . z = listenmobj2 - > z ;
listener2 . angle = listenmobj2 - > angle ;
}
}
2017-12-17 03:32:43 +00:00
if ( listenmobj3 )
{
if ( camera3 . chase & & ! players [ thirddisplayplayer ] . awayviewtics )
{
listener3 . x = camera3 . x ;
listener3 . y = camera3 . y ;
listener3 . z = camera3 . z ;
listener3 . angle = camera3 . angle ;
}
else
{
listener3 . x = listenmobj3 - > x ;
listener3 . y = listenmobj3 - > y ;
listener3 . z = listenmobj3 - > z ;
listener3 . angle = listenmobj3 - > angle ;
}
}
if ( listenmobj4 )
{
if ( camera4 . chase & & ! players [ fourthdisplayplayer ] . awayviewtics )
{
listener4 . x = camera4 . x ;
listener4 . y = camera4 . y ;
listener4 . z = camera4 . z ;
listener4 . angle = camera4 . angle ;
}
else
{
listener4 . x = listenmobj4 - > x ;
listener4 . y = listenmobj4 - > y ;
listener4 . z = listenmobj4 - > z ;
listener4 . angle = listenmobj4 - > angle ;
}
}
2014-03-15 16:59:03 +00:00
for ( cnum = 0 ; cnum < numofchannels ; cnum + + )
{
c = & channels [ cnum ] ;
if ( c - > sfxinfo )
{
if ( I_SoundIsPlaying ( c - > handle ) )
{
// initialize parameters
volume = 255 ; // 8 bits internal volume precision
pitch = NORM_PITCH ;
sep = NORM_SEP ;
// check non-local sounds for distance clipping
// or modify their params
2017-12-17 03:32:43 +00:00
if ( c - > origin & & ( ( c - > origin ! = players [ consoleplayer ] . mo )
| | ( ( splitscreen | | splitscreen3 | | splitscreen4 ) & & c - > origin ! = players [ secondarydisplayplayer ] . mo )
| | ( ( splitscreen3 | | splitscreen4 ) & & c - > origin ! = players [ thirddisplayplayer ] . mo )
| | ( splitscreen4 & & c - > origin ! = players [ fourthdisplayplayer ] . mo ) ) )
2014-03-15 16:59:03 +00:00
{
// Whomever is closer gets the sound, but only in splitscreen.
2017-12-17 03:32:43 +00:00
if ( listenmobj & & listenmobj2 & & ( splitscreen | | splitscreen3 | | splitscreen4 ) )
2014-03-15 16:59:03 +00:00
{
const mobj_t * soundmobj = c - > origin ;
fixed_t dist1 , dist2 ;
dist1 = P_AproxDistance ( listener . x - soundmobj - > x , listener . y - soundmobj - > y ) ;
dist2 = P_AproxDistance ( listener2 . x - soundmobj - > x , listener2 . y - soundmobj - > y ) ;
if ( dist1 < = dist2 )
{
// Player 1 gets the sound
audible = S_AdjustSoundParams ( listenmobj , c - > origin , & volume , & sep , & pitch ,
c - > sfxinfo ) ;
}
else
{
// Player 2 gets the sound
audible = S_AdjustSoundParams ( listenmobj2 , c - > origin , & volume , & sep , & pitch ,
c - > sfxinfo ) ;
}
if ( audible )
I_UpdateSoundParams ( c - > handle , volume , sep , pitch ) ;
else
S_StopChannel ( cnum ) ;
}
2017-12-17 03:32:43 +00:00
else if ( listenmobj & & listenmobj3 & & ( splitscreen3 | | splitscreen4 ) ) // TODO: make 3/4P compare their distances with all players, not just the first player and themselves V:
{
const mobj_t * soundmobj = c - > origin ;
fixed_t dist1 , dist2 ;
dist1 = P_AproxDistance ( listener . x - soundmobj - > x , listener . y - soundmobj - > y ) ;
dist2 = P_AproxDistance ( listener3 . x - soundmobj - > x , listener3 . y - soundmobj - > y ) ;
if ( dist1 < = dist2 )
{
// Player 1 gets the sound
audible = S_AdjustSoundParams ( listenmobj , c - > origin , & volume , & sep , & pitch ,
c - > sfxinfo ) ;
}
else
{
// Player 3 gets the sound
audible = S_AdjustSoundParams ( listenmobj3 , c - > origin , & volume , & sep , & pitch ,
c - > sfxinfo ) ;
}
if ( audible )
I_UpdateSoundParams ( c - > handle , volume , sep , pitch ) ;
else
S_StopChannel ( cnum ) ;
}
else if ( listenmobj & & listenmobj4 & & splitscreen4 )
{
const mobj_t * soundmobj = c - > origin ;
fixed_t dist1 , dist2 ;
dist1 = P_AproxDistance ( listener . x - soundmobj - > x , listener . y - soundmobj - > y ) ;
dist2 = P_AproxDistance ( listener4 . x - soundmobj - > x , listener4 . y - soundmobj - > y ) ;
if ( dist1 < = dist2 )
{
// Player 1 gets the sound
audible = S_AdjustSoundParams ( listenmobj , c - > origin , & volume , & sep , & pitch ,
c - > sfxinfo ) ;
}
else
{
// Player 4 gets the sound
audible = S_AdjustSoundParams ( listenmobj4 , c - > origin , & volume , & sep , & pitch ,
c - > sfxinfo ) ;
}
if ( audible )
I_UpdateSoundParams ( c - > handle , volume , sep , pitch ) ;
else
S_StopChannel ( cnum ) ;
}
else if ( listenmobj & & ! ( splitscreen | | splitscreen3 | | splitscreen4 ) )
2014-03-15 16:59:03 +00:00
{
// In the case of a single player, he or she always should get updated sound.
audible = S_AdjustSoundParams ( listenmobj , c - > origin , & volume , & sep , & pitch ,
c - > sfxinfo ) ;
if ( audible )
I_UpdateSoundParams ( c - > handle , volume , sep , pitch ) ;
else
S_StopChannel ( cnum ) ;
}
}
}
else
{
// if channel is allocated but sound has stopped, free it
S_StopChannel ( cnum ) ;
}
}
}
I_UpdateSound ( ) ;
}
void S_SetSfxVolume ( INT32 volume )
{
if ( volume < 0 | | volume > 31 )
CONS_Alert ( CONS_WARNING , " sfxvolume should be between 0-31 \n " ) ;
CV_SetValue ( & cv_soundvolume , volume & 0x1F ) ;
actualsfxvolume = cv_soundvolume . value ; // check for change of var
# ifdef HW3SOUND
hws_mode = = HWS_DEFAULT_MODE ? I_SetSfxVolume ( volume & 0x1F ) : HW3S_SetSfxVolume ( volume & 0x1F ) ;
# else
// now hardware volume
I_SetSfxVolume ( volume & 0x1F ) ;
# endif
}
void S_ClearSfx ( void )
{
# ifndef DJGPPDOS
size_t i ;
for ( i = 1 ; i < NUMSFX ; i + + )
I_FreeSfx ( S_sfx + i ) ;
# endif
}
static void S_StopChannel ( INT32 cnum )
{
INT32 i ;
channel_t * c = & channels [ cnum ] ;
if ( c - > sfxinfo )
{
// stop the sound playing
if ( I_SoundIsPlaying ( c - > handle ) )
I_StopSound ( c - > handle ) ;
// check to see
// if other channels are playing the sound
for ( i = 0 ; i < numofchannels ; i + + )
if ( cnum ! = i & & c - > sfxinfo = = channels [ i ] . sfxinfo )
break ;
// degrade usefulness of sound data
c - > sfxinfo - > usefulness - - ;
c - > sfxinfo = 0 ;
}
}
//
// S_CalculateSoundDistance
//
// Calculates the distance between two points for a sound.
// Clips the distance to prevent overflow.
//
fixed_t S_CalculateSoundDistance ( fixed_t sx1 , fixed_t sy1 , fixed_t sz1 , fixed_t sx2 , fixed_t sy2 , fixed_t sz2 )
{
fixed_t approx_dist , adx , ady ;
// calculate the distance to sound origin and clip it if necessary
adx = abs ( ( sx1 > > FRACBITS ) - ( sx2 > > FRACBITS ) ) ;
ady = abs ( ( sy1 > > FRACBITS ) - ( sy2 > > FRACBITS ) ) ;
// From _GG1_ p.428. Approx. euclidian distance fast.
// Take Z into account
adx = adx + ady - ( ( adx < ady ? adx : ady ) > > 1 ) ;
ady = abs ( ( sz1 > > FRACBITS ) - ( sz2 > > FRACBITS ) ) ;
approx_dist = adx + ady - ( ( adx < ady ? adx : ady ) > > 1 ) ;
if ( approx_dist > = FRACUNIT / 2 )
approx_dist = FRACUNIT / 2 - 1 ;
approx_dist < < = FRACBITS ;
return approx_dist ;
}
//
// Changes volume, stereo-separation, and pitch variables
// from the norm of a sound effect to be played.
// If the sound is not audible, returns a 0.
// Otherwise, modifies parameters and returns 1.
//
INT32 S_AdjustSoundParams ( const mobj_t * listener , const mobj_t * source , INT32 * vol , INT32 * sep , INT32 * pitch ,
sfxinfo_t * sfxinfo )
{
fixed_t approx_dist ;
angle_t angle ;
listener_t listensource ;
( void ) pitch ;
if ( ! listener )
return false ;
if ( listener = = players [ displayplayer ] . mo & & camera . chase )
{
listensource . x = camera . x ;
listensource . y = camera . y ;
listensource . z = camera . z ;
listensource . angle = camera . angle ;
}
2017-12-17 03:32:43 +00:00
else if ( ( splitscreen | | splitscreen3 | | splitscreen4 ) & & listener = = players [ secondarydisplayplayer ] . mo & & camera2 . chase )
2014-03-15 16:59:03 +00:00
{
listensource . x = camera2 . x ;
listensource . y = camera2 . y ;
listensource . z = camera2 . z ;
listensource . angle = camera2 . angle ;
}
2017-12-17 03:32:43 +00:00
else if ( ( splitscreen3 | | splitscreen4 ) & & listener = = players [ thirddisplayplayer ] . mo & & camera3 . chase )
{
listensource . x = camera3 . x ;
listensource . y = camera3 . y ;
listensource . z = camera3 . z ;
listensource . angle = camera3 . angle ;
}
else if ( splitscreen4 & & listener = = players [ fourthdisplayplayer ] . mo & & camera4 . chase )
{
listensource . x = camera4 . x ;
listensource . y = camera4 . y ;
listensource . z = camera4 . z ;
listensource . angle = camera4 . angle ;
}
2014-03-15 16:59:03 +00:00
else
{
listensource . x = listener - > x ;
listensource . y = listener - > y ;
listensource . z = listener - > z ;
listensource . angle = listener - > angle ;
}
if ( sfxinfo - > pitch & SF_OUTSIDESOUND ) // Rain special case
{
fixed_t x , y , yl , yh , xl , xh , newdist ;
if ( R_PointInSubsector ( listensource . x , listensource . y ) - > sector - > ceilingpic = = skyflatnum )
approx_dist = 0 ;
else
{
// Essentially check in a 1024 unit radius of the player for an outdoor area.
yl = listensource . y - 1024 * FRACUNIT ;
yh = listensource . y + 1024 * FRACUNIT ;
xl = listensource . x - 1024 * FRACUNIT ;
xh = listensource . x + 1024 * FRACUNIT ;
approx_dist = 1024 * FRACUNIT ;
for ( y = yl ; y < = yh ; y + = FRACUNIT * 64 )
for ( x = xl ; x < = xh ; x + = FRACUNIT * 64 )
{
if ( R_PointInSubsector ( x , y ) - > sector - > ceilingpic = = skyflatnum )
{
// Found the outdoors!
newdist = S_CalculateSoundDistance ( listensource . x , listensource . y , 0 , x , y , 0 ) ;
if ( newdist < approx_dist )
{
approx_dist = newdist ;
}
}
}
}
}
else
{
approx_dist = S_CalculateSoundDistance ( listensource . x , listensource . y , listensource . z ,
source - > x , source - > y , source - > z ) ;
}
// Ring loss, deaths, etc, should all be heard louder.
if ( sfxinfo - > pitch & SF_X8AWAYSOUND )
approx_dist = FixedDiv ( approx_dist , 8 * FRACUNIT ) ;
// Combine 8XAWAYSOUND with 4XAWAYSOUND and get.... 32XAWAYSOUND?
if ( sfxinfo - > pitch & SF_X4AWAYSOUND )
approx_dist = FixedDiv ( approx_dist , 4 * FRACUNIT ) ;
if ( sfxinfo - > pitch & SF_X2AWAYSOUND )
approx_dist = FixedDiv ( approx_dist , 2 * FRACUNIT ) ;
if ( approx_dist > S_CLIPPING_DIST )
return 0 ;
// angle of source to listener
angle = R_PointToAngle2 ( listensource . x , listensource . y , source - > x , source - > y ) ;
if ( angle > listensource . angle )
angle = angle - listensource . angle ;
else
angle = angle + InvAngle ( listensource . angle ) ;
# ifdef SURROUND
// Produce a surround sound for angle from 105 till 255
if ( surround . value = = 1 & & ( angle > ANG105 & & angle < ANG255 ) )
* sep = SURROUND_SEP ;
else
# endif
{
angle > > = ANGLETOFINESHIFT ;
// stereo separation
* sep = 128 - ( FixedMul ( S_STEREO_SWING , FINESINE ( angle ) ) > > FRACBITS ) ;
}
// volume calculation
if ( approx_dist < S_CLOSE_DIST )
{
// SfxVolume is now hardware volume
* vol = 255 ; // not snd_SfxVolume
}
else
{
// distance effect
* vol = ( 15 * ( ( S_CLIPPING_DIST - approx_dist ) > > FRACBITS ) ) / S_ATTENUATOR ;
}
return ( * vol > 0 ) ;
}
// Searches through the channels and checks if a sound is playing
// on the given origin.
INT32 S_OriginPlaying ( void * origin )
{
INT32 cnum ;
if ( ! origin )
return false ;
# ifdef HW3SOUND
if ( hws_mode ! = HWS_DEFAULT_MODE )
return HW3S_OriginPlaying ( origin ) ;
# endif
for ( cnum = 0 ; cnum < numofchannels ; cnum + + )
if ( channels [ cnum ] . origin = = origin )
return 1 ;
return 0 ;
}
// Searches through the channels and checks if a given id
// is playing anywhere.
INT32 S_IdPlaying ( sfxenum_t id )
{
INT32 cnum ;
# ifdef HW3SOUND
if ( hws_mode ! = HWS_DEFAULT_MODE )
return HW3S_IdPlaying ( id ) ;
# endif
for ( cnum = 0 ; cnum < numofchannels ; cnum + + )
if ( ( size_t ) ( channels [ cnum ] . sfxinfo - S_sfx ) = = ( size_t ) id )
return 1 ;
return 0 ;
}
// Searches through the channels and checks for
// origin x playing sound id y.
INT32 S_SoundPlaying ( void * origin , sfxenum_t id )
{
INT32 cnum ;
if ( ! origin )
return 0 ;
# ifdef HW3SOUND
if ( hws_mode ! = HWS_DEFAULT_MODE )
return HW3S_SoundPlaying ( origin , id ) ;
# endif
for ( cnum = 0 ; cnum < numofchannels ; cnum + + )
{
if ( channels [ cnum ] . origin = = origin
& & ( size_t ) ( channels [ cnum ] . sfxinfo - S_sfx ) = = ( size_t ) id )
return 1 ;
}
return 0 ;
}
//
// S_StartSoundName
// Starts a sound using the given name.
# define MAXNEWSOUNDS 10
static sfxenum_t newsounds [ MAXNEWSOUNDS ] = { 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 } ;
void S_StartSoundName ( void * mo , const char * soundname )
{
INT32 i , soundnum = 0 ;
// Search existing sounds...
for ( i = sfx_None + 1 ; i < NUMSFX ; i + + )
{
if ( ! S_sfx [ i ] . name )
continue ;
if ( ! stricmp ( S_sfx [ i ] . name , soundname ) )
{
soundnum = i ;
break ;
}
}
if ( ! soundnum )
{
for ( i = 0 ; i < MAXNEWSOUNDS ; i + + )
{
if ( newsounds [ i ] = = 0 )
break ;
if ( ! S_IdPlaying ( newsounds [ i ] ) )
{
S_RemoveSoundFx ( newsounds [ i ] ) ;
break ;
}
}
if ( i = = MAXNEWSOUNDS )
{
CONS_Debug ( DBG_GAMELOGIC , " Cannot load another extra sound! \n " ) ;
return ;
}
2014-03-18 17:56:54 +00:00
soundnum = S_AddSoundFx ( soundname , false , 0 , false ) ;
2014-03-15 16:59:03 +00:00
newsounds [ i ] = soundnum ;
}
S_StartSound ( mo , soundnum ) ;
}
2016-07-06 04:09:17 +00:00
/// ------------------------
/// Music
/// ------------------------
# ifdef MUSICSLOT_COMPATIBILITY
2017-02-07 22:19:04 +00:00
const char * compat_special_music_slots [ 21 ] =
2016-07-06 04:09:17 +00:00
{
" titles " , // 1036 title screen
" read_m " , // 1037 intro
" lclear " , // 1038 level clear
" invinc " , // 1039 invincibility
" shoes " , // 1040 super sneakers
" minvnc " , // 1041 Mario invincibility
" drown " , // 1042 drowning
" gmover " , // 1043 game over
" xtlife " , // 1044 extra life
" contsc " , // 1045 continue screen
" supers " , // 1046 Super Sonic
" chrsel " , // 1047 character select
" credit " , // 1048 credits
" racent " , // 1049 Race Results
" stjr " , // 1050 Sonic Team Jr. Presents
2017-02-07 22:19:04 +00:00
// SRB2kart 040217
" finlap " , // 1051 Sonic Team Jr. Presents
" karwin " , // 1052 Sonic Team Jr. Presents
" karok " , // 1053 Sonic Team Jr. Presents
" karlos " , // 1054 Sonic Team Jr. Presents
" mega " , // 1055 Sonic Team Jr. Presents
2016-07-06 04:09:17 +00:00
" "
} ;
# endif
# define music_playing (music_name[0]) // String is empty if no music is playing
static char music_name [ 7 ] ; // up to 6-character name
static lumpnum_t music_lumpnum ; // lump number of music (used??)
static void * music_data ; // music raw data
static INT32 music_handle ; // once registered, the handle for the music
static boolean mus_paused = 0 ; // whether songs are mus_paused
static boolean S_MIDIMusic ( const char * mname , boolean looping )
{
lumpnum_t mlumpnum ;
void * mdata ;
INT32 mhandle ;
if ( nomidimusic | | music_disabled )
return false ; // didn't search.
if ( W_CheckNumForName ( va ( " d_%s " , mname ) ) = = LUMPERROR )
return false ;
mlumpnum = W_GetNumForName ( va ( " d_%s " , mname ) ) ;
// load & register it
mdata = W_CacheLumpNum ( mlumpnum , PU_MUSIC ) ;
mhandle = I_RegisterSong ( mdata , W_LumpLength ( mlumpnum ) ) ;
# ifdef MUSSERV
if ( msg_id ! = - 1 )
{
struct musmsg msg_buffer ;
msg_buffer . msg_type = 6 ;
memset ( msg_buffer . msg_text , 0 , sizeof ( msg_buffer . msg_text ) ) ;
sprintf ( msg_buffer . msg_text , " d_%s " , mname ) ;
msgsnd ( msg_id , ( struct msgbuf * ) & msg_buffer , sizeof ( msg_buffer . msg_text ) , IPC_NOWAIT ) ;
}
# endif
// play it
if ( ! I_PlaySong ( mhandle , looping ) )
return false ;
strncpy ( music_name , mname , 7 ) ;
music_name [ 6 ] = 0 ;
music_lumpnum = mlumpnum ;
music_data = mdata ;
music_handle = mhandle ;
return true ;
}
static boolean S_DigMusic ( const char * mname , boolean looping )
{
if ( nodigimusic | | digital_disabled )
return false ; // try midi
if ( ! I_StartDigSong ( mname , looping ) )
return false ;
strncpy ( music_name , mname , 7 ) ;
music_name [ 6 ] = 0 ;
music_lumpnum = LUMPERROR ;
music_data = NULL ;
music_handle = 0 ;
return true ;
}
void S_ChangeMusic ( const char * mmusic , UINT16 mflags , boolean looping )
{
# if defined (DC) || defined (_WIN32_WCE) || defined (PSP) || defined(GP2X)
S_ClearSfx ( ) ;
# endif
if ( ( nomidimusic | | music_disabled ) & & ( nodigimusic | | digital_disabled ) )
return ;
// No Music (empty string)
if ( mmusic [ 0 ] = = 0 )
{
S_StopMusic ( ) ;
return ;
}
if ( strncmp ( music_name , mmusic , 6 ) )
{
S_StopMusic ( ) ; // shutdown old music
if ( ! S_DigMusic ( mmusic , looping ) & & ! S_MIDIMusic ( mmusic , looping ) )
{
CONS_Alert ( CONS_ERROR , M_GetText ( " Music lump %.6s not found! \n " ) , mmusic ) ;
return ;
}
}
I_SetSongTrack ( mflags & MUSIC_TRACKMASK ) ;
}
boolean S_SpeedMusic ( float speed )
{
return I_SetSongSpeed ( speed ) ;
}
void S_StopMusic ( void )
{
if ( ! music_playing )
return ;
if ( mus_paused )
I_ResumeSong ( music_handle ) ;
if ( ! nodigimusic )
I_StopDigSong ( ) ;
S_SpeedMusic ( 1.0f ) ;
I_StopSong ( music_handle ) ;
I_UnRegisterSong ( music_handle ) ;
# ifndef HAVE_SDL //SDL uses RWOPS
Z_ChangeTag ( music_data , PU_CACHE ) ;
# endif
music_data = NULL ;
music_name [ 0 ] = 0 ;
}
void S_SetDigMusicVolume ( INT32 volume )
{
if ( volume < 0 | | volume > 31 )
CONS_Alert ( CONS_WARNING , " musicvolume should be between 0-31 \n " ) ;
CV_SetValue ( & cv_digmusicvolume , volume & 31 ) ;
actualdigmusicvolume = cv_digmusicvolume . value ; //check for change of var
# ifdef DJGPPDOS
I_SetDigMusicVolume ( 31 ) ; // Trick for buggy dos drivers. Win32 doesn't need this.
# endif
I_SetDigMusicVolume ( volume & 31 ) ;
}
void S_SetMIDIMusicVolume ( INT32 volume )
{
if ( volume < 0 | | volume > 31 )
CONS_Alert ( CONS_WARNING , " musicvolume should be between 0-31 \n " ) ;
CV_SetValue ( & cv_midimusicvolume , volume & 0x1f ) ;
actualmidimusicvolume = cv_midimusicvolume . value ; //check for change of var
# ifdef DJGPPDOS
I_SetMIDIMusicVolume ( 31 ) ; // Trick for buggy dos drivers. Win32 doesn't need this.
# endif
I_SetMIDIMusicVolume ( volume & 0x1f ) ;
}
/// ------------------------
/// Init & Others
/// ------------------------
//
// Initializes sound stuff, including volume
// Sets channels, SFX and music volume,
// allocates channel buffer, sets S_sfx lookup.
//
void S_Init ( INT32 sfxVolume , INT32 digMusicVolume , INT32 midiMusicVolume )
{
INT32 i ;
if ( dedicated )
return ;
S_SetSfxVolume ( sfxVolume ) ;
S_SetDigMusicVolume ( digMusicVolume ) ;
S_SetMIDIMusicVolume ( midiMusicVolume ) ;
SetChannelsNum ( ) ;
// no sounds are playing, and they are not mus_paused
mus_paused = 0 ;
// Note that sounds have not been cached (yet).
for ( i = 1 ; i < NUMSFX ; i + + )
{
S_sfx [ i ] . usefulness = - 1 ; // for I_GetSfx()
S_sfx [ i ] . lumpnum = LUMPERROR ;
}
// precache sounds if requested by cmdline, or precachesound var true
if ( ! nosound & & ( M_CheckParm ( " -precachesound " ) | | precachesound . value ) )
{
// Initialize external data (all sounds) at start, keep static.
CONS_Printf ( M_GetText ( " Loading sounds... " ) ) ;
for ( i = 1 ; i < NUMSFX ; i + + )
if ( S_sfx [ i ] . name )
S_sfx [ i ] . data = I_GetSfx ( & S_sfx [ i ] ) ;
CONS_Printf ( M_GetText ( " pre-cached all sound data \n " ) ) ;
}
}
//
// Per level startup code.
// Kills playing sounds at start of level,
// determines music if any, changes music.
//
void S_Start ( void )
{
if ( mapmusflags & MUSIC_RELOADRESET )
{
strncpy ( mapmusname , mapheaderinfo [ gamemap - 1 ] - > musname , 7 ) ;
mapmusname [ 6 ] = 0 ;
mapmusflags = ( mapheaderinfo [ gamemap - 1 ] - > mustrack & MUSIC_TRACKMASK ) ;
}
mus_paused = 0 ;
if ( cv_resetmusic . value )
S_StopMusic ( ) ;
S_ChangeMusic ( mapmusname , mapmusflags , true ) ;
}
//
// Stop and resume music, during game PAUSE.
//
void S_PauseAudio ( void )
{
if ( ! nodigimusic )
I_PauseSong ( 0 ) ;
if ( music_playing & & ! mus_paused )
{
I_PauseSong ( music_handle ) ;
mus_paused = true ;
}
// pause cd music
# if (defined (__unix__) && !defined (MSDOS)) || defined (UNIXCOMMON) || defined (HAVE_SDL)
I_PauseCD ( ) ;
# else
I_StopCD ( ) ;
# endif
}
void S_ResumeAudio ( void )
{
if ( ! nodigimusic )
I_ResumeSong ( 0 ) ;
else
if ( music_playing & & mus_paused )
{
I_ResumeSong ( music_handle ) ;
mus_paused = false ;
}
// resume cd music
I_ResumeCD ( ) ;
}