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
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE .
See the GNU General Public License for more details .
You should have received a copy of the GNU General Public License
along with this program ; if not , write to the Free Software
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"
2005-02-28 07:16:19 +00:00
# ifndef __CYGWIN__
2004-08-23 00:15:46 +00:00
# ifdef _WIN32
# include "winquake.h"
# endif
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
// =======================================================================
int snd_blocked = 0 ;
static qboolean snd_ambient = 1 ;
qboolean snd_initialized = false ;
int snd_speed ;
qboolean snd_multipledevices = false ;
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 ;
cvar_t bgmvolume = { " musicvolume " , " 0 " , NULL , CVAR_ARCHIVE } ;
cvar_t volume = { " volume " , " 0.7 " , NULL , CVAR_ARCHIVE } ;
cvar_t nosound = { " nosound " , " 0 " } ;
cvar_t precache = { " precache " , " 1 " } ;
cvar_t loadas8bit = { " loadas8bit " , " 0 " } ;
cvar_t bgmbuffer = { " bgmbuffer " , " 4096 " } ;
cvar_t ambient_level = { " ambient_level " , " 0.3 " } ;
cvar_t ambient_fade = { " ambient_fade " , " 100 " } ;
cvar_t snd_noextraupdate = { " snd_noextraupdate " , " 0 " } ;
cvar_t snd_show = { " snd_show " , " 0 " } ;
cvar_t snd_khz = { " snd_khz " , " 11 " } ;
2004-10-03 22:52:02 +00:00
cvar_t snd_inactive = { " snd_inactive " , " 0 " } ; //set if you want sound even when tabbed out.
2004-08-23 00:15:46 +00:00
cvar_t _snd_mixahead = { " _snd_mixahead " , " 0.2 " , NULL , CVAR_ARCHIVE } ;
cvar_t snd_leftisright = { " snd_leftisright " , " 0 " , NULL , CVAR_ARCHIVE } ;
cvar_t snd_eax = { " snd_eax " , " 0 " } ;
cvar_t snd_speakers = { " snd_numspeakers " , " 2 " } ;
cvar_t snd_capture = { " snd_capture " , " 0 " } ;
// ====================================================================
// User-setable variables
// ====================================================================
//
// Fake dma is a synchronous faking of the DMA progress used for
// isolating performance in the renderer. The fakedma_updates is
// number of times S_Update() is called per second.
//
qboolean fakedma = false ;
int fakedma_updates = 15 ;
void S_AmbientOff ( void )
{
snd_ambient = false ;
}
void S_AmbientOn ( void )
{
snd_ambient = true ;
}
void S_SoundInfo_f ( void )
{
soundcardinfo_t * sc ;
if ( ! sound_started )
{
Con_Printf ( " sound system not started \n " ) ;
return ;
}
if ( ! sndcardinfo )
{
Con_Print ( " No sound cards \n " ) ;
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 submission_chunk \n " , sc - > sn . submission_chunk ) ;
Con_Printf ( " %5d speed \n " , sc - > sn . speed ) ;
Con_Printf ( " 0x%x dma buffer \n " , sc - > sn . buffer ) ;
Con_Printf ( " %5d total_channels \n " , sc - > total_chans ) ;
}
}
/*
= = = = = = = = = = = = = = = =
S_Startup
= = = = = = = = = = = = = = = =
*/
void S_Startup ( void )
{
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 ;
2004-08-23 00:15:46 +00:00
if ( ! fakedma )
{
# if defined(_WIN32) && !defined(NODIRECTX)
extern int aimedforguid ; //restart directsound guid aims.
aimedforguid = 0 ;
# endif
for ( ; ; )
{
sc = Z_Malloc ( sizeof ( soundcardinfo_t ) ) ;
2004-09-20 23:25:38 +00:00
if ( snd_khz . value > = 45 )
2004-08-23 00:15:46 +00:00
sc - > sn . speed = 48000 ;
2004-09-20 23:25:38 +00:00
else if ( snd_khz . value > = 30 ) //set by a slider
2004-08-23 00:15:46 +00:00
sc - > sn . speed = 44100 ;
2004-09-20 23:25:38 +00:00
else if ( snd_khz . value > = 20 )
2004-08-23 00:15:46 +00:00
sc - > sn . speed = 22050 ;
else
sc - > sn . speed = 11025 ;
rc = SNDDMA_Init ( sc ) ;
if ( ! rc ) //error stop
{
# ifndef _WIN32
Con_Printf ( " S_Startup: SNDDMA_Init failed. \n " ) ;
# endif
Z_Free ( sc ) ;
break ;
}
if ( rc = = 2 ) //silently stop (no more cards)
{
Z_Free ( sc ) ;
break ;
}
2004-09-20 23:25:38 +00:00
if ( sc - > sn . numchannels < 3 )
2004-08-23 00:15:46 +00:00
{
sc - > pitch [ 0 ] = 0 ;
sc - > pitch [ 1 ] = 0 ;
sc - > dist [ 0 ] = 1 ;
sc - > dist [ 1 ] = 1 ;
sc - > yaw [ 0 ] = 270 ;
sc - > yaw [ 1 ] = 90 ;
}
2004-09-20 23:25:38 +00:00
else if ( sc - > sn . numchannels < 5 )
2004-08-23 00:15:46 +00:00
{
sc - > pitch [ 0 ] = 0 ;
sc - > pitch [ 1 ] = 0 ;
sc - > pitch [ 2 ] = 0 ;
sc - > pitch [ 3 ] = 0 ;
sc - > dist [ 0 ] = 1 ;
sc - > dist [ 1 ] = 1 ;
sc - > dist [ 2 ] = 1 ;
sc - > dist [ 3 ] = 1 ;
sc - > yaw [ 0 ] = 315 ;
sc - > yaw [ 1 ] = 45 ;
sc - > yaw [ 2 ] = 225 ;
sc - > yaw [ 3 ] = 135 ;
}
else
{
sc - > pitch [ 0 ] = 0 ;
sc - > pitch [ 1 ] = 0 ;
sc - > pitch [ 2 ] = 0 ;
sc - > pitch [ 3 ] = 0 ;
sc - > pitch [ 4 ] = 0 ;
sc - > pitch [ 5 ] = 0 ;
sc - > dist [ 0 ] = 1 ;
sc - > dist [ 1 ] = 1 ;
sc - > dist [ 2 ] = 1 ;
sc - > dist [ 3 ] = 1 ;
sc - > dist [ 4 ] = 1 ;
sc - > dist [ 5 ] = 1 ;
sc - > yaw [ 0 ] = 315 ;
sc - > yaw [ 1 ] = 45 ;
sc - > yaw [ 2 ] = 0 ;
sc - > yaw [ 3 ] = 0 ;
sc - > yaw [ 4 ] = 225 ;
sc - > yaw [ 5 ] = 135 ;
}
if ( sndcardinfo )
{ //if the sample speeds of multiple soundcards do not match, it'll fail.
if ( sc - > sn . speed ! = sc - > sn . speed )
{
if ( ! warningmessage )
{
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 ;
}
Z_Free ( sc ) ;
continue ;
}
}
else
snd_speed = sc - > sn . speed ;
sc - > next = sndcardinfo ;
sndcardinfo = sc ;
}
}
sound_started = 1 ;
}
void S_Restart_f ( void )
{
extern qboolean snd_firsttime ;
Cache_Flush ( ) ; //forget the old sounds.
2004-12-02 07:09:14 +00:00
if ( COM_CheckParm ( " -nosound " ) )
return ;
2004-08-23 00:15:46 +00:00
S_StopAllSounds ( true ) ;
S_Shutdown ( ) ;
sound_started = 0 ;
snd_firsttime = true ;
S_Startup ( ) ;
ambient_sfx [ AMBIENT_WATER ] = S_PrecacheSound ( " ambience/water1.wav " ) ;
ambient_sfx [ AMBIENT_SKY ] = S_PrecacheSound ( " ambience/wind2.wav " ) ;
S_StopAllSounds ( true ) ;
}
void S_Control_f ( void )
{
int i ;
char * command ;
if ( Cmd_Argc ( ) < 2 )
return ;
command = Cmd_Argv ( 1 ) ;
if ( ! Q_strcasecmp ( command , " off " ) )
{
Cache_Flush ( ) ; //forget the old sounds.
S_StopAllSounds ( true ) ;
S_Shutdown ( ) ;
sound_started = 0 ;
}
else if ( ! Q_strcasecmp ( command , " multi " ) | | ! Q_strcasecmp ( command , " multiple " ) )
{
if ( ! Q_strcasecmp ( Cmd_Argv ( 2 ) , " off " ) )
{
if ( snd_multipledevices )
{
snd_multipledevices = false ;
S_Restart_f ( ) ;
}
}
else if ( ! snd_multipledevices )
{
snd_multipledevices = true ;
S_Restart_f ( ) ;
}
return ;
}
if ( ! Q_strcasecmp ( command , " single " ) )
{
snd_multipledevices = false ;
S_Restart_f ( ) ;
return ;
}
if ( ! Q_strcasecmp ( command , " rate " ) | | ! Q_strcasecmp ( command , " speed " ) )
{
Cvar_SetValue ( & snd_khz , atof ( Cmd_Argv ( 2 ) ) / 1000 ) ;
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 + + )
{
sc - > yaw [ i ] = 0 ;
sc - > pitch [ i ] = 0 ; //point forwards
sc - > dist [ i ] = 1 ;
}
}
else if ( ! Q_strcasecmp ( command , " standard " ) | | ! Q_strcasecmp ( command , " stereo " ) )
{
for ( i = 0 ; i < MAXSOUNDCHANNELS ; i + + )
{
if ( i & 1 )
sc - > yaw [ i ] = 90 ; //right
else
sc - > yaw [ i ] = 270 ; //left
sc - > pitch [ i ] = 0 ;
sc - > dist [ i ] = 1 ;
}
}
else if ( ! Q_strcasecmp ( command , " swap " ) )
{
for ( i = 0 ; i < MAXSOUNDCHANNELS ; i + + )
{
if ( i & 1 )
sc - > yaw [ i ] = 270 ; //left
else
sc - > yaw [ i ] = 90 ; //right
sc - > pitch [ i ] = 0 ;
sc - > dist [ i ] = 1 ;
}
}
else if ( ! Q_strcasecmp ( command , " front " ) )
{
for ( i = 0 ; i < MAXSOUNDCHANNELS ; i + + )
{
if ( i & 1 )
sc - > yaw [ i ] = 45 ; //front right
else
sc - > yaw [ i ] = 315 ; //front left
sc - > pitch [ i ] = 0 ;
sc - > dist [ i ] = 1 ;
}
}
else if ( ! Q_strcasecmp ( command , " back " ) )
{
for ( i = 0 ; i < MAXSOUNDCHANNELS ; i + + )
{
if ( i & 1 )
sc - > yaw [ i ] = 180 - 45 ; //behind right
else
sc - > yaw [ i ] = 180 + 45 ; //behind left
sc - > pitch [ i ] = 0 ;
sc - > dist [ i ] = 1 ;
}
}
return ;
}
}
/*
= = = = = = = = = = = = = = = =
S_Init
= = = = = = = = = = = = = = = =
*/
void S_Init ( void )
{
int p ;
if ( snd_initialized ) //whoops
{
Con_Printf ( " Sound is already initialized \n " ) ;
return ;
}
2005-05-08 06:03:15 +00:00
Con_DPrintf ( " \n Sound Initialization \n " ) ;
2004-08-23 00:15:46 +00:00
2004-12-02 07:09:14 +00:00
if ( COM_CheckParm ( " -nosound " ) )
{
Cvar_Register ( & nosound , " Sound controls " ) ;
Cvar_ForceSet ( & nosound , " 1 " ) ;
nosound . flags | = CVAR_NOSET ;
return ;
}
2004-08-23 00:15:46 +00:00
// if (COM_CheckParm("-simsound"))
// fakedma = true;
if ( COM_CheckParm ( " -nomultipledevices " ) | | COM_CheckParm ( " -singlesound " ) )
snd_multipledevices = false ;
if ( COM_CheckParm ( " -multisound " ) )
snd_multipledevices = true ;
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 " ) ;
}
Cmd_AddCommand ( " play " , S_Play ) ;
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 " ) ;
Cvar_Register ( & snd_capture , " Sound controls " ) ;
2004-10-03 22:52:02 +00:00
Cvar_Register ( & snd_inactive , " Sound controls " ) ;
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 ;
SND_InitScaletable ( ) ;
known_sfx = Hunk_AllocName ( MAX_SFX * sizeof ( sfx_t ) , " sfx_t " ) ;
num_sfx = 0 ;
// create a piece of DMA memory
/* if (fakedma)
{
cursndcard = Z_Malloc ( sizeof ( * sndcardinfo ) ) ;
cursndcard - > next = sndcardinfo ;
sndcardinfo = cursndcard ;
shm = ( void * ) Hunk_AllocName ( sizeof ( * shm ) , " shm " ) ;
shm - > splitbuffer = 0 ;
shm - > samplebits = 16 ;
shm - > speed = 22050 ;
shm - > numchannels = 2 ;
shm - > samples = 44100 ;
shm - > samplepos = 0 ;
shm - > soundalive = true ;
shm - > gamealive = true ;
shm - > submission_chunk = 1 ;
shm - > buffer = Hunk_AllocName ( 1 < < 16 , " shmbuf " ) ;
}
*/
if ( sndcardinfo )
Con_SafePrintf ( " Sound sampling rate: %i \n " , sndcardinfo - > sn . speed ) ;
// provides a tick sound until washed clean
// if (shm->buffer)
// shm->buffer[4] = shm->buffer[5] = 0x7f; // force a pop for debugging
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 )
{
if ( ! fakedma )
{
SNDDMA_Shutdown ( sc ) ;
}
}
void S_Shutdown ( void )
{
soundcardinfo_t * sc , * next ;
for ( sc = sndcardinfo ; sc ; sc = next )
{
next = sc - > next ;
S_ShutdownCard ( sc ) ;
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 " ) ;
sfx = & known_sfx [ i ] ;
strcpy ( sfx - > name , name ) ;
num_sfx + + ;
return sfx ;
}
/*
= = = = = = = = = = = = = = = = = =
S_TouchSound
= = = = = = = = = = = = = = = = = =
*/
void S_TouchSound ( char * name )
{
sfx_t * sfx ;
if ( ! sound_started )
return ;
sfx = S_FindName ( name ) ;
Cache_Check ( & sfx - > cache ) ;
}
/*
= = = = = = = = = = = = = = = = = =
S_PrecacheSound
= = = = = = = = = = = = = = = = = =
*/
sfx_t * S_PrecacheSound ( char * name )
{
sfx_t * sfx ;
if ( nosound . value )
return NULL ;
sfx = S_FindName ( name ) ;
// cache it in
if ( precache . value & & sndcardinfo )
S_LoadSound ( sfx ) ;
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 ;
for ( ch_idx = NUM_AMBIENTS + NUM_MUSICS ; ch_idx < NUM_AMBIENTS + NUM_MUSICS + MAX_DYNAMIC_CHANNELS ; ch_idx + + )
{
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 )
{ // allways override sound from same entity
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 ;
return & sc - > channel [ first_to_die ] ;
}
/*
= = = = = = = = = = = = = = = = =
SND_Spatialize
= = = = = = = = = = = = = = = = =
*/
void SND_Spatialize ( soundcardinfo_t * sc , channel_t * ch )
{
2005-01-13 16:29:20 +00:00
vec_t dotright , dotforward , dotup ;
2004-08-23 00:15:46 +00:00
vec_t dist ;
2005-01-13 16:29:20 +00:00
vec_t scale ;
2004-08-23 00:15:46 +00:00
vec3_t source_vec ;
sfx_t * snd ;
2005-01-13 16:29:20 +00:00
int i ;
2004-08-23 00:15:46 +00:00
// anything coming from the view entity will allways 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 + + )
{
ch - > vol [ i ] = ch - > master_vol ;
ch - > delay [ i ] = 0 ;
}
2004-08-23 00:15:46 +00:00
return ;
}
// calculate stereo seperation and distance attenuation
snd = ch - > sfx ;
VectorSubtract ( ch - > origin , listener_origin , source_vec ) ;
dist = VectorNormalize ( source_vec ) * ch - > dist_mult ;
2005-01-13 16:29:20 +00:00
dotright = DotProduct ( listener_right , source_vec ) ;
dotforward = DotProduct ( listener_forward , source_vec ) ;
2004-08-23 00:15:46 +00:00
dotup = DotProduct ( listener_up , source_vec ) ;
2005-01-13 16:29:20 +00:00
for ( i = 0 ; i < sc - > sn . numchannels ; i + + )
2004-08-23 00:15:46 +00:00
{
2005-01-13 16:29:20 +00:00
scale = 1 + ( dotright * sin ( sc - > yaw [ i ] * M_PI / 180 ) + dotforward * cos ( sc - > yaw [ i ] * M_PI / 180 ) ) ; // - dotup*cos(sc->pitch[0])*2;
scale = ( 1.0 - dist ) * scale * sc - > dist [ i ] ;
// if (scale < 0.5)
// scale = 0.5;
ch - > vol [ i ] = ( int ) ( ch - > master_vol * scale ) ;
if ( ch - > vol [ i ] < 0 )
ch - > vol [ i ] = 0 ;
ch - > delay [ i ] = 0 ; //(scale[0]-1)*1024;
2004-08-23 00:15:46 +00:00
}
}
// =======================================================================
// Start a sound effect
// =======================================================================
void S_StartSoundCard ( soundcardinfo_t * sc , int entnum , int entchannel , sfx_t * sfx , vec3_t origin , float fvol , float attenuation , int startpos )
{
channel_t * target_chan , * check ;
sfxcache_t * scache ;
int vol ;
int ch_idx ;
int skip ;
if ( ! sound_started )
return ;
if ( ! sfx )
return ;
if ( nosound . value )
return ;
vol = fvol * 255 ;
// pick a channel to play on
target_chan = SND_PickChannel ( sc , entnum , entchannel ) ;
if ( ! target_chan )
return ;
// 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
}
target_chan - > sfx = sfx ;
target_chan - > pos = startpos ;
target_chan - > end = sc - > paintedtime + scache - > length ;
2004-11-23 00:18:51 +00:00
target_chan - > looping = false ;
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
check = & sc - > channel [ NUM_AMBIENTS ] ;
for ( ch_idx = NUM_AMBIENTS + NUM_MUSICS ; ch_idx < NUM_AMBIENTS + NUM_MUSICS + MAX_DYNAMIC_CHANNELS ; ch_idx + + , check + + )
{
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 ;
target_chan - > pos + = skip ;
target_chan - > end - = skip ;
break ;
}
}
}
void S_StartSound ( int entnum , int entchannel , sfx_t * sfx , vec3_t origin , float fvol , float attenuation )
{
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 )
S_StartSoundCard ( sc , entnum , entchannel , sfx , origin , fvol , attenuation , 0 ) ;
}
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 ;
}
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
& & sc - > channel [ i ] . entchannel = = entchannel )
{
sc - > channel [ i ] . end = 0 ;
sc - > channel [ i ] . sfx = NULL ;
return ;
}
}
}
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 ;
sc - > total_chans = MAX_DYNAMIC_CHANNELS + NUM_AMBIENTS + NUM_MUSICS ; // no statics
for ( i = 0 ; i < MAX_CHANNELS ; i + + )
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 ) ;
}
}
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 )
{
int clear ;
# if defined(_WIN32) && !defined(NODIRECTX)
if ( ! sound_started | | ( ! sc - > sn . buffer & & ! sc - > pDSBuf ) )
# else
if ( ! sound_started | | ! sc - > sn . buffer )
# endif
return ;
if ( sc - > sn . samplebits = = 8 )
clear = 0x80 ;
else
clear = 0 ;
# if defined(_WIN32) && !defined(NODIRECTX)
if ( sc - > pDSBuf )
{
DWORD dwSize ;
DWORD * pData ;
int reps ;
HRESULT hresult ;
reps = 0 ;
2004-09-15 03:11:07 +00:00
while ( ( hresult = sc - > pDSBuf - > lpVtbl - > Lock ( sc - > pDSBuf , 0 , sc - > gSndBufSize , ( void * * ) & pData , & dwSize , NULL , NULL , 0 ) ) ! = DS_OK )
2004-08-23 00:15:46 +00:00
{
if ( hresult ! = DSERR_BUFFERLOST )
{
Con_Printf ( " S_ClearBuffer: DS::Lock Sound Buffer Failed \n " ) ;
S_ShutdownCard ( sc ) ;
return ;
}
if ( + + reps > 10000 )
{
Con_Printf ( " S_ClearBuffer: DS: couldn't restore buffer \n " ) ;
S_ShutdownCard ( sc ) ;
return ;
}
}
Q_memset ( pData , clear , sc - > sn . samples * sc - > sn . samplebits / 8 ) ;
sc - > pDSBuf - > lpVtbl - > Unlock ( sc - > pDSBuf , pData , dwSize , NULL , 0 ) ;
}
else
# endif
{
Q_memset ( sc - > sn . buffer , clear , sc - > sn . samples * sc - > sn . samplebits / 8 ) ;
}
}
/*
= = = = = = = = = = = = = = = = =
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 ) ;
return ;
}
ss - > sfx = sfx ;
VectorCopy ( origin , ss - > origin ) ;
ss - > master_vol = vol ;
ss - > dist_mult = ( attenuation / 64 ) / sound_nominal_clip_dist ;
2004-11-23 00:18:51 +00:00
ss - > end = scard - > paintedtime + scache - > length ;
ss - > looping = true ;
2004-08-23 00:15:46 +00:00
SND_Spatialize ( scard , ss ) ;
}
}
//=============================================================================
/*
= = = = = = = = = = = = = = = = = = =
S_UpdateAmbientSounds
= = = = = = = = = = = = = = = = = = =
*/
char * Media_NextTrack ( void ) ;
void S_UpdateAmbientSounds ( soundcardinfo_t * sc )
{
mleaf_t * l ;
float vol ;
int ambient_channel ;
channel_t * chan ;
int i ;
if ( ! snd_ambient )
return ;
for ( i = NUM_AMBIENTS ; i < NUM_AMBIENTS + NUM_MUSICS ; i + + )
{
chan = & sc - > channel [ i ] ;
if ( ! chan - > sfx )
{
char * nexttrack = Media_NextTrack ( ) ;
sfxcache_t * scache ;
sfx_t * newmusic ;
if ( nexttrack & & * nexttrack )
{
newmusic = S_PrecacheSound ( nexttrack ) ;
scache = S_LoadSound ( newmusic ) ;
if ( scache )
{
chan - > sfx = newmusic ;
chan - > pos = 0 ;
chan - > end = sc - > paintedtime + scache - > length + 1000 ;
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
if ( ! cl . worldmodel )
return ;
l = Mod_PointInLeaf ( listener_origin , cl . worldmodel ) ;
if ( ! l | | ! ambient_level . value )
{
for ( ambient_channel = 0 ; ambient_channel < NUM_AMBIENTS ; ambient_channel + + )
sc - > channel [ ambient_channel ] . sfx = NULL ;
return ;
}
for ( ambient_channel = 0 ; ambient_channel < NUM_AMBIENTS ; ambient_channel + + )
{
chan = & sc - > channel [ ambient_channel ] ;
chan - > sfx = ambient_sfx [ ambient_channel ] ;
VectorCopy ( listener_origin , chan - > origin ) ;
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 ;
}
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
= = = = = = = = = = = =
*/
void S_Update ( vec3_t origin , vec3_t forward , vec3_t right , vec3_t up )
{
soundcardinfo_t * sc ;
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
S_UpdateCapture ( ) ;
for ( sc = sndcardinfo ; sc ; sc = sc - > next )
2005-02-06 02:47:36 +00:00
S_UpdateCard ( sc ) ;
2004-08-23 00:15:46 +00:00
}
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 ;
}
2004-08-23 00:15:46 +00:00
// update general area ambient sound sources
S_UpdateAmbientSounds ( sc ) ;
combine = NULL ;
// update spatialization for static and dynamic sounds
ch = sc - > channel + NUM_AMBIENTS + NUM_MUSICS ;
for ( i = NUM_AMBIENTS + NUM_MUSICS ; i < sc - > total_chans ; i + + , ch + + )
{
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
if ( i > MAX_DYNAMIC_CHANNELS + NUM_AMBIENTS + NUM_MUSICS )
{
// 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
combine = sc - > channel + MAX_DYNAMIC_CHANNELS + NUM_AMBIENTS + NUM_MUSICS ;
for ( j = MAX_DYNAMIC_CHANNELS + NUM_AMBIENTS + NUM_MUSICS ; j < i ; j + + , combine + + )
if ( combine - > sfx = = ch - > sfx )
break ;
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
//
if ( snd_show . value )
{
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 + + ;
}
Con_Printf ( " ----(%i)---- \n " , total ) ;
}
// mix some sound
S_Update_ ( sc ) ;
}
void GetSoundtime ( soundcardinfo_t * sc )
{
int samplepos ;
int fullsamples ;
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.
samplepos = SNDDMA_GetDMAPos ( sc ) ;
if ( samplepos < sc - > oldsamplepos )
{
sc - > buffers + + ; // buffer wrapped
if ( sc - > paintedtime > 0x40000000 )
{ // time to chop things off to avoid 32 bit limits
sc - > buffers = 0 ;
sc - > paintedtime = fullsamples ;
S_StopAllSounds ( true ) ;
}
sc - > rawstart = 0 ;
}
else
sc - > rawstart + = samplepos - sc - > oldsamplepos ;
sc - > oldsamplepos = samplepos ;
soundtime = sc - > buffers * fullsamples + samplepos / sc - > sn . numchannels ;
}
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
if ( snd_noextraupdate . value )
return ; // don't pollute timings
S_UpdateCapture ( ) ;
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-08-23 00:15:46 +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
endtime = soundtime + _snd_mixahead . value * sc - > sn . speed ;
// samps = shm->samples >> (shm->numchannels-1);
samps = sc - > sn . samples / sc - > sn . numchannels ;
if ( endtime - soundtime > samps )
endtime = soundtime + samps ;
# if defined(_WIN32) && !defined(NODIRECTX)
// if the buffer was lost or stopped, restore it and/or restart it
{
DWORD dwStatus ;
if ( sc - > pDSBuf )
{
if ( sc - > pDSBuf - > lpVtbl - > GetStatus ( sc - > pDSBuf , & dwStatus ) ! = DD_OK )
Con_Printf ( " Couldn't get sound buffer status \n " ) ;
if ( dwStatus & DSBSTATUS_BUFFERLOST )
sc - > pDSBuf - > lpVtbl - > Restore ( sc - > pDSBuf ) ;
if ( ! ( dwStatus & DSBSTATUS_PLAYING ) )
sc - > pDSBuf - > lpVtbl - > Play ( sc - > pDSBuf , 0 , 0 , DSBPLAY_LOOPING ) ;
}
}
# endif
S_PaintChannels ( sc , endtime ) ;
SNDDMA_Submit ( sc ) ;
}
/*
= = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =
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 ;
i = 1 ;
while ( i < Cmd_Argc ( ) )
{
if ( ! Q_strrchr ( Cmd_Argv ( i ) , ' . ' ) )
{
Q_strcpy ( name , Cmd_Argv ( i ) ) ;
Q_strcat ( name , " .wav " ) ;
}
else
Q_strcpy ( name , Cmd_Argv ( i ) ) ;
sfx = S_PrecacheSound ( name ) ;
2004-10-07 00:23:06 +00:00
S_StartSound ( cl . playernum [ 0 ] + 1 , - 1 , sfx , vec3_origin , 1.0 , 0.0 ) ;
// 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 ;
i = 1 ;
while ( i < Cmd_Argc ( ) )
{
if ( ! Q_strrchr ( Cmd_Argv ( i ) , ' . ' ) )
{
Q_strcpy ( name , Cmd_Argv ( i ) ) ;
Q_strcat ( name , " .wav " ) ;
}
else
Q_strcpy ( name , Cmd_Argv ( i ) ) ;
sfx = S_PrecacheSound ( name ) ;
vol = Q_atof ( Cmd_Argv ( i + 1 ) ) ;
2004-10-07 00:23:06 +00:00
S_StartSound ( cl . playernum [ 0 ] + 1 , - 1 , sfx , vec3_origin , vol , 0.0 ) ;
// 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 ;
size = sc - > length * sc - > width * ( sc - > stereo + 1 ) ;
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 ;
if ( nosound . value )
return ;
if ( ! sound_started )
return ;
sfx = S_PrecacheSound ( sound ) ;
if ( ! sfx )
{
Con_Printf ( " S_LocalSound: can't cache %s \n " , sound ) ;
return ;
}
2004-10-03 22:52:02 +00:00
S_StartSound ( - 1 , - 1 , sfx , vec3_origin , 1 , 1 ) ;
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
//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 ;
int spare ;
float speedfactor ;
sfxcache_t * newcache ;
streaming_t * s , * free = NULL ;
samples / = channels ;
for ( s = s_streamers , i = 0 ; i < MAX_RAW_SOURCES ; i + + , s + + )
{
if ( ! s - > inuse )
{
free = s ;
continue ;
}
if ( s - > id = = sourceid )
break ;
}
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 ;
free - > sfxcache - > stereo = channels - 1 ;
free - > sfxcache - > width = width ;
free - > sfxcache - > loopstart = - 1 ;
free - > sfxcache - > length = 0 ;
}
if ( s - > sfxcache - > width ! = width | | s - > sfxcache - > stereo ! = channels - 1 | | s - > sfxcache - > speed ! = snd_speed )
{
s - > sfxcache - > width = width ;
s - > sfxcache - > stereo = channels - 1 ;
s - > sfxcache - > speed = snd_speed ;
s - > sfxcache - > length = 0 ;
}
prepadl = - 0x7fffffff ;
for ( si = sndcardinfo ; si ; si = si - > next ) //make sure all cards are playing, and that we still get a prepad if just one is.
{
for ( i = 0 ; i < MAX_CHANNELS ; i + + )
if ( si - > channel [ i ] . sfx = = & s - > sfx )
{
if ( prepadl < si - > channel [ i ] . pos )
prepadl = si - > channel [ i ] . pos ;
break ;
}
}
if ( prepadl = = - 0x7fffffff )
{
prepadl = 0 ;
spare = s - > sfxcache - > length ;
if ( spare > snd_speed )
spare = 0 ; //too far out. sacrifice it all
}
else
{
spare = s - > sfxcache - > length - prepadl ;
if ( spare < 0 )
spare = 0 ;
}
/* else if (spare > snd_speed)
{
for ( si = sndcardinfo ; si ; si = si - > next )
{
for ( i = 0 ; i < MAX_CHANNELS ; i + + )
if ( si - > channel [ i ] . sfx = = & s - > sfx )
{
break ;
}
if ( i = = MAX_CHANNELS ) //this one wasn't playing.
S_StartSoundCard ( si , - 1 , 0 , & s - > sfx , r_origin , 1 , 32767 , prepadl ) ;
}
return ; //let the slower sound cards catch up. (This shouldn't really happen, but it's possible two cards have slightly different timings but report the same speed)
} */
newcache = BZ_Malloc ( sizeof ( sfxcache_t ) + ( spare + samples ) * ( s - > sfxcache - > stereo + 1 ) * s - > sfxcache - > width ) ;
memcpy ( newcache , s - > sfxcache , sizeof ( sfxcache_t ) ) ;
memcpy ( newcache - > data , s - > sfxcache - > data + prepadl * ( s - > sfxcache - > stereo + 1 ) * s - > sfxcache - > width , spare * ( s - > sfxcache - > stereo + 1 ) * s - > sfxcache - > width ) ;
BZ_Free ( s - > sfxcache ) ;
s - > sfxcache = s - > sfx . cache . data = newcache ;
newcache - > length = spare + samples ;
speedfactor = ( float ) snd_speed / speed ;
if ( channels = = 1 )
{
if ( width = = 2 )
{
short sample ;
short * indata = ( short * ) data ;
short * outpos = ( short * ) ( newcache - > data + spare * ( s - > sfxcache - > stereo + 1 ) * s - > sfxcache - > width ) ;
if ( speedfactor = = 1 ) //fast
{
while ( samples - - )
{
sample = * indata + + ;
* outpos + + = sample ;
}
}
else
{
int src = 0 ;
int pos = 0 ;
while ( pos + + < samples )
{
src = pos / speedfactor ;
sample = indata [ src ] ;
* outpos + + = sample ;
}
}
}
else if ( width = = 1 )
{
char sample ;
char * indata = ( char * ) data ;
char * outpos = ( char * ) ( newcache - > data + spare * ( s - > sfxcache - > stereo + 1 ) * s - > sfxcache - > width ) ;
if ( speedfactor = = 1 ) //fast
{
while ( samples - - )
{
sample = * indata + + ;
* outpos + + = ( int ) ( ( unsigned char ) ( sample ) - 128 ) ;
}
}
else
{
int src = 0 ;
int pos = 0 ;
while ( pos + + < samples )
{
src = pos / speedfactor ;
sample = indata [ src ] ;
* outpos + + = ( int ) ( ( unsigned char ) ( sample ) - 128 ) ;
}
}
}
else
Sys_Error ( " Width isn't 2 \n " ) ;
}
else
{
if ( width = = 2 )
{
short sample ;
short * indata = ( short * ) data ;
short * outpos = ( short * ) ( ( qbyte * ) newcache - > data + spare * ( s - > sfxcache - > stereo + 1 ) * s - > sfxcache - > width ) ;
if ( speedfactor = = 1 ) //fast
{
while ( samples - - )
{
sample = * indata + + ;
* outpos + + = sample ;
sample = * indata + + ;
* outpos + + = sample ;
}
}
else
{
int src = 0 ;
int pos = 0 ;
while ( pos + + < samples )
{
src = pos / speedfactor ;
sample = indata [ src * 2 ] ;
* outpos + + = sample ;
sample = indata [ src * 2 + 1 ] ;
* outpos + + = sample ;
}
}
}
else
Sys_Error ( " Width isn't 2 \n " ) ;
}
for ( si = sndcardinfo ; si ; si = si - > next )
{
for ( i = 0 ; i < MAX_CHANNELS ; i + + )
if ( si - > channel [ i ] . sfx = = & s - > sfx )
{
si - > channel [ i ] . pos - = prepadl ;
si - > channel [ i ] . end + = samples - prepadl ;
break ;
}
if ( i = = MAX_CHANNELS ) //this one wasn't playing.
S_StartSoundCard ( si , - 1 , 0 , & s - > sfx , r_origin , 1 , 32767 , 0 ) ;
}
}
# endif //cygwin