2004-08-23 00:15:46 +00:00
/*
Copyright ( C ) 1996 - 1997 Id Software , Inc .
This program is free software ; you can redistribute it and / or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation ; either version 2
of the License , or ( at your option ) any later version .
This program is distributed in the hope that it will be useful ,
but WITHOUT ANY WARRANTY ; without even the implied warranty of
2005-06-14 04:52:10 +00:00
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE .
2004-08-23 00:15:46 +00:00
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
Foundation , Inc . , 59 Temple Place - Suite 330 , Boston , MA 02111 - 1307 , USA .
*/
// snd_dma.c -- main control for any streaming sound output devices
# include "quakedef.h"
void S_Play ( void ) ;
void S_PlayVol ( void ) ;
void S_SoundList ( void ) ;
void S_Update_ ( soundcardinfo_t * sc ) ;
void S_StopAllSounds ( qboolean clear ) ;
void S_StopAllSoundsC ( void ) ;
2005-02-06 02:47:36 +00:00
void S_UpdateCard ( soundcardinfo_t * sc ) ;
2004-08-23 00:15:46 +00:00
// =======================================================================
// Internal sound data & structures
// =======================================================================
2005-06-14 04:52:10 +00:00
soundcardinfo_t * sndcardinfo ; //the master card.
2004-08-23 00:15:46 +00:00
int snd_blocked = 0 ;
static qboolean snd_ambient = 1 ;
qboolean snd_initialized = false ;
int snd_speed ;
vec3_t listener_origin ;
vec3_t listener_forward ;
vec3_t listener_right ;
vec3_t listener_up ;
vec_t sound_nominal_clip_dist = 1000.0 ;
int soundtime ; // sample PAIRS
# define MAX_SFX 512
sfx_t * known_sfx ; // hunk allocated [MAX_SFX]
int num_sfx ;
sfx_t * ambient_sfx [ NUM_AMBIENTS ] ;
//int desired_speed = 44100;
int desired_bits = 16 ;
int sound_started = 0 ;
2010-07-11 02:22:39 +00:00
cvar_t bgmvolume = CVARF ( " musicvolume " , " 0 " , CVAR_ARCHIVE ) ;
cvar_t volume = CVARF ( " volume " , " 0.7 " , CVAR_ARCHIVE ) ;
cvar_t nosound = CVAR ( " nosound " , " 0 " ) ;
cvar_t precache = CVARAF ( " s_precache " , " 1 " ,
" precache " , 0 ) ;
cvar_t loadas8bit = CVARAF ( " s_loadas8bit " , " 0 " ,
" loadas8bit " , 0 ) ;
cvar_t bgmbuffer = CVAR ( " bgmbuffer " , " 4096 " ) ;
cvar_t ambient_level = CVARAF ( " s_ambientlevel " , " 0.3 " ,
" ambient_level " , 0 ) ;
cvar_t ambient_fade = CVARAF ( " s_ambientfade " , " 100 " ,
" ambient_fade " , 0 ) ;
cvar_t snd_noextraupdate = CVARAF ( " s_noextraupdate " , " 0 " ,
" snd_noextraupdate " , 0 ) ;
cvar_t snd_show = CVARAF ( " s_show " , " 0 " ,
" snd_show " , 0 ) ;
cvar_t snd_khz = CVARAF ( " s_khz " , " 11 " ,
" snd_khz " , CVAR_ARCHIVE ) ;
cvar_t snd_inactive = CVARAF ( " s_inactive " , " 0 " ,
" snd_inactive " , 0 ) ; //set if you want sound even when tabbed out.
cvar_t _snd_mixahead = CVARAF ( " s_mixahead " , " 0.2 " ,
" _snd_mixahead " , CVAR_ARCHIVE ) ;
cvar_t snd_leftisright = CVARAF ( " s_swapstereo " , " 0 " ,
" snd_leftisright " , CVAR_ARCHIVE ) ;
cvar_t snd_eax = CVARAF ( " s_eax " , " 0 " ,
" snd_eax " , 0 ) ;
cvar_t snd_speakers = CVARAF ( " s_numspeakers " , " 2 " ,
" snd_numspeakers " , 0 ) ;
cvar_t snd_buffersize = CVARAF ( " s_buffersize " , " 0 " ,
" snd_buffersize " , 0 ) ;
cvar_t snd_samplebits = CVARAF ( " s_bits " , " 16 " ,
" snd_samplebits " , CVAR_ARCHIVE ) ;
cvar_t snd_playersoundvolume = CVARAF ( " s_localvolume " , " 1 " ,
" snd_localvolume " , 0 ) ; //sugested by crunch
cvar_t snd_capture = CVARAF ( " s_capture " , " 0 " ,
" snd_capture " , 0 ) ;
cvar_t snd_linearresample = CVARAF ( " s_linearresample " , " 1 " ,
" snd_linearresample " , 0 ) ;
cvar_t snd_linearresample_stream = CVARAF ( " s_linearresample_stream " , " 0 " ,
" snd_linearresample_stream " , 0 ) ;
cvar_t snd_usemultipledevices = CVARAF ( " s_multipledevices " , " 0 " ,
" snd_multipledevices " , 0 ) ;
2005-06-14 04:52:10 +00:00
2006-05-09 07:26:14 +00:00
extern vfsfile_t * rawwritefile ;
2004-08-23 00:15:46 +00:00
void S_AmbientOff ( void )
{
snd_ambient = false ;
}
void S_AmbientOn ( void )
{
snd_ambient = true ;
}
2009-04-01 22:03:56 +00:00
qboolean S_HaveOutput ( void )
{
return sound_started & & sndcardinfo ;
}
2004-08-23 00:15:46 +00:00
void S_SoundInfo_f ( void )
{
soundcardinfo_t * sc ;
if ( ! sound_started )
{
Con_Printf ( " sound system not started \n " ) ;
return ;
}
if ( ! sndcardinfo )
{
2005-09-26 08:07:26 +00:00
Con_Printf ( " No sound cards \n " ) ;
2004-08-23 00:15:46 +00:00
return ;
}
for ( sc = sndcardinfo ; sc ; sc = sc - > next )
{
Con_Printf ( " %5d stereo \n " , sc - > sn . numchannels - 1 ) ;
Con_Printf ( " %5d samples \n " , sc - > sn . samples ) ;
Con_Printf ( " %5d samplepos \n " , sc - > sn . samplepos ) ;
Con_Printf ( " %5d samplebits \n " , sc - > sn . samplebits ) ;
Con_Printf ( " %5d speed \n " , sc - > sn . speed ) ;
Con_Printf ( " %5d total_channels \n " , sc - > total_chans ) ;
}
}
2005-08-03 23:14:59 +00:00
void ( * pDSOUND_UpdateCapture ) ( void ) ;
void S_RunCapture ( void )
{
//add new drivers in order or desirability.
if ( pDSOUND_UpdateCapture )
{
pDSOUND_UpdateCapture ( ) ;
return ;
}
}
2004-08-23 00:15:46 +00:00
2010-03-14 14:35:56 +00:00
sounddriver pOPENAL_InitCard ;
2005-06-14 04:52:10 +00:00
sounddriver pDSOUND_InitCard ;
sounddriver pALSA_InitCard ;
sounddriver pOSS_InitCard ;
2007-09-23 22:00:19 +00:00
sounddriver pMacOS_InitCard ;
2005-06-14 04:52:10 +00:00
sounddriver pSDL_InitCard ;
sounddriver pWAV_InitCard ;
2005-11-26 03:02:55 +00:00
sounddriver pAHI_InitCard ;
typedef struct {
char * name ;
sounddriver * ptr ;
} sdriver_t ;
sdriver_t drivers [ ] = {
//in order of preference
2010-03-14 14:35:56 +00:00
{ " OpenAL " , & pOPENAL_InitCard } , //yay, get someone else to sort out sound support, woot
{ " DSound " , & pDSOUND_InitCard } , //prefered on windows
{ " MacOS " , & pMacOS_InitCard } , //prefered on mac
{ " AHI " , & pAHI_InitCard } , //prefered on morphos
{ " SDL " , & pSDL_InitCard } , //prefered on linux
{ " ALSA " , & pALSA_InitCard } , //pure shite
{ " OSS " , & pOSS_InitCard } , //good, but not likely to work any more
{ " WaveOut " , & pWAV_InitCard } , //doesn't work properly in vista, etc.
2005-11-26 03:02:55 +00:00
{ NULL , NULL }
2005-06-14 04:52:10 +00:00
} ;
static int SNDDMA_Init ( soundcardinfo_t * sc , int * cardnum , int * drivernum )
{
2005-11-26 03:02:55 +00:00
sdriver_t * sd ;
2005-06-14 04:52:10 +00:00
int st = 0 ;
memset ( sc , 0 , sizeof ( * sc ) ) ;
2006-05-10 05:18:08 +00:00
// set requested rate
2009-11-04 21:16:50 +00:00
if ( ! snd_khz . ival )
2006-05-09 20:43:39 +00:00
sc - > sn . speed = 22050 ;
2009-11-04 21:16:50 +00:00
/* else if (snd_khz.ival >= 195)
2006-05-09 20:43:39 +00:00
sc - > sn . speed = 200000 ;
2009-11-04 21:16:50 +00:00
else if ( snd_khz . ival > = 180 )
2006-05-09 20:43:39 +00:00
sc - > sn . speed = 192000 ;
2009-11-04 21:16:50 +00:00
else if ( snd_khz . ival > = 90 )
2006-05-09 20:43:39 +00:00
sc - > sn . speed = 96000 ; */
2009-11-04 21:16:50 +00:00
else if ( snd_khz . ival > = 45 )
2005-06-14 04:52:10 +00:00
sc - > sn . speed = 48000 ;
2009-11-04 21:16:50 +00:00
else if ( snd_khz . ival > = 30 )
2005-06-14 04:52:10 +00:00
sc - > sn . speed = 44100 ;
2009-11-04 21:16:50 +00:00
else if ( snd_khz . ival > = 20 )
2005-06-14 04:52:10 +00:00
sc - > sn . speed = 22050 ;
2009-11-04 21:16:50 +00:00
else if ( snd_khz . ival > = 10 )
2005-06-14 04:52:10 +00:00
sc - > sn . speed = 11025 ;
2006-05-09 20:43:39 +00:00
else
sc - > sn . speed = 8000 ;
2005-06-14 04:52:10 +00:00
2006-05-10 05:18:08 +00:00
// set requested speaker count
2009-11-04 21:16:50 +00:00
if ( snd_speakers . ival > MAXSOUNDCHANNELS )
2006-05-10 07:35:19 +00:00
sc - > sn . numchannels = MAXSOUNDCHANNELS ;
2009-11-04 21:16:50 +00:00
else if ( snd_speakers . ival > 1 )
sc - > sn . numchannels = ( int ) snd_speakers . ival ;
2006-05-10 05:18:08 +00:00
else
sc - > sn . numchannels = 1 ;
// set requested sample bits
2009-11-04 21:16:50 +00:00
if ( snd_samplebits . ival > = 16 )
2006-05-10 05:18:08 +00:00
sc - > sn . samplebits = 16 ;
else
sc - > sn . samplebits = 8 ;
// set requested buffer size
2009-11-04 21:16:50 +00:00
if ( snd_buffersize . ival > 0 )
sc - > sn . samples = snd_buffersize . ival * sc - > sn . numchannels ;
2006-05-10 05:18:08 +00:00
else
sc - > sn . samples = 0 ;
2005-11-26 03:02:55 +00:00
sd = & drivers [ * drivernum ] ;
if ( ! sd - > ptr )
2005-06-14 04:52:10 +00:00
return 2 ; //no more cards.
2005-11-26 03:02:55 +00:00
if ( ! * sd - > ptr ) //driver not loaded
{
Con_DPrintf ( " Sound driver %s is not loaded \n " , sd - > name ) ;
2005-06-14 04:52:10 +00:00
st = 2 ;
2005-11-26 03:02:55 +00:00
}
2005-06-14 04:52:10 +00:00
else
2005-11-26 03:02:55 +00:00
{
Con_DPrintf ( " Trying to load a %s sound device \n " , sd - > name ) ;
st = ( * * sd - > ptr ) ( sc , * cardnum ) ;
}
2005-06-14 04:52:10 +00:00
if ( st = = 1 ) //worked
{
* cardnum + = 1 ; //use the next card next time
return st ;
}
else if ( st = = 0 ) //failed, try the next card with this driver.
{
* cardnum + = 1 ;
return SNDDMA_Init ( sc , cardnum , drivernum ) ;
}
else //card number wasn't valid, try the first card of the next driver
{
* cardnum = 0 ;
* drivernum + = 1 ;
return SNDDMA_Init ( sc , cardnum , drivernum ) ;
}
}
2006-09-17 00:59:22 +00:00
void S_DefaultSpeakerConfiguration ( soundcardinfo_t * sc )
{
2010-11-06 23:05:29 +00:00
sc - > dist [ 0 ] = 1 ;
sc - > dist [ 1 ] = 1 ;
sc - > dist [ 2 ] = 1 ;
sc - > dist [ 3 ] = 1 ;
sc - > dist [ 4 ] = 1 ;
sc - > dist [ 5 ] = 1 ;
2006-09-17 00:59:22 +00:00
if ( sc - > sn . numchannels < 3 )
{
2010-11-06 23:05:29 +00:00
VectorSet ( sc - > speakerdir [ 0 ] , 0 , 1 , 0 ) ;
VectorSet ( sc - > speakerdir [ 1 ] , 0 , - 1 , 0 ) ;
2006-09-17 00:59:22 +00:00
}
else if ( sc - > sn . numchannels < 5 )
{
2010-11-06 23:05:29 +00:00
VectorSet ( sc - > speakerdir [ 0 ] , 0.7 , - 0.7 , 0 ) ;
VectorSet ( sc - > speakerdir [ 1 ] , 0.7 , 0.7 , 0 ) ;
VectorSet ( sc - > speakerdir [ 2 ] , - 0.7 , - 0.7 , 0 ) ;
VectorSet ( sc - > speakerdir [ 3 ] , - 0.7 , 0.7 , 0 ) ;
2006-09-17 00:59:22 +00:00
}
else
{
2010-11-06 23:05:29 +00:00
VectorSet ( sc - > speakerdir [ 0 ] , 0.7 , - 0.7 , 0 ) ;
VectorSet ( sc - > speakerdir [ 1 ] , 0.7 , 0.7 , 0 ) ;
VectorSet ( sc - > speakerdir [ 2 ] , 0 , 0 , 0 ) ;
VectorSet ( sc - > speakerdir [ 3 ] , 0 , 0 , 0 ) ;
VectorSet ( sc - > speakerdir [ 4 ] , - 0.7 , - 0.7 , 0 ) ;
VectorSet ( sc - > speakerdir [ 5 ] , - 0.7 , 0.7 , 0 ) ;
2006-09-17 00:59:22 +00:00
}
}
2004-08-23 00:15:46 +00:00
/*
= = = = = = = = = = = = = = = =
S_Startup
= = = = = = = = = = = = = = = =
*/
2005-07-14 01:57:34 +00:00
void S_ClearRaw ( void ) ;
2004-08-23 00:15:46 +00:00
void S_Startup ( void )
{
2005-06-14 04:52:10 +00:00
int cardnum , drivernum ;
2004-08-23 00:15:46 +00:00
int warningmessage = 0 ;
int rc ;
soundcardinfo_t * sc ;
if ( ! snd_initialized )
return ;
if ( sound_started )
S_Shutdown ( ) ;
2005-02-06 02:47:36 +00:00
snd_blocked = 0 ;
2006-06-02 17:42:36 +00:00
snd_speed = 0 ;
2005-02-06 02:47:36 +00:00
2006-09-17 00:59:22 +00:00
for ( cardnum = 0 , drivernum = 0 ; ; )
2004-08-23 00:15:46 +00:00
{
2006-09-17 00:59:22 +00:00
sc = Z_Malloc ( sizeof ( soundcardinfo_t ) ) ;
rc = SNDDMA_Init ( sc , & cardnum , & drivernum ) ;
if ( ! rc ) //error stop
2004-08-23 00:15:46 +00:00
{
2006-09-17 00:59:22 +00:00
Con_Printf ( " S_Startup: SNDDMA_Init failed. \n " ) ;
Z_Free ( sc ) ;
break ;
}
if ( rc = = 2 ) //silently stop (no more cards)
{
Z_Free ( sc ) ;
break ;
}
2004-08-23 00:15:46 +00:00
2006-09-17 00:59:22 +00:00
S_DefaultSpeakerConfiguration ( sc ) ;
2004-08-23 00:15:46 +00:00
2006-09-17 00:59:22 +00:00
if ( sndcardinfo )
{ //if the sample speeds of multiple soundcards do not match, it'll fail.
if ( snd_speed ! = sc - > sn . speed )
2004-08-23 00:15:46 +00:00
{
2006-09-17 00:59:22 +00:00
if ( ! warningmessage )
2004-08-23 00:15:46 +00:00
{
2006-09-17 00:59:22 +00:00
Con_Printf ( " S_Startup: Ignoring soundcard %s due to mismatched sample speeds. \n Try running Quake with -singlesound to use just the primary soundcard \n " , sc - > name ) ;
S_ShutdownCard ( sc ) ;
warningmessage = true ;
2004-08-23 00:15:46 +00:00
}
2006-09-17 00:59:22 +00:00
Z_Free ( sc ) ;
continue ;
2004-08-23 00:15:46 +00:00
}
2006-09-17 00:59:22 +00:00
}
else
snd_speed = sc - > sn . speed ;
2004-08-23 00:15:46 +00:00
2006-09-17 00:59:22 +00:00
sc - > next = sndcardinfo ;
sndcardinfo = sc ;
2005-06-14 04:52:10 +00:00
2009-11-04 21:16:50 +00:00
if ( ! snd_usemultipledevices . ival )
2006-09-17 00:59:22 +00:00
break ;
2004-08-23 00:15:46 +00:00
}
2009-04-01 22:03:56 +00:00
sound_started = ! ! sndcardinfo ;
2005-07-14 01:57:34 +00:00
S_ClearRaw ( ) ;
2004-08-23 00:15:46 +00:00
}
2005-06-14 04:52:10 +00:00
void SNDDMA_SetUnderWater ( qboolean underwater )
{
soundcardinfo_t * sc ;
for ( sc = sndcardinfo ; sc ; sc = sc - > next )
sc - > SetWaterDistortion ( sc , underwater ) ;
}
2005-06-18 23:52:42 +00:00
//why isn't this part of S_Restart_f anymore?
//so that the video code can call it directly without flushing the models it's just loaded.
void S_DoRestart ( void )
2005-06-14 04:52:10 +00:00
{
2009-11-04 21:16:50 +00:00
if ( nosound . ival )
2004-12-02 07:09:14 +00:00
return ;
2005-06-14 04:52:10 +00:00
S_StopAllSounds ( true ) ;
2004-08-23 00:15:46 +00:00
S_Shutdown ( ) ;
sound_started = 0 ;
S_Startup ( ) ;
ambient_sfx [ AMBIENT_WATER ] = S_PrecacheSound ( " ambience/water1.wav " ) ;
2005-06-14 04:52:10 +00:00
ambient_sfx [ AMBIENT_SKY ] = S_PrecacheSound ( " ambience/wind2.wav " ) ;
2004-08-23 00:15:46 +00:00
S_StopAllSounds ( true ) ;
}
2005-06-18 23:52:42 +00:00
void S_Restart_f ( void )
{
Cache_Flush ( ) ; //forget the old sounds.
S_DoRestart ( ) ;
}
2004-08-23 00:15:46 +00:00
void S_Control_f ( void )
2005-06-14 04:52:10 +00:00
{
2004-08-23 00:15:46 +00:00
int i ;
char * command ;
command = Cmd_Argv ( 1 ) ;
if ( ! Q_strcasecmp ( command , " off " ) )
{
Cache_Flush ( ) ; //forget the old sounds.
2005-06-14 04:52:10 +00:00
S_StopAllSounds ( true ) ;
2004-08-23 00:15:46 +00:00
S_Shutdown ( ) ;
sound_started = 0 ;
}
else if ( ! Q_strcasecmp ( command , " multi " ) | | ! Q_strcasecmp ( command , " multiple " ) )
{
if ( ! Q_strcasecmp ( Cmd_Argv ( 2 ) , " off " ) )
{
2009-11-04 21:16:50 +00:00
if ( snd_usemultipledevices . ival )
2004-08-23 00:15:46 +00:00
{
2005-06-14 04:52:10 +00:00
Cvar_SetValue ( & snd_usemultipledevices , 0 ) ;
S_Restart_f ( ) ;
}
2004-08-23 00:15:46 +00:00
}
2009-11-04 21:16:50 +00:00
else if ( ! snd_usemultipledevices . ival )
2004-08-23 00:15:46 +00:00
{
2005-06-14 04:52:10 +00:00
Cvar_SetValue ( & snd_usemultipledevices , 1 ) ;
2004-08-23 00:15:46 +00:00
S_Restart_f ( ) ;
}
return ;
}
if ( ! Q_strcasecmp ( command , " single " ) )
{
2005-06-14 04:52:10 +00:00
Cvar_SetValue ( & snd_usemultipledevices , 0 ) ;
2004-08-23 00:15:46 +00:00
S_Restart_f ( ) ;
return ;
}
if ( ! Q_strcasecmp ( command , " rate " ) | | ! Q_strcasecmp ( command , " speed " ) )
{
2005-06-14 04:52:10 +00:00
Cvar_SetValue ( & snd_khz , atof ( Cmd_Argv ( 2 ) ) / 1000 ) ;
2004-08-23 00:15:46 +00:00
S_Restart_f ( ) ;
return ;
}
//individual device control
if ( ! Q_strncasecmp ( command , " card " , 4 ) )
{
int card ;
soundcardinfo_t * sc ;
card = atoi ( command + 4 ) ;
2005-01-13 16:29:20 +00:00
for ( i = 0 , sc = sndcardinfo ; i < card & & sc ; i + + , sc = sc - > next )
;
2004-08-23 00:15:46 +00:00
if ( ! sc )
{
Con_Printf ( " Sound card %i is invalid (try resetting first) \n " , card ) ;
return ;
}
if ( Cmd_Argc ( ) < 3 )
{
Con_Printf ( " Scard %i is %s \n " , card , sc - > name ) ;
return ;
}
command = Cmd_Argv ( 2 ) ;
if ( ! Q_strcasecmp ( command , " mono " ) )
{
for ( i = 0 ; i < MAXSOUNDCHANNELS ; i + + )
{
2010-11-06 23:05:29 +00:00
VectorSet ( sc - > speakerdir [ i ] , 0 , 0 , 0 ) ;
2004-08-23 00:15:46 +00:00
sc - > dist [ i ] = 1 ;
}
}
else if ( ! Q_strcasecmp ( command , " standard " ) | | ! Q_strcasecmp ( command , " stereo " ) )
{
for ( i = 0 ; i < MAXSOUNDCHANNELS ; i + + )
{
2010-11-06 23:05:29 +00:00
VectorSet ( sc - > speakerdir [ i ] , 0 , ( i & 1 ) ? - 1 : 1 , 0 ) ;
2004-08-23 00:15:46 +00:00
sc - > dist [ i ] = 1 ;
}
}
else if ( ! Q_strcasecmp ( command , " swap " ) )
{
for ( i = 0 ; i < MAXSOUNDCHANNELS ; i + + )
{
2010-11-06 23:05:29 +00:00
sc - > speakerdir [ i ] [ 1 ] * = - 1 ;
2004-08-23 00:15:46 +00:00
}
}
else if ( ! Q_strcasecmp ( command , " front " ) )
{
for ( i = 0 ; i < MAXSOUNDCHANNELS ; i + + )
{
2010-11-06 23:05:29 +00:00
VectorSet ( sc - > speakerdir [ i ] , 0.7 , ( i & 1 ) ? - 0.7 : 0.7 , 0 ) ;
2004-08-23 00:15:46 +00:00
sc - > dist [ i ] = 1 ;
}
}
else if ( ! Q_strcasecmp ( command , " back " ) )
{
for ( i = 0 ; i < MAXSOUNDCHANNELS ; i + + )
{
2010-11-06 23:05:29 +00:00
VectorSet ( sc - > speakerdir [ i ] , - 0.7 , ( i & 1 ) ? - 0.7 : 0.7 , 0 ) ;
2004-08-23 00:15:46 +00:00
sc - > dist [ i ] = 1 ;
}
}
return ;
}
2010-11-06 23:05:29 +00:00
else
Con_Printf ( " valid commands are: off, single, multi, cardX mono, cardX stereo, cardX front, cardX back \n " ) ;
2004-08-23 00:15:46 +00:00
}
/*
= = = = = = = = = = = = = = = =
S_Init
= = = = = = = = = = = = = = = =
*/
void S_Init ( void )
{
int p ;
2005-05-08 06:03:15 +00:00
Con_DPrintf ( " \n Sound Initialization \n " ) ;
2004-08-23 00:15:46 +00:00
Cmd_AddCommand ( " play " , S_Play ) ;
2005-07-08 00:37:52 +00:00
Cmd_AddCommand ( " play2 " , S_Play ) ;
2004-08-23 00:15:46 +00:00
Cmd_AddCommand ( " playvol " , S_PlayVol ) ;
Cmd_AddCommand ( " stopsound " , S_StopAllSoundsC ) ;
Cmd_AddCommand ( " soundlist " , S_SoundList ) ;
Cmd_AddCommand ( " soundinfo " , S_SoundInfo_f ) ;
Cmd_AddCommand ( " snd_restart " , S_Restart_f ) ;
Cmd_AddCommand ( " soundcontrol " , S_Control_f ) ;
Cvar_Register ( & nosound , " Sound controls " ) ;
Cvar_Register ( & volume , " Sound controls " ) ;
Cvar_Register ( & precache , " Sound controls " ) ;
Cvar_Register ( & loadas8bit , " Sound controls " ) ;
Cvar_Register ( & bgmvolume , " Sound controls " ) ;
Cvar_Register ( & bgmbuffer , " Sound controls " ) ;
Cvar_Register ( & ambient_level , " Sound controls " ) ;
Cvar_Register ( & ambient_fade , " Sound controls " ) ;
Cvar_Register ( & snd_noextraupdate , " Sound controls " ) ;
Cvar_Register ( & snd_show , " Sound controls " ) ;
Cvar_Register ( & _snd_mixahead , " Sound controls " ) ;
Cvar_Register ( & snd_khz , " Sound controls " ) ;
Cvar_Register ( & snd_leftisright , " Sound controls " ) ;
Cvar_Register ( & snd_eax , " Sound controls " ) ;
Cvar_Register ( & snd_speakers , " Sound controls " ) ;
2006-05-10 05:18:08 +00:00
Cvar_Register ( & snd_buffersize , " Sound controls " ) ;
Cvar_Register ( & snd_samplebits , " Sound controls " ) ;
2004-08-23 00:15:46 +00:00
Cvar_Register ( & snd_capture , " Sound controls " ) ;
2004-10-03 22:52:02 +00:00
Cvar_Register ( & snd_inactive , " Sound controls " ) ;
2005-05-26 12:55:34 +00:00
Cvar_Register ( & snd_playersoundvolume , " Sound controls " ) ;
2005-06-14 04:52:10 +00:00
Cvar_Register ( & snd_usemultipledevices , " Sound controls " ) ;
2006-05-08 06:44:47 +00:00
Cvar_Register ( & snd_linearresample , " Sound controls " ) ;
2006-06-04 01:43:52 +00:00
Cvar_Register ( & snd_linearresample_stream , " Sound controls " ) ;
2006-05-08 06:44:47 +00:00
2010-03-14 14:35:56 +00:00
# ifdef AVAIL_OPENAL
OpenAL_CvarInit ( ) ;
# endif
2005-08-12 17:57:22 +00:00
if ( COM_CheckParm ( " -nosound " ) )
{
Cvar_ForceSet ( & nosound , " 1 " ) ;
nosound . flags | = CVAR_NOSET ;
return ;
}
p = COM_CheckParm ( " -soundspeed " ) ;
if ( p )
{
if ( p < com_argc - 1 )
Cvar_SetValue ( & snd_khz , atof ( com_argv [ p + 1 ] ) / 1000 ) ;
else
Sys_Error ( " S_Init: you must specify a speed in KB after -soundspeed " ) ;
}
2005-06-14 04:52:10 +00:00
if ( COM_CheckParm ( " -nomultipledevices " ) | | COM_CheckParm ( " -singlesound " ) )
Cvar_SetValue ( & snd_usemultipledevices , 0 ) ;
if ( COM_CheckParm ( " -multisound " ) )
Cvar_SetValue ( & snd_usemultipledevices , 1 ) ;
2005-05-26 12:55:34 +00:00
2004-08-23 00:15:46 +00:00
if ( host_parms . memsize < 0x800000 )
{
Cvar_Set ( & loadas8bit , " 1 " ) ;
Con_Printf ( " loading all sounds as 8bit \n " ) ;
}
snd_initialized = true ;
known_sfx = Hunk_AllocName ( MAX_SFX * sizeof ( sfx_t ) , " sfx_t " ) ;
num_sfx = 0 ;
// create a piece of DMA memory
if ( sndcardinfo )
Con_SafePrintf ( " Sound sampling rate: %i \n " , sndcardinfo - > sn . speed ) ;
ambient_sfx [ AMBIENT_WATER ] = S_PrecacheSound ( " ambience/water1.wav " ) ;
ambient_sfx [ AMBIENT_SKY ] = S_PrecacheSound ( " ambience/wind2.wav " ) ;
S_StopAllSounds ( true ) ;
}
// =======================================================================
// Shutdown sound engine
// =======================================================================
void S_ShutdownCard ( soundcardinfo_t * sc )
{
2006-09-17 00:59:22 +00:00
soundcardinfo_t * prev ;
2009-03-07 04:37:24 +00:00
# if defined(_WIN32) && defined(AVAIL_DSOUND)
2005-06-04 04:20:20 +00:00
extern int aimedforguid ;
aimedforguid = 0 ;
# endif
2006-09-17 00:59:22 +00:00
if ( sndcardinfo = = sc )
sndcardinfo = sc - > next ;
else
2005-06-14 04:52:10 +00:00
{
2006-09-17 00:59:22 +00:00
for ( prev = sndcardinfo ; prev - > next ; prev = prev - > next )
{
if ( prev - > next = = sc )
prev - > next = sc - > next ;
}
2005-06-14 04:52:10 +00:00
}
2006-09-17 00:59:22 +00:00
sc - > Shutdown ( sc ) ;
Z_Free ( sc ) ;
2004-08-23 00:15:46 +00:00
}
void S_Shutdown ( void )
2005-06-14 04:52:10 +00:00
{
2004-08-23 00:15:46 +00:00
soundcardinfo_t * sc , * next ;
2009-03-07 04:37:24 +00:00
# if defined(_WIN32) && defined(AVAIL_DSOUND)
2006-09-17 00:59:22 +00:00
extern int aimedforguid ;
aimedforguid = 0 ;
# endif
2004-08-23 00:15:46 +00:00
for ( sc = sndcardinfo ; sc ; sc = next )
{
next = sc - > next ;
2006-09-17 00:59:22 +00:00
sc - > Shutdown ( sc ) ;
2004-08-23 00:15:46 +00:00
Z_Free ( sc ) ;
sndcardinfo = next ;
}
sound_started = 0 ;
}
// =======================================================================
// Load a sound
// =======================================================================
/*
= = = = = = = = = = = = = = = = = =
S_FindName
= = = = = = = = = = = = = = = = = =
*/
sfx_t * S_FindName ( char * name )
{
int i ;
sfx_t * sfx ;
if ( ! name )
Sys_Error ( " S_FindName: NULL \n " ) ;
if ( Q_strlen ( name ) > = MAX_OSPATH )
Sys_Error ( " Sound name too long: %s " , name ) ;
// see if already loaded
for ( i = 0 ; i < num_sfx ; i + + )
if ( ! Q_strcmp ( known_sfx [ i ] . name , name ) )
{
return & known_sfx [ i ] ;
}
if ( num_sfx = = MAX_SFX )
Sys_Error ( " S_FindName: out of sfx_t " ) ;
2005-06-14 04:52:10 +00:00
2004-08-23 00:15:46 +00:00
sfx = & known_sfx [ i ] ;
strcpy ( sfx - > name , name ) ;
num_sfx + + ;
2005-06-14 04:52:10 +00:00
2004-08-23 00:15:46 +00:00
return sfx ;
}
2006-10-05 22:11:17 +00:00
void S_ResetFailedLoad ( void )
{
int i ;
for ( i = 0 ; i < num_sfx ; i + + )
known_sfx [ i ] . failedload = false ;
}
2004-08-23 00:15:46 +00:00
/*
= = = = = = = = = = = = = = = = = =
S_TouchSound
= = = = = = = = = = = = = = = = = =
*/
void S_TouchSound ( char * name )
{
sfx_t * sfx ;
2005-06-14 04:52:10 +00:00
2004-08-23 00:15:46 +00:00
if ( ! sound_started )
return ;
sfx = S_FindName ( name ) ;
Cache_Check ( & sfx - > cache ) ;
}
/*
= = = = = = = = = = = = = = = = = =
S_PrecacheSound
= = = = = = = = = = = = = = = = = =
*/
sfx_t * S_PrecacheSound ( char * name )
{
sfx_t * sfx ;
2009-11-04 21:16:50 +00:00
if ( nosound . ival )
2004-08-23 00:15:46 +00:00
return NULL ;
sfx = S_FindName ( name ) ;
2005-06-14 04:52:10 +00:00
2004-08-23 00:15:46 +00:00
// cache it in
2009-11-04 21:16:50 +00:00
if ( precache . ival & & sndcardinfo )
2004-08-23 00:15:46 +00:00
S_LoadSound ( sfx ) ;
2005-06-14 04:52:10 +00:00
2004-08-23 00:15:46 +00:00
return sfx ;
}
//=============================================================================
/*
= = = = = = = = = = = = = = = = =
SND_PickChannel
= = = = = = = = = = = = = = = = =
*/
channel_t * SND_PickChannel ( soundcardinfo_t * sc , int entnum , int entchannel )
{
int ch_idx ;
int first_to_die ;
int life_left ;
// Check for replacement sound, or find the best one to replace
first_to_die = - 1 ;
life_left = 0x7fffffff ;
2010-11-06 23:05:29 +00:00
for ( ch_idx = DYNAMIC_FIRST ; ch_idx < DYNAMIC_STOP ; ch_idx + + )
2004-08-23 00:15:46 +00:00
{
if ( entchannel ! = 0 // channel 0 never overrides
& & sc - > channel [ ch_idx ] . entnum = = entnum
& & ( sc - > channel [ ch_idx ] . entchannel = = entchannel | | entchannel = = - 1 ) & & sc - > channel [ ch_idx ] . end > snd_speed / 10 )
2005-07-28 15:33:27 +00:00
{ // always override sound from same entity
2004-08-23 00:15:46 +00:00
first_to_die = ch_idx ;
break ;
}
// don't let monster sounds override player sounds
2004-10-03 22:52:02 +00:00
if ( sc - > channel [ ch_idx ] . entnum = = cl . playernum [ 0 ] + 1 & & entnum ! = cl . playernum [ 0 ] + 1 & & sc - > channel [ ch_idx ] . sfx )
2004-08-23 00:15:46 +00:00
continue ;
if ( sc - > channel [ ch_idx ] . end < life_left )
{
life_left = sc - > channel [ ch_idx ] . end ;
first_to_die = ch_idx ;
}
}
if ( first_to_die = = - 1 )
return NULL ;
if ( sc - > channel [ first_to_die ] . sfx )
sc - > channel [ first_to_die ] . sfx = NULL ;
2009-07-25 09:15:42 +00:00
if ( sc - > total_chans < = first_to_die )
sc - > total_chans = first_to_die + 1 ;
2005-06-14 04:52:10 +00:00
return & sc - > channel [ first_to_die ] ;
}
2004-08-23 00:15:46 +00:00
/*
= = = = = = = = = = = = = = = = =
SND_Spatialize
= = = = = = = = = = = = = = = = =
*/
void SND_Spatialize ( soundcardinfo_t * sc , channel_t * ch )
{
2010-11-06 23:05:29 +00:00
vec3_t listener_vec ;
2004-08-23 00:15:46 +00:00
vec_t dist ;
2005-01-13 16:29:20 +00:00
vec_t scale ;
2010-11-06 23:05:29 +00:00
vec3_t world_vec ;
2004-08-23 00:15:46 +00:00
sfx_t * snd ;
2005-01-13 16:29:20 +00:00
int i ;
2004-08-23 00:15:46 +00:00
2005-07-28 15:33:27 +00:00
// anything coming from the view entity will always be full volume
2004-10-03 22:52:02 +00:00
if ( ch - > entnum = = - 1 | | ch - > entnum = = cl . playernum [ 0 ] + 1 )
2004-08-23 00:15:46 +00:00
{
2005-01-13 16:29:20 +00:00
for ( i = 0 ; i < sc - > sn . numchannels ; i + + )
{
2008-06-08 14:37:57 +00:00
ch - > vol [ i ] = ch - > master_vol * ( ruleset_allow_localvolume . value ? snd_playersoundvolume . value : 1 ) ;
2005-01-13 16:29:20 +00:00
}
2004-08-23 00:15:46 +00:00
return ;
}
// calculate stereo seperation and distance attenuation
snd = ch - > sfx ;
2010-11-06 23:05:29 +00:00
VectorSubtract ( ch - > origin , listener_origin , world_vec ) ;
2005-06-14 04:52:10 +00:00
2010-11-06 23:05:29 +00:00
dist = VectorNormalize ( world_vec ) * ch - > dist_mult ;
2005-06-14 04:52:10 +00:00
2010-11-06 23:05:29 +00:00
listener_vec [ 1 ] = DotProduct ( listener_right , world_vec ) ;
listener_vec [ 0 ] = DotProduct ( listener_forward , world_vec ) ;
listener_vec [ 2 ] = DotProduct ( listener_up , world_vec ) ;
2004-08-23 00:15:46 +00:00
2009-11-04 21:16:50 +00:00
if ( snd_leftisright . ival )
2010-11-06 23:05:29 +00:00
listener_vec [ 1 ] = - listener_vec [ 1 ] ;
2009-11-04 21:16:50 +00:00
2005-01-13 16:29:20 +00:00
for ( i = 0 ; i < sc - > sn . numchannels ; i + + )
2004-08-23 00:15:46 +00:00
{
2010-11-06 23:05:29 +00:00
scale = ( 1 + DotProduct ( listener_vec , sc - > speakerdir [ i ] ) ) / 2 ;
if ( scale > 1 )
scale = 1 ;
2005-01-13 16:29:20 +00:00
scale = ( 1.0 - dist ) * scale * sc - > dist [ i ] ;
ch - > vol [ i ] = ( int ) ( ch - > master_vol * scale ) ;
if ( ch - > vol [ i ] < 0 )
ch - > vol [ i ] = 0 ;
2004-08-23 00:15:46 +00:00
}
}
// =======================================================================
// Start a sound effect
// =======================================================================
2010-11-06 23:05:29 +00:00
void S_StartSoundCard ( soundcardinfo_t * sc , int entnum , int entchannel , sfx_t * sfx , vec3_t origin , float fvol , float attenuation , int startpos , int pitchadj )
2004-08-23 00:15:46 +00:00
{
channel_t * target_chan , * check ;
sfxcache_t * scache ;
int vol ;
int ch_idx ;
int skip ;
if ( ! sound_started )
return ;
if ( ! sfx )
return ;
2009-11-04 21:16:50 +00:00
if ( nosound . ival )
2004-08-23 00:15:46 +00:00
return ;
2010-03-14 14:35:56 +00:00
# ifdef AVAIL_OPENAL
if ( sc - > openal )
OpenAL_StartSound ( entnum , entchannel , sfx , origin , fvol , attenuation ) ;
# endif
2004-08-23 00:15:46 +00:00
vol = fvol * 255 ;
// pick a channel to play on
target_chan = SND_PickChannel ( sc , entnum , entchannel ) ;
if ( ! target_chan )
return ;
2005-06-14 04:52:10 +00:00
2004-08-23 00:15:46 +00:00
// spatialize
memset ( target_chan , 0 , sizeof ( * target_chan ) ) ;
if ( ! origin )
{
VectorCopy ( listener_origin , target_chan - > origin ) ;
}
else
{
VectorCopy ( origin , target_chan - > origin ) ;
}
target_chan - > dist_mult = attenuation / sound_nominal_clip_dist ;
target_chan - > master_vol = vol ;
target_chan - > entnum = entnum ;
target_chan - > entchannel = entchannel ;
SND_Spatialize ( sc , target_chan ) ;
if ( ! target_chan - > vol [ 0 ] & & ! target_chan - > vol [ 1 ] & & ! target_chan - > vol [ 2 ] & & ! target_chan - > vol [ 3 ] & & ! target_chan - > vol [ 4 ] & & ! target_chan - > vol [ 5 ] )
return ; // not audible at all
// new channel
scache = S_LoadSound ( sfx ) ;
if ( ! scache )
{
target_chan - > sfx = NULL ;
return ; // couldn't load the sound's data
}
2007-08-23 21:25:18 +00:00
2009-11-04 21:16:50 +00:00
if ( scache - > length > snd_speed * 20 & & ! ruleset_allow_overlongsounds . ival )
2007-08-23 21:25:18 +00:00
{
Con_DPrintf ( " Shortening over-long sound effect \n " ) ;
2007-08-24 17:40:31 +00:00
startpos = scache - > length - snd_speed * 10 ;
2007-08-23 21:25:18 +00:00
}
2004-08-23 00:15:46 +00:00
target_chan - > sfx = sfx ;
2010-11-06 23:05:29 +00:00
target_chan - > rate = ( 1 < < PITCHSHIFT ) + pitchadj ;
target_chan - > pos = startpos * target_chan - > rate ;
target_chan - > end = sc - > paintedtime + ( ( scache - > length - startpos ) < < PITCHSHIFT ) / target_chan - > rate ;
2004-11-23 00:18:51 +00:00
target_chan - > looping = false ;
2005-06-14 04:52:10 +00:00
2004-08-23 00:15:46 +00:00
// if an identical sound has also been started this frame, offset the pos
// a bit to keep it from just making the first one louder
2010-11-06 23:05:29 +00:00
check = & sc - > channel [ DYNAMIC_FIRST ] ;
for ( ch_idx = DYNAMIC_FIRST ; ch_idx < DYNAMIC_STOP ; ch_idx + + , check + + )
2004-08-23 00:15:46 +00:00
{
if ( check = = target_chan )
continue ;
if ( check - > sfx = = sfx & & ! check - > pos )
{
skip = rand ( ) % ( int ) ( 0.1 * sc - > sn . speed ) ;
if ( skip > = target_chan - > end )
skip = target_chan - > end - 1 ;
2010-11-06 23:05:29 +00:00
target_chan - > pos + = skip * target_chan - > rate ;
2004-08-23 00:15:46 +00:00
target_chan - > end - = skip ;
break ;
}
}
}
2006-05-10 07:35:19 +00:00
void S_StartSoundDelayed ( int entnum , int entchannel , sfx_t * sfx , vec3_t origin , float fvol , float attenuation , float timeofs )
{
soundcardinfo_t * sc ;
if ( ! sfx | | ! * sfx - > name ) //no named sounds would need specific starting.
return ;
for ( sc = sndcardinfo ; sc ; sc = sc - > next )
2010-11-06 23:05:29 +00:00
S_StartSoundCard ( sc , entnum , entchannel , sfx , origin , fvol , attenuation , - ( int ) ( timeofs * sc - > sn . speed ) , 0 ) ;
2006-05-10 07:35:19 +00:00
}
2010-11-06 23:05:29 +00:00
void S_StartSound ( int entnum , int entchannel , sfx_t * sfx , vec3_t origin , float fvol , float attenuation , int pitchadj )
2004-08-23 00:15:46 +00:00
{
soundcardinfo_t * sc ;
2004-10-03 22:52:02 +00:00
2004-08-23 00:15:46 +00:00
if ( ! sfx | | ! * sfx - > name ) //no named sounds would need specific starting.
return ;
for ( sc = sndcardinfo ; sc ; sc = sc - > next )
2010-11-06 23:05:29 +00:00
S_StartSoundCard ( sc , entnum , entchannel , sfx , origin , fvol , attenuation , 0 , pitchadj ) ;
2004-08-23 00:15:46 +00:00
}
qboolean S_IsPlayingSomewhere ( sfx_t * s )
{
soundcardinfo_t * si ;
int i ;
for ( si = sndcardinfo ; si ; si = si - > next )
{
2006-05-28 21:56:04 +00:00
for ( i = 0 ; i < si - > total_chans ; i + + )
2004-08-23 00:15:46 +00:00
if ( si - > channel [ i ] . sfx = = s )
return true ;
}
return false ;
}
void S_StopSoundCard ( soundcardinfo_t * sc , int entnum , int entchannel )
{
int i ;
for ( i = 0 ; i < sc - > total_chans ; i + + )
{
if ( sc - > channel [ i ] . entnum = = entnum
2010-08-21 13:31:39 +00:00
& & ( ! entchannel | | sc - > channel [ i ] . entchannel = = entchannel ) )
2004-08-23 00:15:46 +00:00
{
sc - > channel [ i ] . end = 0 ;
sc - > channel [ i ] . sfx = NULL ;
2010-08-21 13:31:39 +00:00
if ( entchannel )
return ;
2004-08-23 00:15:46 +00:00
}
}
}
void S_StopSound ( int entnum , int entchannel )
{
soundcardinfo_t * sc ;
for ( sc = sndcardinfo ; sc ; sc = sc - > next )
S_StopSoundCard ( sc , entnum , entchannel ) ;
}
void S_StopAllSounds ( qboolean clear )
{
int i ;
sfx_t * s ;
soundcardinfo_t * sc ;
for ( sc = sndcardinfo ; sc ; sc = sc - > next )
{
if ( ! sound_started )
return ;
2006-05-28 21:56:04 +00:00
for ( i = 0 ; i < sc - > total_chans ; i + + )
2004-08-23 00:15:46 +00:00
if ( sc - > channel [ i ] . sfx )
{
s = sc - > channel [ i ] . sfx ;
sc - > channel [ i ] . sfx = NULL ;
if ( s - > decoder )
if ( ! S_IsPlayingSomewhere ( s ) ) //if we aint playing it elsewhere, free it compleatly.
{
s - > decoder - > abort ( s ) ;
}
}
2006-05-28 21:56:04 +00:00
sc - > total_chans = MAX_DYNAMIC_CHANNELS + NUM_AMBIENTS + NUM_MUSICS ; // no statics
2004-08-23 00:15:46 +00:00
Q_memset ( sc - > channel , 0 , MAX_CHANNELS * sizeof ( channel_t ) ) ;
if ( clear )
S_ClearBuffer ( sc ) ;
}
}
void S_StopAllSoundsC ( void )
{
S_StopAllSounds ( true ) ;
}
void S_ClearBuffer ( soundcardinfo_t * sc )
{
2005-06-14 04:52:10 +00:00
void * buffer ;
2004-08-23 00:15:46 +00:00
int clear ;
2006-02-01 22:36:12 +00:00
2004-08-23 00:15:46 +00:00
if ( ! sound_started | | ! sc - > sn . buffer )
return ;
if ( sc - > sn . samplebits = = 8 )
clear = 0x80 ;
else
clear = 0 ;
2005-06-14 04:52:10 +00:00
buffer = sc - > Lock ( sc ) ;
if ( buffer )
{
2008-03-02 10:20:25 +00:00
Q_memset ( buffer , clear , sc - > sn . samples * sc - > sn . samplebits / 8 ) ;
2005-06-14 04:52:10 +00:00
sc - > Unlock ( sc , buffer ) ;
}
2004-08-23 00:15:46 +00:00
}
/*
= = = = = = = = = = = = = = = = =
S_StaticSound
= = = = = = = = = = = = = = = = =
*/
void S_StaticSound ( sfx_t * sfx , vec3_t origin , float vol , float attenuation )
{
channel_t * ss ;
sfxcache_t * scache ;
soundcardinfo_t * scard ;
if ( ! sfx )
return ;
for ( scard = sndcardinfo ; scard ; scard = scard - > next )
{
if ( scard - > total_chans = = MAX_CHANNELS )
{
Con_Printf ( " total_channels == MAX_CHANNELS \n " ) ;
continue ;
}
ss = & scard - > channel [ scard - > total_chans ] ;
scard - > total_chans + + ;
scache = S_LoadSound ( sfx ) ;
if ( ! scache )
return ;
if ( scache - > loopstart = = - 1 )
{
Con_Printf ( " Ambient sound %s not looped \n " , sfx - > name ) ;
2006-02-13 01:00:10 +00:00
scache - > loopstart = 0 ;
2004-08-23 00:15:46 +00:00
}
ss - > sfx = sfx ;
2010-11-06 23:05:29 +00:00
ss - > rate = 1 < < PITCHSHIFT ;
2004-08-23 00:15:46 +00:00
VectorCopy ( origin , ss - > origin ) ;
ss - > master_vol = vol ;
ss - > dist_mult = ( attenuation / 64 ) / sound_nominal_clip_dist ;
2010-11-06 23:05:29 +00:00
ss - > end = scard - > paintedtime + ( scache - > length < < PITCHSHIFT ) / ss - > rate ;
2004-11-23 00:18:51 +00:00
ss - > looping = true ;
2005-06-14 04:52:10 +00:00
2004-08-23 00:15:46 +00:00
SND_Spatialize ( scard , ss ) ;
}
}
//=============================================================================
2009-04-01 22:03:56 +00:00
void S_Music_Clear ( sfx_t * onlyifsample )
{
//stops the current BGM music
//calling this will trigger Media_NextTrack later
sfx_t * s ;
soundcardinfo_t * sc ;
int i ;
2010-11-06 23:05:29 +00:00
for ( i = MUSIC_FIRST ; i < MUSIC_STOP ; i + + )
2009-04-01 22:03:56 +00:00
{
for ( sc = sndcardinfo ; sc ; sc = sc - > next )
{
s = sc - > channel [ i ] . sfx ;
if ( ! s )
continue ;
if ( onlyifsample & & s ! = onlyifsample )
continue ;
sc - > channel [ i ] . end = 0 ;
sc - > channel [ i ] . sfx = NULL ;
if ( s )
if ( s - > decoder )
if ( ! S_IsPlayingSomewhere ( s ) ) //if we aint playing it elsewhere, free it compleatly.
{
s - > decoder - > abort ( s ) ;
if ( s - > cache . data )
Cache_Free ( & s - > cache ) ;
}
}
}
}
void S_Music_Seek ( float time )
{
soundcardinfo_t * sc ;
int i ;
2010-11-06 23:05:29 +00:00
for ( i = MUSIC_FIRST ; i < MUSIC_STOP ; i + + )
2009-04-01 22:03:56 +00:00
{
for ( sc = sndcardinfo ; sc ; sc = sc - > next )
{
2010-11-06 23:05:29 +00:00
sc - > channel [ i ] . pos + = sc - > sn . speed * time * sc - > channel [ i ] . rate ;
2009-04-01 22:03:56 +00:00
sc - > channel [ i ] . end + = sc - > sn . speed * time ;
if ( sc - > channel [ i ] . pos < 0 )
{ //clamp to the start of the track
sc - > channel [ i ] . end - = sc - > channel [ i ] . pos ;
sc - > channel [ i ] . pos = 0 ;
}
//if we seek over the end, ignore it. The sound playing code will spot that.
}
}
}
2004-08-23 00:15:46 +00:00
/*
= = = = = = = = = = = = = = = = = = =
S_UpdateAmbientSounds
= = = = = = = = = = = = = = = = = = =
*/
2009-04-02 22:25:54 +00:00
char * Media_NextTrack ( int musicchannelnum ) ;
2005-11-30 01:20:53 +00:00
mleaf_t * Q1BSP_LeafForPoint ( model_t * model , vec3_t p ) ;
2004-08-23 00:15:46 +00:00
void S_UpdateAmbientSounds ( soundcardinfo_t * sc )
{
mleaf_t * l ;
float vol ;
int ambient_channel ;
channel_t * chan ;
int i ;
if ( ! snd_ambient )
return ;
2010-11-06 23:05:29 +00:00
for ( i = MUSIC_FIRST ; i < MUSIC_STOP ; i + + )
2004-08-23 00:15:46 +00:00
{
chan = & sc - > channel [ i ] ;
if ( ! chan - > sfx )
{
2010-11-06 23:05:29 +00:00
char * nexttrack = Media_NextTrack ( i - MUSIC_FIRST ) ;
2004-08-23 00:15:46 +00:00
sfxcache_t * scache ;
sfx_t * newmusic ;
if ( nexttrack & & * nexttrack )
{
newmusic = S_PrecacheSound ( nexttrack ) ;
scache = S_LoadSound ( newmusic ) ;
if ( scache )
2005-06-14 04:52:10 +00:00
{
2004-08-23 00:15:46 +00:00
chan - > sfx = newmusic ;
2010-11-06 23:05:29 +00:00
chan - > rate = 1 < < PITCHSHIFT ;
2004-08-23 00:15:46 +00:00
chan - > pos = 0 ;
2010-11-06 23:05:29 +00:00
chan - > end = sc - > paintedtime + ( ( scache - > length + 1000 ) < < PITCHSHIFT ) / chan - > rate ;
2004-08-23 00:15:46 +00:00
chan - > vol [ 0 ] = chan - > vol [ 1 ] = chan - > vol [ 2 ] = chan - > vol [ 3 ] = chan - > vol [ 4 ] = chan - > vol [ 5 ] = chan - > master_vol = 100 ;
}
}
}
if ( chan - > sfx )
chan - > vol [ 0 ] = chan - > vol [ 1 ] = chan - > vol [ 2 ] = chan - > vol [ 3 ] = chan - > vol [ 4 ] = chan - > vol [ 5 ] = chan - > master_vol = ( 255 / volume . value ) * bgmvolume . value ;
}
// calc ambient sound levels
2005-08-26 22:56:51 +00:00
if ( ! cl . worldmodel | | cl . worldmodel - > type ! = mod_brush | | cl . worldmodel - > fromgame ! = fg_quake )
2004-08-23 00:15:46 +00:00
return ;
2005-08-26 22:56:51 +00:00
l = Q1BSP_LeafForPoint ( cl . worldmodel , listener_origin ) ;
2004-08-23 00:15:46 +00:00
if ( ! l | | ! ambient_level . value )
{
for ( ambient_channel = 0 ; ambient_channel < NUM_AMBIENTS ; ambient_channel + + )
2010-11-06 23:05:29 +00:00
sc - > channel [ AMBIENT_FIRST + ambient_channel ] . sfx = NULL ;
2004-08-23 00:15:46 +00:00
return ;
}
for ( ambient_channel = 0 ; ambient_channel < NUM_AMBIENTS ; ambient_channel + + )
{
2010-11-06 23:05:29 +00:00
chan = & sc - > channel [ AMBIENT_FIRST + ambient_channel ] ;
chan - > sfx = ambient_sfx [ AMBIENT_FIRST + ambient_channel ] ;
chan - > rate = 1 < < PITCHSHIFT ;
2004-08-23 00:15:46 +00:00
VectorCopy ( listener_origin , chan - > origin ) ;
2005-06-14 04:52:10 +00:00
2004-08-23 00:15:46 +00:00
vol = ambient_level . value * l - > ambient_sound_level [ ambient_channel ] ;
if ( vol < 8 )
vol = 0 ;
// don't adjust volume too fast
if ( chan - > master_vol < vol )
{
chan - > master_vol + = host_frametime * ambient_fade . value ;
if ( chan - > master_vol > vol )
chan - > master_vol = vol ;
}
else if ( chan - > master_vol > vol )
{
chan - > master_vol - = host_frametime * ambient_fade . value ;
if ( chan - > master_vol < vol )
chan - > master_vol = vol ;
}
2005-06-14 04:52:10 +00:00
2004-08-23 00:15:46 +00:00
chan - > vol [ 0 ] = chan - > vol [ 1 ] = chan - > vol [ 2 ] = chan - > vol [ 3 ] = chan - > vol [ 4 ] = chan - > vol [ 5 ] = chan - > master_vol ;
}
}
/*
= = = = = = = = = = = =
S_Update
Called once each time through the main loop
= = = = = = = = = = = =
*/
2010-11-06 23:05:29 +00:00
void S_UpdateListener ( vec3_t origin , vec3_t forward , vec3_t right , vec3_t up )
2004-08-23 00:15:46 +00:00
{
2005-02-06 02:47:36 +00:00
VectorCopy ( origin , listener_origin ) ;
VectorCopy ( forward , listener_forward ) ;
VectorCopy ( right , listener_right ) ;
VectorCopy ( up , listener_up ) ;
2004-08-23 00:15:46 +00:00
}
2009-04-01 22:03:56 +00:00
void S_GetListenerInfo ( float * origin , float * forward , float * right , float * up )
{
VectorCopy ( listener_origin , origin ) ;
VectorCopy ( listener_forward , forward ) ;
VectorCopy ( listener_right , right ) ;
VectorCopy ( listener_up , up ) ;
}
2005-02-06 02:47:36 +00:00
void S_UpdateCard ( soundcardinfo_t * sc )
2004-08-23 00:15:46 +00:00
{
int i , j ;
int total ;
channel_t * ch ;
channel_t * combine ;
2004-10-03 22:52:02 +00:00
if ( ! sound_started )
2004-08-23 00:15:46 +00:00
return ;
2004-10-03 22:52:02 +00:00
if ( ( snd_blocked > 0 ) )
{
if ( ! sc - > inactive_sound )
return ;
}
2005-06-14 04:52:10 +00:00
2010-03-14 14:35:56 +00:00
# ifdef AVAIL_OPENAL
if ( sc - > openal = = 1 )
{
OpenAL_Update_Listener ( listener_origin , listener_forward , listener_right , listener_up ) ;
return ;
}
# endif
2004-08-23 00:15:46 +00:00
// update general area ambient sound sources
S_UpdateAmbientSounds ( sc ) ;
combine = NULL ;
2005-06-14 04:52:10 +00:00
// update spatialization for static and dynamic sounds
2010-11-06 23:05:29 +00:00
ch = sc - > channel + DYNAMIC_FIRST ;
for ( i = DYNAMIC_FIRST ; i < sc - > total_chans ; i + + , ch + + )
2004-08-23 00:15:46 +00:00
{
if ( ! ch - > sfx )
continue ;
SND_Spatialize ( sc , ch ) ; // respatialize channel
if ( ! ch - > vol [ 0 ] & & ! ch - > vol [ 1 ] & & ! ch - > vol [ 2 ] & & ! ch - > vol [ 3 ] & & ! ch - > vol [ 4 ] & & ! ch - > vol [ 5 ] )
continue ;
// try to combine static sounds with a previous channel of the same
// sound effect so we don't mix five torches every frame
2005-06-14 04:52:10 +00:00
2010-11-06 23:05:29 +00:00
if ( i > = DYNAMIC_STOP )
2004-08-23 00:15:46 +00:00
{
// see if it can just use the last one
if ( combine & & combine - > sfx = = ch - > sfx )
{
combine - > vol [ 0 ] + = ch - > vol [ 0 ] ;
combine - > vol [ 1 ] + = ch - > vol [ 1 ] ;
combine - > vol [ 2 ] + = ch - > vol [ 2 ] ;
combine - > vol [ 3 ] + = ch - > vol [ 3 ] ;
combine - > vol [ 4 ] + = ch - > vol [ 4 ] ;
combine - > vol [ 5 ] + = ch - > vol [ 5 ] ;
ch - > vol [ 0 ] = ch - > vol [ 1 ] = ch - > vol [ 2 ] = ch - > vol [ 3 ] = ch - > vol [ 4 ] = ch - > vol [ 5 ] = 0 ;
continue ;
}
// search for one
2010-11-06 23:05:29 +00:00
combine = sc - > channel + DYNAMIC_FIRST ;
for ( j = DYNAMIC_FIRST ; j < i ; j + + , combine + + )
2004-08-23 00:15:46 +00:00
if ( combine - > sfx = = ch - > sfx )
break ;
2005-06-14 04:52:10 +00:00
2004-08-23 00:15:46 +00:00
if ( j = = sc - > total_chans )
{
combine = NULL ;
}
else
{
if ( combine ! = ch )
{
combine - > vol [ 0 ] + = ch - > vol [ 0 ] ;
combine - > vol [ 1 ] + = ch - > vol [ 1 ] ;
combine - > vol [ 2 ] + = ch - > vol [ 2 ] ;
combine - > vol [ 3 ] + = ch - > vol [ 3 ] ;
combine - > vol [ 4 ] + = ch - > vol [ 4 ] ;
combine - > vol [ 5 ] + = ch - > vol [ 5 ] ;
ch - > vol [ 0 ] = ch - > vol [ 1 ] = ch - > vol [ 2 ] = ch - > vol [ 3 ] = ch - > vol [ 4 ] = ch - > vol [ 5 ] = 0 ;
}
continue ;
}
}
}
//
// debugging output
//
2009-11-04 21:16:50 +00:00
if ( snd_show . ival )
2004-08-23 00:15:46 +00:00
{
total = 0 ;
ch = sc - > channel ;
for ( i = 0 ; i < sc - > total_chans ; i + + , ch + + )
if ( ch - > sfx & & ( ch - > vol [ 0 ] | | ch - > vol [ 1 ] ) )
{
// Con_Printf ("%i, %i %i %i %i %i %i %s\n", i, ch->vol[0], ch->vol[1], ch->vol[2], ch->vol[3], ch->vol[4], ch->vol[5], ch->sfx->name);
total + + ;
}
2005-06-14 04:52:10 +00:00
2004-08-23 00:15:46 +00:00
Con_Printf ( " ----(%i)---- \n " , total ) ;
}
2005-06-14 04:52:10 +00:00
// mix some sound
2004-08-23 00:15:46 +00:00
S_Update_ ( sc ) ;
}
void GetSoundtime ( soundcardinfo_t * sc )
{
2005-06-14 04:52:10 +00:00
int samplepos ;
2004-08-23 00:15:46 +00:00
int fullsamples ;
2005-06-14 04:52:10 +00:00
2004-08-23 00:15:46 +00:00
fullsamples = sc - > sn . samples / sc - > sn . numchannels ;
// it is possible to miscount buffers if it has wrapped twice between
// calls to S_Update. Oh well.
2005-06-14 04:52:10 +00:00
samplepos = sc - > GetDMAPos ( sc ) ;
2004-08-23 00:15:46 +00:00
if ( samplepos < sc - > oldsamplepos )
{
sc - > buffers + + ; // buffer wrapped
2005-06-14 04:52:10 +00:00
2004-08-23 00:15:46 +00:00
if ( sc - > paintedtime > 0x40000000 )
{ // time to chop things off to avoid 32 bit limits
sc - > buffers = 0 ;
sc - > paintedtime = fullsamples ;
S_StopAllSounds ( true ) ;
}
}
sc - > oldsamplepos = samplepos ;
soundtime = sc - > buffers * fullsamples + samplepos / sc - > sn . numchannels ;
}
2010-11-06 23:05:29 +00:00
void S_Update ( void )
{
soundcardinfo_t * sc ;
S_RunCapture ( ) ;
for ( sc = sndcardinfo ; sc ; sc = sc - > next )
S_UpdateCard ( sc ) ;
}
2004-08-23 00:15:46 +00:00
void S_ExtraUpdate ( void )
{
soundcardinfo_t * sc ;
2005-02-06 02:47:36 +00:00
if ( ! sound_started )
return ;
2004-08-23 00:15:46 +00:00
# ifdef _WIN32
IN_Accumulate ( ) ;
# endif
2009-11-04 21:16:50 +00:00
if ( snd_noextraupdate . ival )
2004-08-23 00:15:46 +00:00
return ; // don't pollute timings
2005-08-03 23:14:59 +00:00
S_RunCapture ( ) ;
2004-08-23 00:15:46 +00:00
for ( sc = sndcardinfo ; sc ; sc = sc - > next )
S_Update_ ( sc ) ;
}
void S_Update_ ( soundcardinfo_t * sc )
{
unsigned endtime ;
int samps ;
2005-02-06 02:47:36 +00:00
2004-12-24 08:45:56 +00:00
if ( sc - > selfpainting )
return ;
2005-02-06 02:47:36 +00:00
if ( ( snd_blocked > 0 ) )
{
if ( ! sc - > inactive_sound )
return ;
}
2004-08-23 00:15:46 +00:00
// Updates DMA time
GetSoundtime ( sc ) ;
// check to make sure that we haven't overshot
if ( sc - > paintedtime < soundtime )
{
//Con_Printf ("S_Update_ : overflow\n");
sc - > paintedtime = soundtime ;
}
// mix ahead of current position
2006-04-09 01:59:07 +00:00
endtime = soundtime + ( int ) ( _snd_mixahead . value * sc - > sn . speed ) ;
2004-08-23 00:15:46 +00:00
// samps = shm->samples >> (shm->numchannels-1);
samps = sc - > sn . samples / sc - > sn . numchannels ;
if ( endtime - soundtime > samps )
endtime = soundtime + samps ;
2005-06-14 04:52:10 +00:00
if ( sc - > Restore )
sc - > Restore ( sc ) ;
2004-08-23 00:15:46 +00:00
S_PaintChannels ( sc , endtime ) ;
2005-06-14 04:52:10 +00:00
sc - > Submit ( sc ) ;
2004-08-23 00:15:46 +00:00
}
/*
= = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =
console functions
= = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =
*/
void S_Play ( void )
{
2004-10-06 23:44:39 +00:00
// static int hash=345;
2004-08-23 00:15:46 +00:00
int i ;
char name [ 256 ] ;
sfx_t * sfx ;
2005-06-14 04:52:10 +00:00
2004-08-23 00:15:46 +00:00
i = 1 ;
while ( i < Cmd_Argc ( ) )
{
if ( ! Q_strrchr ( Cmd_Argv ( i ) , ' . ' ) )
{
2006-04-21 17:23:35 +00:00
Q_strncpyz ( name , Cmd_Argv ( i ) , sizeof ( name ) - 4 ) ;
2004-08-23 00:15:46 +00:00
Q_strcat ( name , " .wav " ) ;
}
else
2006-04-21 17:23:35 +00:00
Q_strncpyz ( name , Cmd_Argv ( i ) , sizeof ( name ) ) ;
2004-08-23 00:15:46 +00:00
sfx = S_PrecacheSound ( name ) ;
2010-11-06 23:05:29 +00:00
S_StartSound ( cl . playernum [ 0 ] + 1 , - 1 , sfx , vec3_origin , 1.0 , 0.0 , 0 ) ;
2004-10-07 00:23:06 +00:00
// hash++;
2004-08-23 00:15:46 +00:00
i + + ;
}
}
void S_PlayVol ( void )
{
2004-10-06 23:44:39 +00:00
// static int hash=543;
2004-08-23 00:15:46 +00:00
int i ;
float vol ;
char name [ 256 ] ;
sfx_t * sfx ;
2005-06-14 04:52:10 +00:00
2004-08-23 00:15:46 +00:00
i = 1 ;
while ( i < Cmd_Argc ( ) )
{
if ( ! Q_strrchr ( Cmd_Argv ( i ) , ' . ' ) )
{
2006-04-21 16:25:25 +00:00
Q_strncpy ( name , Cmd_Argv ( i ) , sizeof ( name ) - 4 ) ;
2004-08-23 00:15:46 +00:00
Q_strcat ( name , " .wav " ) ;
}
else
2006-04-21 16:25:25 +00:00
Q_strncpy ( name , Cmd_Argv ( i ) , sizeof ( name ) ) ;
2004-08-23 00:15:46 +00:00
sfx = S_PrecacheSound ( name ) ;
vol = Q_atof ( Cmd_Argv ( i + 1 ) ) ;
2010-11-06 23:05:29 +00:00
S_StartSound ( cl . playernum [ 0 ] + 1 , - 1 , sfx , vec3_origin , vol , 0.0 , 0 ) ;
2004-10-07 00:23:06 +00:00
// hash;
2004-08-23 00:15:46 +00:00
i + = 2 ;
}
}
void S_SoundList ( void )
{
int i ;
sfx_t * sfx ;
sfxcache_t * sc ;
int size , total ;
total = 0 ;
for ( sfx = known_sfx , i = 0 ; i < num_sfx ; i + + , sfx + + )
{
sc = Cache_Check ( & sfx - > cache ) ;
if ( ! sc )
continue ;
2006-01-28 06:41:20 +00:00
size = sc - > length * sc - > width * ( sc - > numchannels ) ;
2004-08-23 00:15:46 +00:00
total + = size ;
if ( sc - > loopstart > = 0 )
Con_Printf ( " L " ) ;
else
Con_Printf ( " " ) ;
Con_Printf ( " (%2db) %6i : %s \n " , sc - > width * 8 , size , sfx - > name ) ;
}
Con_Printf ( " Total resident: %i \n " , total ) ;
}
void S_LocalSound ( char * sound )
{
sfx_t * sfx ;
2009-11-04 21:16:50 +00:00
if ( nosound . ival )
2004-08-23 00:15:46 +00:00
return ;
if ( ! sound_started )
return ;
sfx = S_PrecacheSound ( sound ) ;
if ( ! sfx )
{
Con_Printf ( " S_LocalSound: can't cache %s \n " , sound ) ;
return ;
}
2010-11-06 23:05:29 +00:00
S_StartSound ( - 1 , - 1 , sfx , vec3_origin , 1 , 1 , 0 ) ;
2004-08-23 00:15:46 +00:00
}
void S_ClearPrecache ( void )
{
}
void S_BeginPrecaching ( void )
{
}
void S_EndPrecaching ( void )
{
}
typedef struct {
qboolean inuse ;
int id ;
sfx_t sfx ;
sfxcache_t * sfxcache ;
} streaming_t ;
# define MAX_RAW_SOURCES (MAX_CLIENTS+1)
streaming_t s_streamers [ MAX_RAW_SOURCES ] ;
/*
qboolean S_IsPlayingSomewhere ( sfx_t * s )
{
soundcardinfo_t * si ;
int i ;
for ( si = sndcardinfo ; si ; si = si - > next )
{
for ( i = 0 ; i < MAX_CHANNELS ; i + + )
if ( si - > channel [ i ] . sfx = = s )
return true ;
}
return false ;
} */
# undef free
2005-07-14 01:57:34 +00:00
void S_ClearRaw ( void )
{
memset ( s_streamers , 0 , sizeof ( s_streamers ) ) ;
}
2004-08-23 00:15:46 +00:00
//streaming audio. //this is useful when there is one source, and the sound is to be played with no attenuation
void S_RawAudio ( int sourceid , qbyte * data , int speed , int samples , int channels , int width )
{
soundcardinfo_t * si ;
int i ;
int prepadl ;
2005-07-14 01:57:34 +00:00
int oldlength ;
2004-08-23 00:15:46 +00:00
int spare ;
2005-08-12 19:37:24 +00:00
int outsamples ;
2006-06-04 01:43:52 +00:00
double speedfactor ;
2004-08-23 00:15:46 +00:00
sfxcache_t * newcache ;
streaming_t * s , * free = NULL ;
for ( s = s_streamers , i = 0 ; i < MAX_RAW_SOURCES ; i + + , s + + )
{
if ( ! s - > inuse )
{
free = s ;
continue ;
}
if ( s - > id = = sourceid )
break ;
}
2005-07-14 01:57:34 +00:00
if ( ! data )
{
if ( i = = MAX_RAW_SOURCES )
return ; //wierd, it wasn't even playing.
s - > sfxcache - > loopstart = - 1 ; //stop mixing it
s - > inuse = false ;
for ( si = sndcardinfo ; si ; si = si - > next )
for ( i = 0 ; i < MAX_CHANNELS ; i + + )
if ( si - > channel [ i ] . sfx = = & s - > sfx )
{
si - > channel [ i ] . sfx = NULL ;
break ;
}
BZ_Free ( s - > sfxcache ) ;
return ;
}
2004-08-23 00:15:46 +00:00
if ( i = = MAX_RAW_SOURCES ) //whoops.
{
if ( ! free )
{
Con_Printf ( " No free audio streams \n " ) ;
return ;
}
s = free ;
free - > id = sourceid ;
free - > inuse = true ;
free - > sfx . cache . fake = true ;
strcpy ( free - > sfx . name , " " ) ;
free - > sfxcache = BZ_Malloc ( sizeof ( sfxcache_t ) ) ;
free - > sfx . cache . data = free - > sfxcache ;
free - > sfxcache - > speed = snd_speed ;
2006-01-28 06:41:20 +00:00
free - > sfxcache - > numchannels = channels ;
2004-08-23 00:15:46 +00:00
free - > sfxcache - > width = width ;
free - > sfxcache - > loopstart = - 1 ;
free - > sfxcache - > length = 0 ;
2005-07-14 01:57:34 +00:00
// Con_Printf("Added new raw stream\n");
2004-08-23 00:15:46 +00:00
}
2006-01-28 06:41:20 +00:00
if ( s - > sfxcache - > width ! = width | | s - > sfxcache - > numchannels ! = channels | | s - > sfxcache - > speed ! = snd_speed )
2004-08-23 00:15:46 +00:00
{
s - > sfxcache - > width = width ;
2006-01-28 06:41:20 +00:00
s - > sfxcache - > numchannels = channels ;
2004-08-23 00:15:46 +00:00
s - > sfxcache - > speed = snd_speed ;
s - > sfxcache - > length = 0 ;
2005-07-14 01:57:34 +00:00
// Con_Printf("Restarting raw stream\n");
2004-08-23 00:15:46 +00:00
}
2006-06-04 16:02:03 +00:00
speedfactor = ( double ) speed / snd_speed ;
2005-08-12 19:37:24 +00:00
outsamples = samples / speedfactor ;
2005-07-14 01:57:34 +00:00
oldlength = s - > sfxcache - > length ;
prepadl = 0x7fffffff ;
2004-08-23 00:15:46 +00:00
for ( si = sndcardinfo ; si ; si = si - > next ) //make sure all cards are playing, and that we still get a prepad if just one is.
{
2006-05-28 21:56:04 +00:00
for ( i = 0 ; i < si - > total_chans ; i + + )
2004-08-23 00:15:46 +00:00
if ( si - > channel [ i ] . sfx = = & s - > sfx )
{
2005-07-14 01:57:34 +00:00
if ( prepadl > si - > channel [ i ] . pos )
2004-08-23 00:15:46 +00:00
prepadl = si - > channel [ i ] . pos ;
break ;
}
}
2005-07-14 01:57:34 +00:00
if ( prepadl = = 0x7fffffff )
2004-08-23 00:15:46 +00:00
{
2009-11-04 21:16:50 +00:00
if ( snd_show . ival )
2005-07-14 01:57:34 +00:00
Con_Printf ( " Wasn't playing \n " ) ;
2004-08-23 00:15:46 +00:00
prepadl = 0 ;
spare = s - > sfxcache - > length ;
if ( spare > snd_speed )
2005-07-14 01:57:34 +00:00
{
2006-03-11 03:12:10 +00:00
Con_DPrintf ( " Sacrificed raw sound stream \n " ) ;
2004-08-23 00:15:46 +00:00
spare = 0 ; //too far out. sacrifice it all
2005-07-14 01:57:34 +00:00
}
2004-08-23 00:15:46 +00:00
}
else
{
spare = s - > sfxcache - > length - prepadl ;
2005-07-14 01:57:34 +00:00
if ( spare < 0 ) //remaining samples since last time
2004-08-23 00:15:46 +00:00
spare = 0 ;
2005-07-14 01:57:34 +00:00
2005-08-12 19:37:24 +00:00
if ( s - > sfxcache - > length > snd_speed * 2 ) // more than 2 seconds of sound
2005-07-14 01:57:34 +00:00
{
2006-03-11 03:12:10 +00:00
Con_DPrintf ( " Sacrificed raw sound stream \n " ) ;
2005-07-14 01:57:34 +00:00
spare = 0 ; //too far out. sacrifice it all
}
2004-08-23 00:15:46 +00:00
}
2006-01-28 06:41:20 +00:00
newcache = BZ_Malloc ( sizeof ( sfxcache_t ) + ( spare + outsamples ) * ( s - > sfxcache - > numchannels ) * s - > sfxcache - > width ) ;
2004-08-23 00:15:46 +00:00
memcpy ( newcache , s - > sfxcache , sizeof ( sfxcache_t ) ) ;
2006-01-28 06:41:20 +00:00
memcpy ( newcache - > data , s - > sfxcache - > data + prepadl * ( s - > sfxcache - > numchannels ) * s - > sfxcache - > width , spare * ( s - > sfxcache - > numchannels ) * s - > sfxcache - > width ) ;
2004-08-23 00:15:46 +00:00
BZ_Free ( s - > sfxcache ) ;
s - > sfxcache = s - > sfx . cache . data = newcache ;
2005-08-12 19:37:24 +00:00
newcache - > length = spare + outsamples ;
2004-08-23 00:15:46 +00:00
{
2006-06-04 01:43:52 +00:00
extern cvar_t snd_linearresample_stream ;
short * outpos = ( short * ) ( newcache - > data + spare * ( s - > sfxcache - > numchannels ) * s - > sfxcache - > width ) ;
SND_ResampleStream ( data ,
speed ,
width ,
channels ,
samples ,
outpos ,
snd_speed ,
s - > sfxcache - > width ,
s - > sfxcache - > numchannels ,
2009-11-04 21:16:50 +00:00
snd_linearresample_stream . ival ) ;
2004-08-23 00:15:46 +00:00
}
2005-07-14 01:57:34 +00:00
s - > sfxcache - > loopstart = s - > sfxcache - > length ;
2004-08-23 00:15:46 +00:00
for ( si = sndcardinfo ; si ; si = si - > next )
{
2006-05-28 21:56:04 +00:00
for ( i = 0 ; i < si - > total_chans ; i + + )
2004-08-23 00:15:46 +00:00
if ( si - > channel [ i ] . sfx = = & s - > sfx )
{
2010-11-06 23:05:29 +00:00
si - > channel [ i ] . pos - = prepadl * si - > channel [ i ] . rate ;
2005-07-14 01:57:34 +00:00
// si->channel[i].end -= prepadl;
2005-08-12 19:37:24 +00:00
si - > channel [ i ] . end + = outsamples ;
2005-07-14 01:57:34 +00:00
if ( si - > channel [ i ] . end < si - > paintedtime )
{
si - > channel [ i ] . pos = 0 ;
si - > channel [ i ] . end = si - > paintedtime + s - > sfxcache - > length ;
}
2004-08-23 00:15:46 +00:00
break ;
}
2006-05-28 21:56:04 +00:00
if ( i = = si - > total_chans ) //this one wasn't playing.
2005-07-14 01:57:34 +00:00
{
2010-11-06 23:05:29 +00:00
S_StartSoundCard ( si , - 1 , 0 , & s - > sfx , r_origin , 1 , 32767 , 500 , 0 ) ;
2005-07-14 01:57:34 +00:00
// Con_Printf("Restarted\n");
}
2004-08-23 00:15:46 +00:00
}
2005-07-14 01:57:34 +00:00
// Con_Printf("Stripped %i, added %i (length %i)\n", prepadl, samples, s->sfxcache->length);
2004-08-23 00:15:46 +00:00
}