diff --git a/bshift/client.cpp b/bshift/client.cpp index a439613d..15a29075 100644 --- a/bshift/client.cpp +++ b/bshift/client.cpp @@ -942,11 +942,11 @@ void UpdateEntityState( entity_state_t *to, edict_t *from, int baseline ) to->skin = pNet->pev->skin; // studio model skin to->body = pNet->pev->body; // studio model submodel to->effects = pNet->pev->effects; // shared client and render flags - to->soundindex = pNet->pev->soundindex; // soundindex to->renderfx = pNet->pev->renderfx; // renderer flags to->rendermode = pNet->pev->rendermode; // rendering mode to->renderamt = pNet->pev->renderamt; // alpha value to->animtime = (int)(1000.0 * pNet->pev->animtime) * 0.001; // sequence time + to->localtime = (int)(1000.0 * pNet->pev->ltime) * 0.001; // movement time to->scale = pNet->pev->scale; // shared client and render flags to->movetype = (movetype_t)pNet->pev->movetype; to->frame = pNet->pev->frame; // any model current frame @@ -1019,16 +1019,7 @@ void UpdateEntityState( entity_state_t *to, edict_t *from, int baseline ) } else if( to->ed_type == ED_AMBIENT ) { - to->soundindex = pNet->pev->soundindex; - - if( pNet->pev->solid == SOLID_TRIGGER ) - { - Vector midPoint; - - // NOTE: no reason to compute this shit on the client - save bandwidth - midPoint = pNet->pev->mins + pNet->pev->maxs * 0.5f; - to->origin += midPoint; - } + // add here specified fiels e.g for trigger_teleport wind sound etc } else if( to->ed_type == ED_MOVER || to->ed_type == ED_BSPBRUSH || to->ed_type == ED_PORTAL ) { diff --git a/bshift/util.cpp b/bshift/util.cpp index e2e8ef51..71f52a49 100644 --- a/bshift/util.cpp +++ b/bshift/util.cpp @@ -267,8 +267,6 @@ TYPEDESCRIPTION gEntvarsDescription[] = DEFINE_ENTITY_FIELD( modelindex, FIELD_INTEGER ), DEFINE_ENTITY_GLOBAL_FIELD( model, FIELD_MODELNAME ), - DEFINE_ENTITY_FIELD( soundindex, FIELD_INTEGER ), - DEFINE_ENTITY_FIELD( viewmodel, FIELD_MODELNAME ), DEFINE_ENTITY_FIELD( weaponmodel, FIELD_MODELNAME ), diff --git a/client/global/dll_int.cpp b/client/global/dll_int.cpp index 5c503ab0..93d7c9f7 100644 --- a/client/global/dll_int.cpp +++ b/client/global/dll_int.cpp @@ -224,6 +224,7 @@ void HUD_UpdateEntityVars( edict_t *ent, const entity_state_t *state, const enti ent->v.flags = state->flags; ent->v.ideal_pitch = state->idealpitch; ent->v.animtime = state->animtime; + ent->v.ltime = state->localtime; if( state->groundent != -1 ) ent->v.groundentity = GetEntityByIndex( state->groundent ); diff --git a/common/entity_def.h b/common/entity_def.h index 67334133..e829678b 100644 --- a/common/entity_def.h +++ b/common/entity_def.h @@ -41,7 +41,6 @@ typedef struct entvars_s float yaw_speed; int modelindex; // ENG [all], NET [all] - int soundindex; // ENG [all], NET [all] string_t model; // model name string_t viewmodel; // player's viewmodel (no network updates) diff --git a/common/entity_state.h b/common/entity_state.h index 0a959a3d..daf810ac 100644 --- a/common/entity_state.h +++ b/common/entity_state.h @@ -39,7 +39,6 @@ typedef struct entity_state_s uint number; // edict index edtype_t ed_type; // edict type string_t classname; // edict classname - int soundindex; // looped ambient sound int ed_flags; // engine clearing this at end of server frame // physics information @@ -65,6 +64,7 @@ typedef struct entity_state_s float frame; // % playback position in animation sequences (0..255) int skin; // skin for studiomodels int body; // sub-model selection for studiomodels + float localtime; // pev->ltime for monsters for right lerping on platforms, trains etc float animtime; // auto-animating time float framerate; // custom framerate, specified by QC int sequence; // animation sequence (0 - 255) diff --git a/engine/client/cl_demo.c b/engine/client/cl_demo.c index 0a21f82d..50294bdd 100644 --- a/engine/client/cl_demo.c +++ b/engine/client/cl_demo.c @@ -93,7 +93,7 @@ void CL_WriteDemoHeader( const char *name ) for( i = 0; i < clgame.globals->maxEntities; i++ ) { state = &clgame.baselines[i]; - if( !state->modelindex && !state->soundindex && !state->effects ) + if( !state->modelindex && !state->effects ) continue; MSG_WriteByte( &buf, svc_spawnbaseline ); diff --git a/engine/client/cl_game.c b/engine/client/cl_game.c index ec609e01..5926bedc 100644 --- a/engine/client/cl_game.c +++ b/engine/client/cl_game.c @@ -1943,7 +1943,7 @@ pfnStopSound */ void pfnStopSound( int ent, int channel, const char *sample ) { - S_StartSound( vec3_origin, ent, channel, S_RegisterSound( sample ), 0, 0, PITCH_NORM, SND_STOP ); + S_StopSound( ent, channel, sample ); } /* @@ -1999,7 +1999,7 @@ pfnStopAllSounds void pfnStopAllSounds( edict_t *ent, int entchannel ) { if( !CL_IsValidEdict( ent )) return; - S_StopSound( ent->serialnumber, entchannel ); + S_StopSound( ent->serialnumber, entchannel, NULL ); } /* diff --git a/engine/client/cl_parse.c b/engine/client/cl_parse.c index b5b20bc1..b96add69 100644 --- a/engine/client/cl_parse.c +++ b/engine/client/cl_parse.c @@ -29,6 +29,7 @@ char *svc_strings[256] = "svc_packetentities", "svc_frame", "svc_sound", + "svc_ambientsound", "svc_setangle", "svc_addangle", "svc_setview", @@ -324,28 +325,25 @@ CL_ParseSoundPacket ================== */ -void CL_ParseSoundPacket( sizebuf_t *msg ) +void CL_ParseSoundPacket( sizebuf_t *msg, bool is_ambient ) { vec3_t pos_; float *pos = NULL; - int channel, sound_num; - float volume, attenuation; + int chan, sound; + float volume, attn; int flags, pitch, entnum; flags = MSG_ReadWord( msg ); - sound_num = MSG_ReadWord( msg ); - channel = MSG_ReadByte( msg ); + sound = MSG_ReadWord( msg ); + chan = MSG_ReadByte( msg ); if( flags & SND_VOLUME ) volume = MSG_ReadByte( msg ) / 255.0f; else volume = VOL_NORM; - if( flags & SND_SOUNDLEVEL ) - { - int soundlevel = MSG_ReadByte( msg ); - attenuation = SNDLVL_TO_ATTN( soundlevel ); - } - else attenuation = ATTN_NONE; + if( flags & SND_ATTENUATION ) + attn = MSG_ReadByte( msg ) / 64.0f; + else attn = ATTN_NONE; if( flags & SND_PITCH ) pitch = MSG_ReadByte( msg ); @@ -361,7 +359,14 @@ void CL_ParseSoundPacket( sizebuf_t *msg ) MSG_ReadPos( msg, pos ); } - S_StartSound( pos, entnum, channel, cl.sound_precache[sound_num], volume, attenuation, pitch, flags ); + if( is_ambient ) + { + S_AmbientSound( pos, entnum, chan, cl.sound_precache[sound], volume, attn, pitch, flags ); + } + else + { + S_StartSound( pos, entnum, chan, cl.sound_precache[sound], volume, attn, pitch, flags ); + } } /* @@ -815,7 +820,10 @@ void CL_ParseServerMessage( sizebuf_t *msg ) CL_ParseDownload( msg ); break; case svc_sound: - CL_ParseSoundPacket( msg ); + CL_ParseSoundPacket( msg, false ); + break; + case svc_ambientsound: + CL_ParseSoundPacket( msg, true ); break; case svc_setangle: CL_ParseSetAngle( msg ); diff --git a/engine/common.h b/engine/common.h index fe6ba46f..8807cb22 100644 --- a/engine/common.h +++ b/engine/common.h @@ -221,7 +221,6 @@ void Tri_DrawTriangles( int fTrans ); int CL_PointContents( const vec3_t point ); void CL_StudioFxTransform( edict_t *ent, float transform[4][4] ); bool CL_GetEntitySpatialization( int entnum, soundinfo_t *info ); -void CL_GetEntitySoundSpatialization( int ent, vec3_t origin, vec3_t velocity ); bool CL_GetAttachment( int entityIndex, int number, vec3_t origin, vec3_t angles ); bool CL_SetAttachment( int entityIndex, int number, vec3_t origin, vec3_t angles ); void CL_StudioEvent( dstudioevent_t *event, edict_t *ent ); diff --git a/engine/common/com_export.h b/engine/common/com_export.h index ef6c2b68..73df2f45 100644 --- a/engine/common/com_export.h +++ b/engine/common/com_export.h @@ -200,6 +200,7 @@ _inline bool CM_BoxVisible( const vec3_t mins, const vec3_t maxs ) #define S_Shutdown if( se ) se->Shutdown #define S_StartStreaming if( se ) se->StartStreaming #define S_StartSound if( se ) se->StartSound +#define S_AmbientSound if( se ) se->StaticSound #define S_StartLocalSound if( se ) se->StartLocalSound #define S_StartBackgroundTrack if( se ) se->StartBackgroundTrack #define S_StopBackgroundTrack if( se ) se->StopBackgroundTrack diff --git a/engine/common/net_msg.c b/engine/common/net_msg.c index c2a3f44d..92ce53a3 100644 --- a/engine/common/net_msg.c +++ b/engine/common/net_msg.c @@ -18,7 +18,6 @@ static net_field_t ent_fields[] = { ES_FIELD(ed_type), NET_BYTE, true }, // stateflags_t #0 (4 bytes) { ES_FIELD(ed_flags), NET_BYTE, false }, // stateflags_t #0 (4 bytes) { ES_FIELD(classname), NET_WORD, true }, -{ ES_FIELD(soundindex), NET_WORD, false }, // 512 sounds ( OpenAL software limit is 255 ) { ES_FIELD(angles[0]), NET_FLOAT, false }, { ES_FIELD(angles[1]), NET_FLOAT, false }, { ES_FIELD(angles[2]), NET_FLOAT, false }, diff --git a/engine/common/net_msg.h b/engine/common/net_msg.h index 2700d000..81dfaf16 100644 --- a/engine/common/net_msg.h +++ b/engine/common/net_msg.h @@ -65,6 +65,7 @@ enum svc_ops_e svc_packetentities, // [...] svc_frame, // server frame svc_sound, // + svc_ambientsound, // svc_setangle, // [short short short] set the view angle to this absolute value svc_addangle, // [short short] add angles when client turn on mover svc_setview, // [short] entity number diff --git a/engine/common/net_sound.h b/engine/common/net_sound.h index 0e4bd9fa..d6da99f4 100644 --- a/engine/common/net_sound.h +++ b/engine/common/net_sound.h @@ -10,7 +10,7 @@ #define SND_SENTENCE (1<<7) // set if sound num is actually a sentence num #define SND_VOLUME (1<<8) // a scaled byte -#define SND_SOUNDLEVEL (1<<9) // a byte +#define SND_ATTENUATION (1<<9) // a byte #define SND_PITCH (1<<10) // a byte #define SND_FIXED_ORIGIN (1<<11) // a vector diff --git a/engine/host.c b/engine/host.c index 60318301..e9b82cd3 100644 --- a/engine/host.c +++ b/engine/host.c @@ -71,8 +71,6 @@ bool Host_NewGame( const char *mapName, bool loadGame ) { bool iRet; - S_StopAllSounds (); - iRet = SV_NewGame( mapName, loadGame ); return iRet; @@ -224,7 +222,6 @@ bool Host_InitSound( void ) // sound callbacks si.GetEntitySpatialization = CL_GetEntitySpatialization; - si.GetSoundSpatialization = CL_GetEntitySoundSpatialization; si.TraceLine = CL_TraceLine; si.PointContents = CL_PointContents; si.GetClientEdict = CL_GetEdictByIndex; diff --git a/engine/server/server.h b/engine/server/server.h index 629ac806..a016f9ea 100644 --- a/engine/server/server.h +++ b/engine/server/server.h @@ -345,7 +345,6 @@ float SV_VecToYaw( const vec3_t src ); // sv_send.c // void SV_SendClientMessages( void ); -void SV_AmbientSound( edict_t *entity, int soundindex, float volume, float attenuation ); void SV_ClientPrintf( sv_client_t *cl, int level, char *fmt, ... ); void SV_BroadcastPrintf( int level, char *fmt, ... ); void SV_BroadcastCommand( char *fmt, ... ); diff --git a/engine/server/sv_client.c b/engine/server/sv_client.c index 55097ec8..397ee26f 100644 --- a/engine/server/sv_client.c +++ b/engine/server/sv_client.c @@ -856,7 +856,7 @@ void SV_Baselines_f( sv_client_t *cl ) while( cl->netchan.message.cursize < MAX_MSGLEN / 2 && start < GI->max_edicts ) { base = &svs.baselines[start]; - if( base->modelindex || base->soundindex || base->effects ) + if( base->modelindex || base->effects ) { MSG_WriteByte( &cl->netchan.message, svc_spawnbaseline ); MSG_WriteDeltaEntity( &nullstate, base, &cl->netchan.message, true, true ); diff --git a/engine/server/sv_game.c b/engine/server/sv_game.c index 6b1a0def..7fe2f9da 100644 --- a/engine/server/sv_game.c +++ b/engine/server/sv_game.c @@ -596,14 +596,14 @@ void SV_BaselineForEntity( const edict_t *pEdict ) base = &sv_ent->s; - if( pEdict->v.modelindex || base->soundindex || pEdict->v.effects ) + if( pEdict->v.modelindex || pEdict->v.effects ) { // take current state as baseline SV_UpdateEntityState( pEdict, true ); svs.baselines[pEdict->serialnumber] = *base; } - if( sv.state == ss_active && ( base->modelindex || base->soundindex || base->effects )) + if( sv.state == ss_active && ( base->modelindex || base->effects )) { entity_state_t nullstate; @@ -1420,7 +1420,7 @@ SV_StartSound void SV_StartSound( edict_t *ent, int chan, const char *sample, float vol, float attn, int flags, int pitch ) { int sound_idx; - int msg_dest = MSG_PAS_R; + int msg_dest; vec3_t origin; if( attn < ATTN_NONE || attn > ATTN_IDLE ) @@ -1443,7 +1443,7 @@ void SV_StartSound( edict_t *ent, int chan, const char *sample, float vol, float if( sv.state == ss_loading ) flags |= SND_SPAWNING; if( vol != VOL_NORM ) flags |= SND_VOLUME; - if( attn != ATTN_NONE ) flags |= SND_SOUNDLEVEL; + if( attn != ATTN_NONE ) flags |= SND_ATTENUATION; if( pitch != PITCH_NORM ) flags |= SND_PITCH; // ultimate method for detect bsp models with invalid solidity (e.g. func_pushable) @@ -1477,9 +1477,9 @@ void SV_StartSound( edict_t *ent, int chan, const char *sample, float vol, float MSG_WriteWord( &sv.multicast, sound_idx ); MSG_WriteByte( &sv.multicast, chan ); - if ( flags & SND_VOLUME ) MSG_WriteByte( &sv.multicast, vol * 255 ); - if ( flags & SND_SOUNDLEVEL ) MSG_WriteByte( &sv.multicast, ATTN_TO_SNDLVL( attn )); - if ( flags & SND_PITCH ) MSG_WriteByte( &sv.multicast, pitch ); + if( flags & SND_VOLUME ) MSG_WriteByte( &sv.multicast, vol * 255 ); + if( flags & SND_ATTENUATION ) MSG_WriteByte( &sv.multicast, attn * 64 ); + if( flags & SND_PITCH ) MSG_WriteByte( &sv.multicast, pitch ); // plays from aiment if( ent->v.aiment && !ent->v.aiment->free ) @@ -1515,7 +1515,7 @@ void pfnEmitAmbientSound( edict_t *ent, float *pos, const char *samp, float vol, if( sv.state == ss_loading ) flags |= SND_SPAWNING; if( vol != VOL_NORM ) flags |= SND_VOLUME; - if( attn != ATTN_NONE ) flags |= SND_SOUNDLEVEL; + if( attn != ATTN_NONE ) flags |= SND_ATTENUATION; if( pitch != PITCH_NORM ) flags |= SND_PITCH; if( flags & SND_SPAWNING ) @@ -1549,14 +1549,14 @@ void pfnEmitAmbientSound( edict_t *ent, float *pos, const char *samp, float vol, // and return sound index when server is active sound_idx = SV_SoundIndex( samp ); - MSG_Begin( svc_sound ); + MSG_Begin( svc_ambientsound ); MSG_WriteWord( &sv.multicast, flags ); MSG_WriteWord( &sv.multicast, sound_idx ); MSG_WriteByte( &sv.multicast, CHAN_AUTO ); - if ( flags & SND_VOLUME ) MSG_WriteByte( &sv.multicast, vol * 255 ); - if ( flags & SND_SOUNDLEVEL ) MSG_WriteByte( &sv.multicast, ATTN_TO_SNDLVL( attn )); - if ( flags & SND_PITCH ) MSG_WriteByte( &sv.multicast, pitch ); + if( flags & SND_VOLUME ) MSG_WriteByte( &sv.multicast, vol * 255 ); + if( flags & SND_ATTENUATION ) MSG_WriteByte( &sv.multicast, attn * 64 ); + if( flags & SND_PITCH ) MSG_WriteByte( &sv.multicast, pitch ); // plays from fixed position MSG_WriteWord( &sv.multicast, number ); diff --git a/engine/server/sv_init.c b/engine/server/sv_init.c index 3be173a7..5f4b3858 100644 --- a/engine/server/sv_init.c +++ b/engine/server/sv_init.c @@ -528,6 +528,13 @@ void SV_ForceError( void ) bool SV_NewGame( const char *mapName, bool loadGame ) { + if( !loadGame ) + { + if( !SV_MapIsValid( mapName, GI->sp_entity, NULL )) + return false; + } + + S_StopAllSounds (); SV_InactivateClients (); SV_DeactivateServer (); diff --git a/engine/uimenu/ui_main.c b/engine/uimenu/ui_main.c index 83a58b5d..cce4ddc7 100644 --- a/engine/uimenu/ui_main.c +++ b/engine/uimenu/ui_main.c @@ -162,7 +162,7 @@ static void UI_Main_HazardCourse( void ) Cvar_SetValue( "pausable", 1.0f ); // singleplayer is always allowing pause Cvar_SetValue( "coop", 0.0f ); - Cbuf_ExecuteText( EXEC_APPEND, va( "loading; killserver; wait; map %s\n", GI->trainmap )); + Host_NewGame( GI->trainmap, false ); } /* diff --git a/engine/uimenu/ui_newgame.c b/engine/uimenu/ui_newgame.c index f13eed4d..c43107d0 100644 --- a/engine/uimenu/ui_newgame.c +++ b/engine/uimenu/ui_newgame.c @@ -76,7 +76,7 @@ static void UI_NewGame_StartGame( float skill ) Cvar_SetValue( "pausable", 1 ); // singleplayer is always allowing pause Cvar_SetValue( "coop", 0 ); - Cbuf_ExecuteText( EXEC_APPEND, "loading; killserver; wait; newgame\n" ); + Host_NewGame( GI->startmap, false ); } static void UI_PromptDialog( float skill ) diff --git a/public/vsound_api.h b/public/vsound_api.h index 03bc8a8b..9a997ec6 100644 --- a/public/vsound_api.h +++ b/public/vsound_api.h @@ -7,11 +7,7 @@ #include "ref_params.h" -typedef int sound_t; - -// snd internal flags (lower bits are used for snd channels) -#define CHAN_NO_PHS_ADD (1<<3) // send to all clients, not just ones in PHS (ATTN 0 will also do this) -#define CHAN_RELIABLE (1<<4) // send by reliable message, not datagram +typedef int sound_t; typedef struct { @@ -49,6 +45,7 @@ typedef struct vsound_exp_s void (*EndRegistration)( void ); void (*StartSound)( const vec3_t pos, int ent, int chan, sound_t sfx, float vol, float attn, int pitch, int flags ); + void (*StaticSound)( const vec3_t pos, int ent, int chan, sound_t sfx, float vol, float attn, int pitch, int flags ); void (*StreamRawSamples)( int samples, int rate, int width, int channels, const byte *data ); bool (*StartLocalSound)( const char *name, float volume, int pitch, const float *origin ); void (*FadeClientVolume)( float fadePercent, float fadeOutSeconds, float holdTime, float fadeInSeconds ); @@ -59,7 +56,7 @@ typedef struct vsound_exp_s void (*StopStreaming)( void ); void (*RenderFrame)( ref_params_t *fd ); - void (*StopSound)( int entnum, int channel ); + void (*StopSound)( int entnum, int channel, const char *soundname ); void (*StopAllSounds)( void ); void (*FreeSounds)( void ); @@ -74,7 +71,6 @@ typedef struct vsound_imp_s trace_t (*TraceLine)( const vec3_t start, const vec3_t end ); bool (*GetEntitySpatialization)( int entnum, soundinfo_t *info ); - void (*GetSoundSpatialization)( int entnum, vec3_t origin, vec3_t velocity ); int (*PointContents)( const vec3_t point ); edict_t *(*GetClientEdict)( int index ); mouth_t *(*GetEntityMouth)( edict_t *ent ); diff --git a/server/ents/baseentity.cpp b/server/ents/baseentity.cpp index 38499e01..3f6e6fbc 100644 --- a/server/ents/baseentity.cpp +++ b/server/ents/baseentity.cpp @@ -860,13 +860,6 @@ int CBaseEntity :: Restore( CRestore &restore ) UTIL_SetModel( ENT( pev ), pev->model ); UTIL_SetSize( pev, mins, maxs ); } - - if( pev->soundindex != 0 && !FStringNull( pev->noise )) - { - UTIL_PrecacheSound( pev->noise ); - LINK_ENTITY( ENT( pev ), false ); - } - return status; } diff --git a/server/ents/baseinfo.cpp b/server/ents/baseinfo.cpp index 843f048e..57dcde70 100644 --- a/server/ents/baseinfo.cpp +++ b/server/ents/baseinfo.cpp @@ -49,27 +49,20 @@ class CWallTorch : public CBaseEntity public: void Precache( void ) { - // if sound is missing just reset soundindex - pev->impulse = PRECACHE_SOUND( "ambience/fire1.wav" ); + PRECACHE_SOUND( "ambience/fire1.wav" ); UTIL_PrecacheModel( "models/props/torch1.mdl" ); + UTIL_EmitAmbientSound( ENT(pev), pev->origin, "ambience/fire1.wav", 1.0f, ATTN_NORM, 0, PITCH_NORM ); } void Spawn( void ) { Precache (); - if( !pev->impulse ) - { - UTIL_Remove( this ); - return; - } - // SetObjectClass( ED_NORMAL ); pev->flags |= FL_PHS_FILTER; // allow phs filter instead pvs // setup attenuation radius pev->armorvalue = 384.0f * ATTN_STATIC; - pev->soundindex = pev->impulse; UTIL_SetModel( ENT( pev ), "models/props/torch1.mdl" ); UTIL_SetSize(pev, g_vecZero, g_vecZero); SetBits( pFlags, PF_POINTENTITY ); diff --git a/server/game/sound.cpp b/server/game/sound.cpp index 687a20c0..ec8319aa 100644 --- a/server/game/sound.cpp +++ b/server/game/sound.cpp @@ -906,113 +906,6 @@ void CAmbientGeneric :: KeyValue( KeyValueData *pkvd ) CBaseEntity::KeyValue( pkvd ); } -/*QUAKED target_speaker (1 0 0) (-8 -8 -8) (8 8 8) looped-on looped-off reliable -"noise" wav file to play -"attenuation" --1 = none, send to whole level -1 = normal fighting sounds -2 = idle sound level -3 = ambient sound level -"volume" 0.0 to 1.0 - -Normal sounds play each time the target is used. The reliable flag can be set for crucial voiceovers. - -Looped sounds are always atten 3 / vol 1, and the use function toggles it on/off. -Multiple identical looping sounds will just increase volume without any speed cost. -*/ -#define SF_SPEAKER_LOOPED_ON 1 -#define SF_SPEAKER_LOOPED_OFF 2 -#define SF_SPEAKER_GLOBAL 4 -#define SF_SPEAKER_ACTIVATOR 8 - -class CTargetSpeaker : public CBaseEntity -{ -public: - void KeyValue( KeyValueData* pkvd ); - void Spawn( void ); - void Precache( void ); - void EXPORT ToggleUse ( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ); -}; -LINK_ENTITY_TO_CLASS( target_speaker, CTargetSpeaker ); - -void CTargetSpeaker :: KeyValue( KeyValueData *pkvd ) -{ - if ( FStrEq( pkvd->szKeyName, "volume" )) - { - pev->health = atof( pkvd->szValue ); - pkvd->fHandled = TRUE; - } - if ( FStrEq( pkvd->szKeyName, "attenuation" )) - { - switch( atoi( pkvd->szValue )) - { - case -1: pev->frags = ATTN_NONE; break; - case 1: pev->frags = ATTN_NORM; break; - case 2: pev->frags = ATTN_IDLE; break; - default: pev->frags = ATTN_STATIC; break; - } - pkvd->fHandled = TRUE; - } - else CBaseEntity::KeyValue( pkvd ); -} - -void CTargetSpeaker :: Precache( void ) -{ - // if sound is missing just reset soundindex - pev->impulse = PRECACHE_SOUND( STRING( pev->noise )); -} - -void CTargetSpeaker :: ToggleUse ( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ) -{ - if ( pev->spawnflags & (SF_SPEAKER_LOOPED_ON|SF_SPEAKER_LOOPED_OFF)) - { - // looping sound toggles - if ( pev->soundindex ) pev->soundindex = 0; // turn it off - else pev->soundindex = pev->impulse; // start it - } - else - { // normal sound - if( pev->spawnflags & SF_SPEAKER_ACTIVATOR ) - EMIT_SOUND_DYN( pActivator->edict(), CHAN_AUTO, STRING (pev->noise ), pev->health, pev->frags, SND_SPAWNING, PITCH_NORM ); - // use a G_PositionedSound, because this entity won't normally be - // sent to any clients because it is invisible - else if( pev->spawnflags & SF_SPEAKER_GLOBAL ) - UTIL_EmitAmbientSound( NULL, pev->origin, STRING (pev->noise ), pev->health, pev->frags, SND_SPAWNING, PITCH_NORM ); - else UTIL_EmitAmbientSound( ENT( pev ), pev->origin, STRING (pev->noise ), pev->health, pev->frags, 0, PITCH_NORM ); - } -} - -void CTargetSpeaker :: Spawn( void ) -{ - Precache (); - - if( !pev->impulse ) - { - ALERT( at_error, "%s with no noise set at %g %g %g\n", STRING( pev->classname ), pev->origin.x, pev->origin.y, pev->origin.z ); - UTIL_Remove( this ); - return; - } - - SetObjectClass( ED_AMBIENT ); - pev->flags |= FL_PHS_FILTER; // allow phs filter instead pvs - - if( !pev->health ) pev->health = 1.0f; - if( !pev->frags ) pev->frags = ATTN_NORM; - - // setup attenuation radius - pev->armorvalue = 512.0f * pev->frags; - - // check for prestarted looping sound - if ( pev->spawnflags & SF_SPEAKER_LOOPED_ON ) - pev->soundindex = pev->impulse; - - SetUse( ToggleUse ); - - // must link the entity so we get areas and clusters so - // the server can determine who to send updates to - LINK_ENTITY( ENT( pev ), false ); -} - // ==================== SENTENCE GROUPS, UTILITY FUNCTIONS ====================================== #define CSENTENCE_LRU_MAX 32 // max number of elements per sentence group diff --git a/server/global/client.cpp b/server/global/client.cpp index 8cb797ae..f07a335b 100644 --- a/server/global/client.cpp +++ b/server/global/client.cpp @@ -1132,11 +1132,11 @@ void UpdateEntityState( entity_state_t *to, edict_t *from, int baseline ) to->skin = pNet->pev->skin; // studio model skin to->body = pNet->pev->body; // studio model submodel to->effects = pNet->pev->effects; // shared client and render flags - to->soundindex = pNet->pev->soundindex; // soundindex to->renderfx = pNet->pev->renderfx; // renderer flags to->rendermode = pNet->pev->rendermode; // rendering mode to->renderamt = pNet->pev->renderamt; // alpha value to->animtime = (int)(1000.0 * pNet->pev->animtime) * 0.001; // sequence time + to->localtime = (int)(1000.0 * pNet->pev->ltime) * 0.001; // movement time to->scale = pNet->pev->scale; // shared client and render flags to->movetype = (movetype_t)pNet->pev->movetype; to->frame = pNet->pev->frame; // any model current frame @@ -1209,16 +1209,6 @@ void UpdateEntityState( entity_state_t *to, edict_t *from, int baseline ) } else if( to->ed_type == ED_AMBIENT ) { - to->soundindex = pNet->pev->soundindex; - - if( pNet->pev->solid == SOLID_TRIGGER ) - { - Vector midPoint; - - // NOTE: no reason to compute this shit on the client - save bandwidth - midPoint = pNet->pev->mins + pNet->pev->maxs * 0.5f; - to->origin += midPoint; - } } else if( to->ed_type == ED_MOVER || to->ed_type == ED_BSPBRUSH || to->ed_type == ED_PORTAL ) { diff --git a/server/global/saverestore.cpp b/server/global/saverestore.cpp index 03254468..402784bf 100644 --- a/server/global/saverestore.cpp +++ b/server/global/saverestore.cpp @@ -43,8 +43,6 @@ TYPEDESCRIPTION gEntvarsDescription[] = DEFINE_ENTITY_FIELD( modelindex, FIELD_INTEGER ), DEFINE_ENTITY_GLOBAL_FIELD( model, FIELD_MODELNAME ), - DEFINE_ENTITY_FIELD( soundindex, FIELD_INTEGER ), - DEFINE_ENTITY_FIELD( viewmodel, FIELD_MODELNAME ), DEFINE_ENTITY_FIELD( weaponmodel, FIELD_MODELNAME ), diff --git a/server/quake.cpp b/server/quake.cpp deleted file mode 100644 index 8e25a306..00000000 --- a/server/quake.cpp +++ /dev/null @@ -1,35 +0,0 @@ -class CWallTorch : public CBaseEntity -{ -public: - void Precache( void ) - { - // if sound is missing just reset soundindex - pev->impulse = PRECACHE_SOUND( "ambience/fire1.wav" ); - UTIL_PrecacheModel( "models/props/torch1.mdl" ); - } - void Spawn( void ) - { - Precache (); - - if( !pev->impulse ) - { - UTIL_Remove( this ); - return; - } - -// SetObjectClass( ED_NORMAL ); - pev->flags |= FL_PHS_FILTER; // allow phs filter instead pvs - - // setup attenuation radius - pev->armorvalue = 384.0f * ATTN_STATIC; - - pev->soundindex = pev->impulse; - UTIL_SetModel( ENT( pev ), "models/props/torch1.mdl" ); - UTIL_SetSize(pev, g_vecZero, g_vecZero); - SetBits( pFlags, PF_POINTENTITY ); - pev->animtime = gpGlobals->time + 0.2; // enable animation - pev->framerate = 0.5f; - } -}; - -LINK_ENTITY_TO_CLASS( light_torch_small_walltorch, CWallTorch ); \ No newline at end of file diff --git a/snd_al/s_export.c b/snd_al/s_export.c index c0a70494..83a96316 100644 --- a/snd_al/s_export.c +++ b/snd_al/s_export.c @@ -34,6 +34,7 @@ vsound_exp_t DLLEXPORT *CreateAPI( stdlib_api_t *input, vsound_imp_t *engfuncs ) snd.FadeClientVolume = S_FadeClientVolume; snd.StartSound = S_StartSound; + snd.StaticSound = S_StaticSound; snd.StreamRawSamples = S_StreamRawSamples; snd.StartLocalSound = S_StartLocalSound; snd.StartBackgroundTrack = S_StartBackgroundTrack; diff --git a/snd_al/s_load.c b/snd_al/s_load.c index c9d46655..075597c5 100644 --- a/snd_al/s_load.c +++ b/snd_al/s_load.c @@ -13,19 +13,12 @@ #define MAX_SFX 4096 #define MAX_SFX_HASH (MAX_SFX/4) +static int s_numSfx = 0; static sfx_t s_knownSfx[MAX_SFX]; static sfx_t *s_sfxHashList[MAX_SFX_HASH]; -static int s_numSfx = 0; bool s_registering = false; int s_registration_sequence = 0; -typedef struct loadformat_s -{ - char *formatstring; - char *ext; - bool (*loadfunc)( const char *name, byte **wav, wavinfo_t *info ); -} loadformat_t; - /* ================= S_SoundList_f @@ -37,8 +30,8 @@ void S_SoundList_f( void ) int i, samples = 0; int totalSfx = 0; - Msg("\n"); - Msg(" -samples -hz-- -format- -name--------\n"); + Msg( "\n" ); + Msg( " -samples -hz-- -format- -name--------\n" ); for( i = 0; i < s_numSfx; i++ ) { @@ -46,7 +39,7 @@ void S_SoundList_f( void ) if( sfx->loaded ) { samples += sfx->samples; - if( sfx->loopstart >= 0 ) Msg( "L" ); + if( sfx->loopStart >= 0 ) Msg( "L" ); else Msg( " " ); Msg( "%8i ", sfx->samples ); Msg( "%5i ", sfx->rate ); @@ -60,377 +53,43 @@ void S_SoundList_f( void ) default: Msg( "???????? " ); break; } - if( sfx->name[0] == '#' ) Msg( "%s", &sfx->name[1] ); - else Msg( "sound/%s", sfx->name ); + Msg( "sound/%s", sfx->name ); Msg( "\n" ); totalSfx++; } } - Msg("-------------------------------------------\n"); - Msg("%i total samples\n", samples ); - Msg("%i total sounds\n", totalSfx ); - Msg("\n"); + Msg( "-------------------------------------------\n" ); + Msg( "%i total samples\n", samples ); + Msg( "%i total sounds\n", totalSfx ); + Msg( "\n" ); } -/* -======================================================================= - - WAV LOADING - -======================================================================= -*/ -static byte *iff_data; -static byte *iff_dataPtr; -static byte *iff_end; -static byte *iff_lastChunk; -static int iff_chunkLen; - -/* -================= -S_GetLittleShort -================= -*/ -static short S_GetLittleShort( void ) +// return true if char 'c' is one of 1st 2 characters in pch +bool S_TestSoundChar( const char *pch, char c ) { - short val = 0; + int i; + char *pcht = (char *)pch; - val += (*(iff_dataPtr+0) << 0); - val += (*(iff_dataPtr+1) << 8); - iff_dataPtr += 2; - - return val; + // check first 2 characters + for( i = 0; i < 2; i++ ) + { + if( *pcht == c ) + return true; + pcht++; + } + return false; } -/* -================= -S_GetLittleLong -================= -*/ -static int S_GetLittleLong( void ) +// return pointer to first valid character in file name +char *S_SkipSoundChar( const char *pch ) { - int val = 0; + char *pcht = (char *)pch; - val += (*(iff_dataPtr+0) << 0); - val += (*(iff_dataPtr+1) << 8); - val += (*(iff_dataPtr+2) << 16); - val += (*(iff_dataPtr+3) << 24); - iff_dataPtr += 4; - - return val; -} - -/* -================= -S_FindNextChunk -================= -*/ -static void S_FindNextChunk( const char *name ) -{ - while( 1 ) - { - iff_dataPtr = iff_lastChunk; - if( iff_dataPtr >= iff_end ) - { - // didn't find the chunk - iff_dataPtr = NULL; - return; - } - - iff_dataPtr += 4; - iff_chunkLen = S_GetLittleLong(); - if (iff_chunkLen < 0) - { - iff_dataPtr = NULL; - return; - } - - iff_dataPtr -= 8; - iff_lastChunk = iff_dataPtr + 8 + ((iff_chunkLen + 1) & ~1); - if(!com.strncmp( iff_dataPtr, name, 4 )) - return; - } -} - -/* -================= -S_FindChunk -================= -*/ -static void S_FindChunk( const char *name ) -{ - iff_lastChunk = iff_data; - S_FindNextChunk( name ); -} - -/* -================= -S_LoadWAV -================= -*/ -static bool S_LoadWAV( const char *name, byte **wav, wavinfo_t *info ) -{ - byte *buffer, *out; - int length, samples; - - buffer = FS_LoadFile( name, &length ); - if( !buffer ) return false; - - iff_data = buffer; - iff_end = buffer + length; - - // dind "RIFF" chunk - S_FindChunk( "RIFF" ); - if( !( iff_dataPtr && !com.strncmp( iff_dataPtr + 8, "WAVE", 4 ))) - { - MsgDev( D_WARN, "S_LoadWAV: missing 'RIFF/WAVE' chunks (%s)\n", name ); - Mem_Free( buffer ); - return false; - } - - // get "fmt " chunk - iff_data = iff_dataPtr + 12; - S_FindChunk( "fmt " ); - if( !iff_dataPtr ) - { - MsgDev( D_WARN, "S_LoadWAV: missing 'fmt ' chunk (%s)\n", name ); - Mem_Free( buffer ); - return false; - } - - iff_dataPtr += 8; - if( S_GetLittleShort() != 1 ) - { - MsgDev( D_WARN, "S_LoadWAV: microsoft PCM format only (%s)\n", name ); - Mem_Free( buffer ); - return false; - } - - info->channels = S_GetLittleShort(); - if( info->channels != 1 && info->channels != 2 ) - { - MsgDev( D_WARN, "S_LoadWAV: only mono and stereo WAV files supported (%s)\n", name ); - Mem_Free( buffer ); - return false; - } - - info->rate = S_GetLittleLong(); - iff_dataPtr += 4+2; - - info->width = S_GetLittleShort() / 8; - if( info->width != 1 && info->width != 2 ) - { - MsgDev( D_WARN, "S_LoadWAV: only 8 and 16 bit WAV files supported (%s)\n", name ); - Mem_Free( buffer ); - return false; - } - - // get cue chunk - S_FindChunk( "cue " ); - if( iff_dataPtr ) - { - iff_dataPtr += 32; - info->loopstart = S_GetLittleLong(); - S_FindNextChunk( "LIST" ); // if the next chunk is a LIST chunk, look for a cue length marker - if( iff_dataPtr ) - { - if( !com.strncmp((const char *)iff_dataPtr + 28, "mark", 4 )) - { - // this is not a proper parse, but it works with CoolEdit... - iff_dataPtr += 24; - info->samples = info->loopstart + S_GetLittleLong(); // samples in loop - } - } - } - else - { - info->loopstart = -1; - info->samples = 0; - } - - // find data chunk - S_FindChunk( "data" ); - if( !iff_dataPtr ) - { - MsgDev( D_WARN, "S_LoadWAV: missing 'data' chunk (%s)\n", name ); - Mem_Free( buffer ); - return false; - } - - iff_dataPtr += 4; - samples = S_GetLittleLong() / info->width; - - if( info->samples ) - { - if( samples < info->samples ) - { - MsgDev( D_ERROR, "S_LoadWAV: %s has a bad loop length\n", name ); - Mem_Free( buffer ); - return false; - } - } - else info->samples = samples; - - if( info->samples <= 0 ) - { - MsgDev( D_WARN, "S_LoadWAV: file with %i samples (%s)\n", info->samples, name ); - Mem_Free( buffer ); - return false; - } - - // Load the data - *wav = out = Z_Malloc( info->samples * info->width * info->channels ); - Mem_Copy( out, buffer + (iff_dataPtr - buffer), info->samples * info->width * info->channels ); - Mem_Free( buffer ); - - return true; -} - -/* - ======================================================================= - - OGG LOADING - - ======================================================================= -*/ -typedef struct -{ - byte *buffer; - ogg_int64_t ind; - ogg_int64_t buffsize; -} ov_decode_t; - -static size_t ovc_read( void *ptr, size_t size, size_t nb, void *datasource ) -{ - ov_decode_t *sound = (ov_decode_t *)datasource; - size_t remain, length; - - remain = sound->buffsize - sound->ind; - length = size * nb; - if( remain < length ) length = remain - remain % size; - - Mem_Copy( ptr, sound->buffer + sound->ind, length ); - sound->ind += length; - - return length / size; -} - -static int ovc_seek ( void *datasource, ogg_int64_t offset, int whence ) -{ - ov_decode_t *sound = (ov_decode_t*)datasource; - - switch( whence ) - { - case SEEK_SET: - break; - case SEEK_CUR: - offset += sound->ind; - break; - case SEEK_END: - offset += sound->buffsize; - break; - default: - return -1; - } - if( offset < 0 || offset > sound->buffsize ) - return -1; - - sound->ind = offset; - return 0; -} - -static int ovc_close( void *datasource ) -{ - return 0; -} - -static long ovc_tell (void *datasource) -{ - return ((ov_decode_t*)datasource)->ind; -} - -/* -================= -S_LoadOGG -================= -*/ -static bool S_LoadOGG( const char *name, byte **wav, wavinfo_t *info ) -{ - vorbisfile_t vf; - vorbis_info_t *vi; - vorbis_comment_t *vc; - fs_offset_t filesize; - ov_decode_t ov_decode; - ogg_int64_t length, done = 0; - ov_callbacks_t ov_callbacks = { ovc_read, ovc_seek, ovc_close, ovc_tell }; - byte *data, *buffer; - const char *comm; - int dummy; - long ret; - - // load the file - data = FS_LoadFile( name, &filesize ); - if( !data ) return false; - - // Open it with the VorbisFile API - ov_decode.buffer = data; - ov_decode.ind = 0; - ov_decode.buffsize = filesize; - if( ov_open_callbacks( &ov_decode, &vf, NULL, 0, ov_callbacks ) < 0 ) - { - MsgDev( D_ERROR, "S_LoadOGG: couldn't open ogg stream %s\n", name ); - Mem_Free( data ); - return false; - } - - // get the stream information - vi = ov_info( &vf, -1 ); - if( vi->channels != 1 ) - { - MsgDev( D_ERROR, "S_LoadOGG: only mono OGG files supported (%s)\n", name ); - ov_clear( &vf ); - Mem_Free( data ); - return false; - } - - info->channels = vi->channels; - info->rate = vi->rate; - info->width = 2; // always 16-bit PCM - info->loopstart = -1; - length = ov_pcm_total( &vf, -1 ) * vi->channels * 2; // 16 bits => "* 2" - if( !length ) - { - // bad ogg file - MsgDev( D_ERROR, "S_LoadOGG: (%s) is probably corrupted\n", name ); - ov_clear( &vf ); - Mem_Free( data ); - return false; - } - buffer = (byte *)Z_Malloc( length ); - - // decompress ogg into pcm wav format - while((ret = ov_read( &vf, &buffer[done], (int)(length - done), big_endian, 2, 1, &dummy )) > 0) - done += ret; - info->samples = done / ( vi->channels * 2 ); - vc = ov_comment( &vf, -1 ); - - if( vc ) - { - comm = vorbis_comment_query( vc, "LOOP_START", 0 ); - if( comm ) - { - //FXIME: implement - Msg("ogg 'cue' %d\n", com.atoi(comm) ); - //info->loopstart = bound( 0, com.atoi(comm), info->samples ); - } - } - - // close file - ov_clear( &vf ); - Mem_Free( data ); - *wav = buffer; // load the data - - return true; + // check first character + if( *pcht == '!' ) + pcht++; + return pcht; } /* @@ -438,31 +97,31 @@ static bool S_LoadOGG( const char *name, byte **wav, wavinfo_t *info ) S_UploadSound ================= */ -static void S_UploadSound( byte *data, wavinfo_t *info, sfx_t *sfx ) +static void S_UploadSound( wavdata_t *sc, sfx_t *sfx ) { - int size; - - // calculate buffer size - size = info->samples * info->width * info->channels; - sfx->loopstart = info->loopstart; - sfx->samples = info->samples; - sfx->rate = info->rate; + sfx->loopStart = sc->loopStart; + sfx->samples = sc->samples; + sfx->rate = sc->rate; + sfx->sampleStep = 1000 * ( sfx->rate / (float)sfx->samples ); // samples per second // Set buffer format - if( info->width == 2 ) + if( sc->width == 2 ) { - if( info->channels == 2 ) sfx->format = AL_FORMAT_STEREO16; + if( sc->channels == 2 ) + sfx->format = AL_FORMAT_STEREO16; else sfx->format = AL_FORMAT_MONO16; } else { - if( info->channels == 2 ) sfx->format = AL_FORMAT_STEREO8; + if( sc->channels == 2 ) + sfx->format = AL_FORMAT_STEREO8; else sfx->format = AL_FORMAT_MONO8; } // upload the sound palGenBuffers( 1, &sfx->bufferNum ); - palBufferData( sfx->bufferNum, sfx->format, data, size, sfx->rate ); + palBufferData( sfx->bufferNum, sfx->format, sc->buffer, sc->size, sfx->rate ); + FS_FreeSound( sc ); // don't need to keep this data S_CheckForErrors(); sfx->loaded = true; @@ -473,30 +132,35 @@ static void S_UploadSound( byte *data, wavinfo_t *info, sfx_t *sfx ) S_CreateDefaultSound ================= */ -static void S_CreateDefaultSound( byte **wav, wavinfo_t *info ) +static wavdata_t *S_CreateDefaultSound( void ) { - byte *out; + wavdata_t *sc; int i; - info->rate = 22050; - info->width = 2; - info->channels = 1; - info->samples = 11025; + sc = Z_Malloc( sizeof( wavdata_t )); - *wav = out = Z_Malloc( info->samples * info->width ); + sc->rate = 22050; + sc->width = 2; + sc->channels = 1; + sc->samples = 11025; + sc->loopStart = -1; + sc->size = sc->samples * sc->width * sc->channels; + sc->buffer = Z_Malloc( sc->size ); if( s_check_errors->integer ) { // create 1 kHz tone as default sound - for( i = 0; i < info->samples; i++ ) - ((short *)out)[i] = sin(i * 0.1f) * 20000; + for( i = 0; i < sc->samples; i++ ) + ((short *)sc->buffer)[i] = com.sin( i * 0.1f ) * 20000; } else { // create silent sound - for( i = 0; i < info->samples; i++ ) - ((short *)out)[i] = i; + for( i = 0; i < sc->samples; i++ ) + ((short *)sc->buffer)[i] = i; } + + return sc; } /* @@ -504,59 +168,25 @@ static void S_CreateDefaultSound( byte **wav, wavinfo_t *info ) S_LoadSound ================= */ -loadformat_t load_formats[] = -{ -{ "sound/%s.%s", "ogg", S_LoadOGG }, -{ "sound/%s.%s", "wav", S_LoadWAV }, -{ "%s.%s", "ogg", S_LoadOGG }, -{ "%s.%s", "wav", S_LoadWAV }, -{ NULL, NULL } -}; - bool S_LoadSound( sfx_t *sfx ) { - byte *data; - wavinfo_t info; - const char *ext; - string loadname, path; - loadformat_t *format; - bool anyformat; + wavdata_t *sc; if( !sfx ) return false; if( sfx->name[0] == '*' ) return false; - if( sfx->loaded ) return true; // see if still in memory + if( sfx->loaded ) return true; // see if still in memory // load it from disk - ext = FS_FileExtension( sfx->name ); - anyformat = !com.stricmp( ext, "" ) ? true : false; + sc = FS_LoadSound( sfx->name, NULL, 0 ); - com.strncpy( loadname, sfx->name, sizeof( loadname )); - FS_StripExtension( loadname ); // remove extension if needed - Mem_Set( &info, 0, sizeof( info )); - - // developer warning - if( !anyformat ) MsgDev( D_NOTE, "Note: %s will be loading only with ext .%s\n", loadname, ext ); - - // now try all the formats in the selected list - for( format = load_formats; format->formatstring; format++ ) + if( sc == NULL ) { - if( anyformat || !com.stricmp( ext, format->ext )) - { - com.sprintf( path, format->formatstring, loadname, format->ext ); - if( format->loadfunc( path, &data, &info )) - goto snd_loaded; - } + sc = S_CreateDefaultSound(); + sfx->default_sound = true; } - sfx->default_sound = true; - MsgDev( D_WARN, "FS_LoadSound: couldn't load %s\n", sfx->name ); - S_CreateDefaultSound( &data, &info ); - info.loopstart = -1; - -snd_loaded: - // load it in - S_UploadSound( data, &info, sfx ); - Mem_Free( data ); + // upload and resample + S_UploadSound( sc, sfx ); return true; } @@ -702,9 +332,6 @@ sound_t S_RegisterSound( const char *name ) { sfx_t *sfx; - if( !al_state.initialized ) - return -1; - sfx = S_FindSound( name ); if( !sfx ) return -1; diff --git a/snd_al/s_main.c b/snd_al/s_main.c index 3de0a0f5..b57c98bf 100644 --- a/snd_al/s_main.c +++ b/snd_al/s_main.c @@ -7,9 +7,9 @@ #include "const.h" #include "trace_def.h" -#define MAX_PLAYSOUNDS 256 -#define MAX_CHANNELS 64 -#define CSXROOM 29 +#define MAX_CHANNELS 128 +#define CSXROOM 29 +int MAX_DYNAMIC_CHANNELS = 24; // can be reduced by openAL limitations typedef struct { @@ -20,9 +20,6 @@ typedef struct } dsproom_t; static soundfade_t soundfade; -static playSound_t s_playSounds[MAX_PLAYSOUNDS]; -static playSound_t s_freePlaySounds; -static playSound_t s_pendingPlaySounds; static channel_t s_channels[MAX_CHANNELS]; static listener_t s_listener; @@ -87,7 +84,7 @@ bool S_CheckForErrors( void ) if( !s_check_errors->integer ) return false; - if((err = palGetError()) == AL_NO_ERROR) + if(( err = palGetError( )) == AL_NO_ERROR ) return false; switch( err ) @@ -196,6 +193,16 @@ void S_UpdateSoundFade( void ) soundfade.percent = soundfade.initial_percent * f; } +/* +================= +S_IsClient +================= +*/ +bool S_IsClient( int entnum ) +{ + return ( entnum == al_state.clientnum ); +} + /* ================= S_AllocChannels @@ -211,8 +218,16 @@ static void S_AllocChannels( void ) palGenSources( 1, &ch->sourceNum ); if( palGetError() != AL_NO_ERROR ) break; - al_state.num_channels++; + al_state.max_channels++; } + + if( al_state.max_channels <= MAX_DYNAMIC_CHANNELS ) + { + // there are not enough channels! + MAX_DYNAMIC_CHANNELS = (int)(al_state.max_channels / 3); + MsgDev( D_WARN, "S_AllocChannels: reduced dynamic channels count from 24 to %i\n", MAX_DYNAMIC_CHANNELS ); + } + al_state.initialized = true; } /* @@ -225,12 +240,12 @@ static void S_FreeChannels( void ) channel_t *ch; int i; - for( i = 0, ch = s_channels; i < al_state.num_channels; i++, ch++ ) + for( i = 0, ch = s_channels; i < al_state.max_channels; i++, ch++ ) { - palDeleteSources(1, &ch->sourceNum); - Mem_Set(ch, 0, sizeof(*ch)); + palDeleteSources( 1, &ch->sourceNum ); + Mem_Set( ch, 0, sizeof( *ch )); } - al_state.num_channels = 0; + al_state.max_channels = 0; } /* @@ -266,23 +281,37 @@ S_PlayChannel */ static void S_PlayChannel( channel_t *ch, sfx_t *sfx ) { + if( sfx == NULL ) + { + S_StopChannel( ch ); + return; + } ch->sfx = sfx; palSourcei( ch->sourceNum, AL_BUFFER, sfx->bufferNum ); - palSourcei( ch->sourceNum, AL_LOOPING, ch->loopsound ); + palSourcei( ch->sourceNum, AL_LOOPING, false ); palSourcei( ch->sourceNum, AL_SOURCE_RELATIVE, false ); palSourcei( ch->sourceNum, AL_SAMPLE_OFFSET, 0 ); - if( ch->loopstart >= 0 ) + if( ch->use_loop ) { - // kill any looping sounds - if( al_state.paused ) + if( ch->sfx->loopStart >= 0 ) { - palSourceStop( ch->sourceNum ); - return; + if( ch->state == CHAN_FIRSTPLAY ) + { + // play first from start, then from loopOffset + ch->state = CHAN_LOOPED; + } + else if( ch->state == CHAN_LOOPED ) + { + palSourcei( ch->sourceNum, AL_SAMPLE_OFFSET, sfx->loopStart ); + } + } + else + { + ch->state = CHAN_LOOPED; + palSourcei( ch->sourceNum, AL_LOOPING, true ); } - if( ch->state == CHAN_FIRSTPLAY ) ch->state = CHAN_LOOPED; - else if( ch->state == CHAN_LOOPED ) palSourcei( ch->sourceNum, AL_SAMPLE_OFFSET, sfx->loopstart ); } palSourcePlay( ch->sourceNum ); } @@ -294,25 +323,29 @@ S_SpatializeChannel */ static void S_SpatializeChannel( channel_t *ch ) { - vec3_t position, velocity; - + vec3_t position, velocity; + soundinfo_t SndInfo; + // update position and velocity - if( ch->entnum == al_state.clientnum || !ch->distanceMult ) + if( ch->entnum == al_state.clientnum || !ch->dist_mult ) { - palSourcefv(ch->sourceNum, AL_POSITION, s_listener.position); - palSourcefv(ch->sourceNum, AL_VELOCITY, s_listener.velocity); + palSourcefv( ch->sourceNum, AL_POSITION, s_listener.position ); + palSourcefv( ch->sourceNum, AL_VELOCITY, s_listener.velocity ); } else { - if( ch->fixedPosition ) + if( ch->staticsound ) { - palSource3f(ch->sourceNum, AL_POSITION, ch->position[1], ch->position[2], -ch->position[0]); - palSource3f(ch->sourceNum, AL_VELOCITY, 0, 0, 0); + palSource3f( ch->sourceNum, AL_POSITION, ch->position[1], ch->position[2], -ch->position[0] ); + palSource3f( ch->sourceNum, AL_VELOCITY, 0, 0, 0 ); } else { - if( ch->loopsound ) si.GetSoundSpatialization( ch->loopnum, position, velocity ); - else si.GetSoundSpatialization( ch->entnum, position, velocity ); + SndInfo.pOrigin = position; + SndInfo.pAngles = velocity; // FIXME: this is angles, not velocity + SndInfo.pflRadius = NULL; + + si.GetEntitySpatialization( ch->entnum, &SndInfo ); palSource3f( ch->sourceNum, AL_POSITION, position[1], position[2], -position[0] ); palSource3f( ch->sourceNum, AL_VELOCITY, velocity[1], velocity[2], -velocity[0] ); @@ -320,8 +353,8 @@ static void S_SpatializeChannel( channel_t *ch ) } // update min/max distance - if( ch->distanceMult ) - palSourcef( ch->sourceNum, AL_REFERENCE_DISTANCE, s_minDistance->value * ch->distanceMult ); + if( ch->dist_mult ) + palSourcef( ch->sourceNum, AL_REFERENCE_DISTANCE, s_minDistance->value * ch->dist_mult ); else palSourcef( ch->sourceNum, AL_REFERENCE_DISTANCE, s_maxDistance->value ); palSourcef( ch->sourceNum, AL_MAX_DISTANCE, s_maxDistance->value ); @@ -334,162 +367,186 @@ static void S_SpatializeChannel( channel_t *ch ) /* ================= -S_PickChannel +SND_PickDynamicChannel -Tries to find a free channel, or tries to replace an active channel +Select a channel from the dynamic channel allocation area. For the given entity, +override any other sound playing on the same channel (see code comments below for +exceptions). ================= */ -channel_t *S_PickChannel( int entnum, int channel ) +channel_t *SND_PickDynamicChannel( int entnum, int channel, sfx_t *sfx ) { - channel_t *ch; - int i; - int firstToDie = -1; - float oldestTime = Sys_DoubleTime(); + int ch_idx; + int first_to_die; + int life_left; - if( entnum < 0 || channel < 0 ) return NULL; // invalid channel or entnum + // check for replacement sound, or find the best one to replace + first_to_die = -1; + life_left = 0x7fffffff; - for( i = 0, ch = s_channels; i < al_state.num_channels; i++, ch++ ) + for( ch_idx = 0; ch_idx < MAX_DYNAMIC_CHANNELS; ch_idx++ ) { - // don't let game sounds override streaming sounds - if( ch->streaming ) continue; + channel_t *ch = &s_channels[ch_idx]; - // check if this channel is active - if( channel == CHAN_AUTO && !ch->sfx ) + // Never override a streaming sound that is currently playing or + // voice over IP data that is playing or any sound on CHAN_VOICE( acting ) + if( ch->sfx && ( ch->entchannel == CHAN_STREAM )) { - // free channel - firstToDie = i; - break; + continue; } - // channel 0 never overrides - if( channel != CHAN_AUTO && (ch->entnum == entnum && ch->entchannel == channel)) + if( channel != 0 && ch->entnum == entnum && ( ch->entchannel == channel || channel == -1 )) { // always override sound from same entity - firstToDie = i; + first_to_die = ch_idx; break; } + // don't let monster sounds override player sounds + if( ch->sfx && S_IsClient( ch->entnum ) && !S_IsClient( entnum )) + continue; + // don't let monster sounds override player sounds if( entnum != al_state.clientnum && ch->entnum == al_state.clientnum ) continue; // replace the oldest sound - if( ch->startTime < oldestTime ) + if( ch->startTime < life_left ) { - oldestTime = ch->startTime; - firstToDie = i; + life_left = ch->startTime; + first_to_die = ch_idx; } } - if( firstToDie == -1 ) return NULL; - ch = &s_channels[firstToDie]; + if( first_to_die == -1 ) + return NULL; - ch->entnum = entnum; - ch->entchannel = channel; - ch->startTime = Sys_DoubleTime(); - ch->state = CHAN_NORMAL; // remove any loop sound - ch->loopsound = false; // clear loopstate - ch->loopstart = -1; + if( s_channels[first_to_die].sfx ) + { + // don't restart looping sounds for the same entity + if( sfx->loopStart != -1 ) + { + channel_t *ch = &s_channels[first_to_die]; - // make sure this channel is stopped - S_StopChannel( ch ); + if( ch->entnum == entnum && ch->entchannel == channel && ch->sfx == sfx ) + { + // same looping sound, same ent, same channel, don't restart the sound + return NULL; + } + } + // be sure and release previous channel if sentence. + S_StopChannel( &( s_channels[first_to_die] )); + } + + return &s_channels[first_to_die]; +} + +/* +===================== +SND_PickStaticChannel + +Pick an empty channel from the static sound area, or allocate a new +channel. Only fails if we're at max_channels (128!!!) or if +we're trying to allocate a channel for a stream sound that is +already playing. +===================== +*/ +channel_t *SND_PickStaticChannel( int entnum, sfx_t *sfx ) +{ + channel_t *ch = NULL; + int i; + + // check for replacement sound, or find the best one to replace + for( i = MAX_DYNAMIC_CHANNELS; i < al_state.total_channels; i++ ) + { + if( s_channels[i].sfx == NULL ) + break; + } + + if( i < al_state.total_channels ) + { + // reuse an empty static sound channel + ch = &s_channels[i]; + } + else + { + // no empty slots, alloc a new static sound channel + if( al_state.total_channels >= al_state.max_channels ) + { + MsgDev( D_ERROR, "S_PickChannel: no free channels\n" ); + return NULL; + } + // get a channel for the static sound + ch = &s_channels[al_state.total_channels]; + al_state.total_channels++; + } return ch; } /* ================= -S_AllocPlaySound +S_AlterChannel + +search through all channels for a channel that matches this +soundsource, entchannel and sfx, and perform alteration on channel +as indicated by 'flags' parameter. If shut down request and +sfx contains a sentence name, shut off the sentence. +returns TRUE if sound was altered, +returns FALSE if sound was not found (sound is not playing) ================= */ -static playSound_t *S_AllocPlaySound( void ) +int S_AlterChannel( int entnum, int channel, sfx_t *sfx, float vol, int pitch, int flags ) { - playSound_t *ps; + channel_t *ch; + int i; - ps = s_freePlaySounds.next; - if( ps == &s_freePlaySounds ) - return NULL; // No free playSounds - - // unlink from freelist - ps->prev->next = ps->next; - ps->next->prev = ps->prev; - - return ps; -} - -/* -================= -S_FreePlaySound -================= -*/ -static void S_FreePlaySound( playSound_t *ps ) -{ - // unlink from channel - ps->prev->next = ps->next; - ps->next->prev = ps->prev; - - // add to free list - ps->next = s_freePlaySounds.next; - s_freePlaySounds.next->prev = ps; - ps->prev = &s_freePlaySounds; - s_freePlaySounds.next = ps; -} - -/* - ================= -S_IssuePlaySounds - -Take all the pending playSounds and begin playing them. -This is never called directly by S_Start*, but only by the update loop. -================= -*/ -static void S_IssuePlaySounds( void ) -{ - playSound_t *ps; - channel_t *ch; - - while( 1 ) + if( S_TestSoundChar( sfx->name, '!' )) { - ps = s_pendingPlaySounds.next; + // This is a sentence name. + // For sentences: assume that the entity is only playing one sentence + // at a time, so we can just shut off + // any channel that has ch->isSentence >= 0 and matches the entnum. - if( ps == &s_pendingPlaySounds ) - break; // no more pending playSounds - - if( ps->beginTime > Sys_DoubleTime( )) - break; // No more pending playSounds this frame - - // pick a channel and start the sound effect - ch = S_PickChannel( ps->entnum, ps->entchannel ); - if( !ch ) + for( i = 0, ch = s_channels; i < al_state.total_channels; i++, ch++ ) { - if( ps->sfx->name[0] == '#' ) MsgDev( D_ERROR, "dropped sound %s\n", &ps->sfx->name[1] ); - else MsgDev( D_ERROR, "dropped sound \"sound/%s\"\n", ps->sfx->name ); - S_FreePlaySound( ps ); - continue; + if( ch->entnum == entnum && ch->entchannel == channel && ch->sfx && ch->isSentence ) + { + if( flags & SND_CHANGE_PITCH ) + ch->pitch = pitch / (float)PITCH_NORM; + + if( flags & SND_CHANGE_VOL ) + ch->volume = vol; + + if( flags & SND_STOP ) + S_StopChannel( ch ); + + return true; + } } + // channel not found + return false; - // check for looping sounds with "cue " marker - if( ps->use_loop && ps->sfx->loopstart >= 0 ) - { - // jump to loopstart at next playing - ch->state = CHAN_FIRSTPLAY; - ch->loopstart = ps->sfx->loopstart; - } - - ch->fixedPosition = ps->fixedPosition; - VectorCopy( ps->position, ch->position ); - ch->volume = ps->volume; - ch->pitch = ps->pitch; - - if( ps->attenuation != ATTN_NONE ) ch->distanceMult = 1.0 / ps->attenuation; - else ch->distanceMult = 0.0; - - S_SpatializeChannel( ch ); - S_PlayChannel( ch, ps->sfx ); - - // free the playSound - S_FreePlaySound( ps ); } + + // regular sound or streaming sound + for( i = 0, ch = s_channels; i < al_state.total_channels; i++, ch++ ) + { + if( ch->entnum == entnum && ch->entchannel == channel && ch->sfx ) + { + if( flags & SND_CHANGE_PITCH ) + ch->pitch = pitch / (float)PITCH_NORM; + + if( flags & SND_CHANGE_VOL ) + ch->volume = vol; + + if( flags & SND_STOP ) + S_StopChannel( ch ); + + return true; + } + } + return false; } /* @@ -501,53 +558,146 @@ if origin is NULL, the sound will be dynamically sourced from the entity. entchannel 0 will never override a playing sound. ================= */ -void S_StartSound( const vec3_t pos, int entnum, int channel, sound_t handle, float vol, float attn, int pitch, int flags ) +void S_StartSound( const vec3_t pos, int ent, int chan, sound_t handle, float fvol, float attn, int pitch, int flags ) { - playSound_t *ps, *sort; - sfx_t *sfx = NULL; + sfx_t *sfx = NULL; + channel_t *target_chan; + int vol, fsentence = 0; - if( !al_state.initialized ) - return; sfx = S_GetSfxByHandle( handle ); if( !sfx ) return; + vol = bound( 0, fvol * 255, 255 ); + + if( flags & ( SND_STOP|SND_CHANGE_VOL|SND_CHANGE_PITCH )) + { + if( S_AlterChannel( ent, chan, sfx, vol, pitch, flags )) + return; + + if( flags & SND_STOP ) return; + // fall through - if we're not trying to stop the sound, + // and we didn't find it (it's not playing), go ahead and start it up + } + + if( pitch == 0 ) + { + MsgDev( D_WARN, "S_StartSound: ( %s ) ignored, called with pitch 0\n", sfx->name ); + return; + } + + if( !pos ) pos = vec3_origin; + + // pick a channel to play on + target_chan = SND_PickDynamicChannel( ent, chan, sfx ); + if( !target_chan ) + { + MsgDev( D_ERROR, "dropped sound \"sound/%s\"\n", sfx->name ); + return; + } + + target_chan->entnum = ent; + target_chan->entchannel = chan; + target_chan->startTime = Sys_Milliseconds(); + VectorCopy( pos, target_chan->position ); + target_chan->volume = vol; + target_chan->entnum = ent; + target_chan->entchannel = chan; + target_chan->isSentence = false; + target_chan->dist_mult = (attn / 1000.0f); + target_chan->state = CHAN_FIRSTPLAY; + target_chan->sfx = sfx; + target_chan->pitch = pitch / (float)PITCH_NORM; + // make sure the sound is loaded if( !S_LoadSound( sfx )) - return; - - // allocate a playSound - ps = S_AllocPlaySound(); - if( !ps ) { - if( sfx->name[0] == '#' ) MsgDev( D_ERROR, "dropped sound %s\n", &sfx->name[1] ); - else MsgDev( D_ERROR, "dropped sound \"sound/%s\"\n", sfx->name ); + S_StopChannel( target_chan ); return; } - ps->sfx = sfx; - ps->entnum = entnum; - ps->entchannel = channel; - ps->use_loop = (flags & (SND_STOP_LOOPING|SND_STOP)) ? false : true; + // only using loop for looped sounds + if( flags & SND_STOP_LOOPING ) + target_chan->use_loop = false; + else target_chan->use_loop = ( sfx->loopStart == -1 ) ? false : true; - if( pos ) - { - ps->fixedPosition = true; - VectorCopy( pos, ps->position ); - } - else ps->fixedPosition = false; + S_SpatializeChannel( target_chan ); + S_PlayChannel( target_chan, sfx ); +} + +/* +================= +S_StartStaticSound + +Start playback of a sound, loaded into the static portion of the channel array. +Currently, this should be used for looping ambient sounds, looping sounds +that should not be interrupted until complete, non-creature sentences, +and one-shot ambient streaming sounds. Can also play 'regular' sounds one-shot, +in case designers want to trigger regular game sounds. +Pitch changes playback pitch of wave by % above or below 100. Ignored if pitch == 100 + +NOTE: volume is 0.0 - 1.0 and attenuation is 0.0 - 1.0 when passed in. +================= +*/ +void S_StaticSound( const vec3_t pos, int ent, int chan, sound_t handle, float fvol, float attn, int pitch, int flags ) +{ + channel_t *ch; + sfx_t *sfx = NULL; + int vol, fvox = 0; - ps->volume = vol; - ps->pitch = pitch / PITCH_NORM; - ps->attenuation = attn; - ps->beginTime = Sys_DoubleTime(); + sfx = S_GetSfxByHandle( handle ); + if( !sfx ) return; - // sort into the pending playSounds list - for( sort = s_pendingPlaySounds.next; sort != &s_pendingPlaySounds && sort->beginTime < ps->beginTime; sort = sort->next ); + vol = bound( 0, fvol * 255, 255 ); - ps->next = sort; - ps->prev = sort->prev; - ps->next->prev = ps; - ps->prev->next = ps; + if( flags & (SND_STOP|SND_CHANGE_VOL|SND_CHANGE_PITCH)) + { + if( S_AlterChannel( ent, chan, sfx, vol, pitch, flags )) + return; + if( flags & SND_STOP ) return; + } + + if( pitch == 0 ) + { + MsgDev( D_WARN, "S_StartStaticSound: ( %s ) ignored, called with pitch 0\n", sfx->name ); + return; + } + + if( !pos ) pos = vec3_origin; + + // pick a channel to play on from the static area + ch = SND_PickStaticChannel( ent, sfx ); // autolooping sounds are always fixed origin(?) + if( !ch ) return; + + // make sure the sound is loaded + if( !S_LoadSound( sfx )) + { + S_StopChannel( ch ); + return; + } + + VectorCopy( pos, ch->position ); + + ch->entnum = ent; + ch->entchannel = chan; + ch->startTime = Sys_Milliseconds(); + ch->state = CHAN_FIRSTPLAY; + VectorCopy( pos, ch->position ); + ch->volume = vol; + ch->entnum = ent; + ch->entchannel = chan; + ch->isSentence = false; + ch->dist_mult = (attn / 1000.0f); + ch->sfx = sfx; + ch->pitch = pitch / (float)PITCH_NORM; + ch->staticsound = true; + + // only using loop for looped sounds + if( flags & SND_STOP_LOOPING ) + ch->use_loop = false; + else ch->use_loop = ( sfx->loopStart == -1 ) ? false : true; + + S_SpatializeChannel( ch ); + S_PlayChannel( ch, sfx ); } /* @@ -561,9 +711,6 @@ bool S_StartLocalSound( const char *name, float volume, int pitch, const float * { sound_t sfxHandle; - if( !al_state.initialized ) - return false; - sfxHandle = S_RegisterSound( name ); S_StartSound( origin, al_state.clientnum, CHAN_AUTO, sfxHandle, volume, ATTN_NONE, pitch, SND_STOP_LOOPING ); return true; @@ -576,9 +723,22 @@ S_StopAllSounds stop all sounds for entity on a channel. ================== */ -void S_StopSound( int entnum, int channel ) +void S_StopSound( int entnum, int channel, const char *soundname ) { - S_StopAllSounds(); // FIXME: this is incorrect! + int i; + + for( i = 0; i < al_state.total_channels; i++ ) + { + channel_t *ch = &s_channels[i]; + + if( !ch->sfx ) continue; // already freed + if( ch->entnum == entnum && ch->entchannel == channel ) + { + if( soundname && com.strcmp( ch->sfx->name, soundname )) + continue; + S_StopChannel( ch ); + } + } } /* @@ -591,25 +751,10 @@ void S_StopAllSounds( void ) channel_t *ch; int i; - if( !al_state.initialized ) - return; - - // Clear all the playSounds - Mem_Set( s_playSounds, 0, sizeof(s_playSounds)); - - s_freePlaySounds.next = s_freePlaySounds.prev = &s_freePlaySounds; - s_pendingPlaySounds.next = s_pendingPlaySounds.prev = &s_pendingPlaySounds; - - for( i = 0; i < MAX_PLAYSOUNDS; i++ ) - { - s_playSounds[i].prev = &s_freePlaySounds; - s_playSounds[i].next = s_freePlaySounds.next; - s_playSounds[i].prev->next = &s_playSounds[i]; - s_playSounds[i].next->prev = &s_playSounds[i]; - } + al_state.total_channels = MAX_DYNAMIC_CHANNELS; // no statics // Stop all the channels - for( i = 0, ch = s_channels; i < al_state.num_channels; i++, ch++ ) + for( i = 0, ch = s_channels; i < al_state.max_channels; i++, ch++ ) { if( !ch->sfx ) continue; S_StopChannel( ch ); @@ -661,8 +806,7 @@ void S_Update( ref_params_t *fd ) channel_t *ch; int i; - if( !al_state.initialized || !fd ) - return; + if( !fd ) return; // bump frame count al_state.framecount++; @@ -671,7 +815,8 @@ void S_Update( ref_params_t *fd ) al_state.refdef = fd; // for using everthing else // update any client side sound fade - if( !fd->paused ) S_UpdateSoundFade(); + if( !fd->paused && si.IsInGame( )) + S_UpdateSoundFade(); // set up listener VectorSet( s_listener.position, fd->simorg[1], fd->simorg[2], -fd->simorg[0] ); @@ -694,34 +839,32 @@ void S_Update( ref_params_t *fd ) // Set state palDistanceModel( AL_INVERSE_DISTANCE_CLAMPED ); - palDopplerFactor(s_dopplerFactor->value); - palDopplerVelocity(s_dopplerVelocity->value); + palDopplerFactor( s_dopplerFactor->value ); + palDopplerVelocity( s_dopplerVelocity->value ); S_AddEnvironmentEffects (); // Stream background track - S_StreamBackgroundTrack(); - - // Issue playSounds - S_IssuePlaySounds(); + S_StreamBackgroundTrack (); // update spatialization for all sounds - for( i = 0, ch = s_channels; i < al_state.num_channels; i++, ch++ ) + for( i = 0, ch = s_channels; i < al_state.total_channels; i++, ch++ ) { if( !ch->sfx ) continue; // not active // check for stop - if( ch->loopsound ) + if( ch->use_loop && ch->sfx->loopStart >= 0 ) { - if( ch->loopframe != al_state.framecount ) + int samplePos; + + palGetSourcei( ch->sourceNum, AL_SAMPLE_OFFSET, &samplePos ); + + if( samplePos + ch->sfx->sampleStep >= ch->sfx->samples ) { - S_StopChannel( ch ); - continue; + Msg( "restart %s\n", ch->sfx->name ); + palSourcei( ch->sourceNum, AL_SAMPLE_OFFSET, ch->sfx->loopStart ); } - } - else if( ch->loopstart >= 0 && ch->volume > 0.0f ) - { - if( S_ChannelState( ch ) == AL_STOPPED ) + else if( S_ChannelState( ch ) == AL_STOPPED ) { S_PlayChannel( ch, ch->sfx ); } @@ -751,12 +894,9 @@ and an activate. */ void S_Activate( bool active ) { - if(!al_state.initialized ) - return; - al_state.active = active; - if( active ) palListenerf( AL_GAIN, S_GetMasterVolume() ); - else palListenerf( AL_GAIN, 0.0 ); + if( active ) palListenerf( AL_GAIN, S_GetMasterVolume( )); + else palListenerf( AL_GAIN, 0.0f ); } /* @@ -805,22 +945,16 @@ S_SoundInfo_f */ void S_SoundInfo_f( void ) { - if(!al_state.initialized ) - { - Msg("Sound system not started\n"); - return; - } - - Msg("\n"); - Msg("AL_VENDOR: %s\n", al_config.vendor_string); - Msg("AL_RENDERER: %s\n", al_config.renderer_string); - Msg("AL_VERSION: %s\n", al_config.version_string); - Msg("AL_EXTENSIONS: %s\n", al_config.extensions_string); - Msg("\n"); - Msg("DEVICE: %s\n", s_alDevice->string ); - Msg("CHANNELS: %i\n", al_state.num_channels); - Msg("3D sound: %s\n", (al_config.allow_3DMode) ? "enabled" : "disabled" ); - Msg("\n"); + Msg( "\n" ); + Msg( "AL_VENDOR: %s\n", al_config.vendor_string ); + Msg( "AL_RENDERER: %s\n", al_config.renderer_string ); + Msg( "AL_VERSION: %s\n", al_config.version_string ); + Msg( "AL_EXTENSIONS: %s\n", al_config.extensions_string ); + Msg( "\n" ); + Msg( "DEVICE: %s\n", s_alDevice->string ); + Msg( "CHANNELS: %i\n", al_state.max_channels ); + Msg( "3D sound: %s\n", (al_config.allow_3DMode) ? "enabled" : "disabled" ); + Msg( "\n" ); } /* @@ -859,12 +993,11 @@ bool S_Init( void *hInst ) return false; } - palcGetIntegerv( al_state.hDevice, ALC_MONO_SOURCES, sizeof(int), &num_mono_src ); - palcGetIntegerv( al_state.hDevice, ALC_STEREO_SOURCES, sizeof(int), &num_stereo_src ); + palcGetIntegerv( al_state.hDevice, ALC_MONO_SOURCES, sizeof( int ), &num_mono_src ); + palcGetIntegerv( al_state.hDevice, ALC_STEREO_SOURCES, sizeof( int ), &num_stereo_src ); MsgDev( D_NOTE, "S_Init: mono sources %d, stereo %d\n", num_mono_src, num_stereo_src ); sndpool = Mem_AllocPool( "Sound Zone" ); - al_state.initialized = true; S_AllocChannels(); S_StopAllSounds(); @@ -892,13 +1025,9 @@ void S_Shutdown( void ) Cmd_RemoveCommand( "s_info" ); Cmd_RemoveCommand( "soundlist" ); - if( !al_state.initialized ) - return; - S_FreeSounds(); S_FreeChannels(); Mem_FreePool( &sndpool ); S_Free_OpenAL(); - al_state.initialized = false; } \ No newline at end of file diff --git a/snd_al/s_openal.c b/snd_al/s_openal.c index 52847e5f..3ff0e022 100644 --- a/snd_al/s_openal.c +++ b/snd_al/s_openal.c @@ -132,27 +132,30 @@ S_InitDriver */ static bool S_InitDriver( void ) { - int attrlist[3] = { ALC_FREQUENCY, 44100, 0 }; - int *al_contxt = attrlist; + int attrlist[3] = { ALC_FREQUENCY, 44100, 0 }; + int *al_contxt = attrlist; - if((al_state.hDevice = palcOpenDevice( s_alDevice->string )) == NULL) + if(( al_state.hDevice = palcOpenDevice( s_alDevice->string )) == NULL ) { Msg("alOpenDevice - failed\n" ); return false; } - if((al_state.hALC = palcCreateContext( al_state.hDevice, al_contxt )) == NULL) + + if(( al_state.hALC = palcCreateContext( al_state.hDevice, al_contxt )) == NULL ) goto failed; - if(!palcMakeContextCurrent(al_state.hALC)) + + if( !palcMakeContextCurrent( al_state.hALC )) goto failed; return true; failed: - if(al_state.hALC) + if( al_state.hALC ) { palcDestroyContext( al_state.hALC ); al_state.hALC = NULL; } - if(al_state.hDevice) + + if( al_state.hDevice ) { palcCloseDevice( al_state.hDevice ); al_state.hDevice = NULL; @@ -171,11 +174,11 @@ static bool S_SetupEFX( void ) const dllfunc_t *func; // get the function pointers - for(func = openal_effects; func && func->name != NULL; func++) + for( func = openal_effects; func && func->name != NULL; func++ ) { - if (!(*func->func = palGetProcAddress( func->name ))) + if( !( *func->func = palGetProcAddress( func->name ))) { - MsgDev(D_ERROR, "S_InitEffects: %s missing or invalid function\n", func->name ); + MsgDev( D_ERROR, "S_InitEffects: %s missing or invalid function\n", func->name ); return false; } } @@ -190,31 +193,31 @@ static void S_InitEffects( void ) if( palGetError() == AL_NO_ERROR ) { MsgDev( D_NOTE, "S_InitEffects:" ); - alEffecti(uiEffects[0], AL_EFFECT_TYPE, AL_EFFECT_REVERB); + alEffecti( uiEffects[0], AL_EFFECT_TYPE, AL_EFFECT_REVERB ); if(!palGetError()) MsgDev( D_NOTE, " ^3al_ext_revrb" ); - alEffecti(uiEffects[0], AL_EFFECT_TYPE, AL_EFFECT_EAXREVERB); + alEffecti( uiEffects[0], AL_EFFECT_TYPE, AL_EFFECT_EAXREVERB ); if(!palGetError()) MsgDev( D_NOTE, " ^3al_ext_eaxrevrb" ); - alEffecti(uiEffects[0], AL_EFFECT_TYPE, AL_EFFECT_CHORUS); + alEffecti( uiEffects[0], AL_EFFECT_TYPE, AL_EFFECT_CHORUS ); if(!palGetError()) MsgDev( D_NOTE, " ^3al_ext_chorus" ); - alEffecti(uiEffects[0], AL_EFFECT_TYPE, AL_EFFECT_DISTORTION); + alEffecti( uiEffects[0], AL_EFFECT_TYPE, AL_EFFECT_DISTORTION ); if(!palGetError()) MsgDev( D_NOTE, " ^3al_ext_distortion" ); - alEffecti(uiEffects[0], AL_EFFECT_TYPE, AL_EFFECT_ECHO); + alEffecti( uiEffects[0], AL_EFFECT_TYPE, AL_EFFECT_ECHO ); if(!palGetError()) MsgDev( D_NOTE, " ^3al_ext_echo" ); - alEffecti(uiEffects[0], AL_EFFECT_TYPE, AL_EFFECT_FLANGER); + alEffecti( uiEffects[0], AL_EFFECT_TYPE, AL_EFFECT_FLANGER ); if(!palGetError()) MsgDev( D_NOTE, " ^3al_ext_flanger" ); - alEffecti(uiEffects[0], AL_EFFECT_TYPE, AL_EFFECT_FREQUENCY_SHIFTER); + alEffecti( uiEffects[0], AL_EFFECT_TYPE, AL_EFFECT_FREQUENCY_SHIFTER ); if(!palGetError()) MsgDev( D_NOTE, " ^3al_ext_frequency_shifter" ); - alEffecti(uiEffects[0], AL_EFFECT_TYPE, AL_EFFECT_VOCAL_MORPHER); + alEffecti( uiEffects[0], AL_EFFECT_TYPE, AL_EFFECT_VOCAL_MORPHER ); if(!palGetError()) MsgDev( D_NOTE, " ^3al_ext_vocal_morpher" ); - alEffecti(uiEffects[0], AL_EFFECT_TYPE, AL_EFFECT_PITCH_SHIFTER); + alEffecti( uiEffects[0], AL_EFFECT_TYPE, AL_EFFECT_PITCH_SHIFTER ); if(!palGetError()) MsgDev( D_NOTE, " ^3al_ext_pitch_shifter" ); - alEffecti(uiEffects[0], AL_EFFECT_TYPE, AL_EFFECT_RING_MODULATOR); + alEffecti( uiEffects[0], AL_EFFECT_TYPE, AL_EFFECT_RING_MODULATOR ); if(!palGetError()) MsgDev( D_NOTE, " ^3al_ext_ring_modulator" ); - alEffecti(uiEffects[0], AL_EFFECT_TYPE, AL_EFFECT_AUTOWAH); + alEffecti( uiEffects[0], AL_EFFECT_TYPE, AL_EFFECT_AUTOWAH ); if(!palGetError()) MsgDev( D_NOTE, " ^3al_ext_autowah" ); - alEffecti(uiEffects[0], AL_EFFECT_TYPE, AL_EFFECT_COMPRESSOR); + alEffecti( uiEffects[0], AL_EFFECT_TYPE, AL_EFFECT_COMPRESSOR ); if(!palGetError()) MsgDev( D_NOTE, " ^3al_ext_compressor" ); - alEffecti(uiEffects[0], AL_EFFECT_TYPE, AL_EFFECT_EQUALIZER); + alEffecti( uiEffects[0], AL_EFFECT_TYPE, AL_EFFECT_EQUALIZER ); if(!palGetError()) MsgDev( D_NOTE, " ^3al_ext_equalizer" ); MsgDev( D_NOTE, "\n" ); } @@ -229,15 +232,15 @@ static void S_InitFilters( void ) if( palGetError() == AL_NO_ERROR ) { MsgDev( D_NOTE, "S_InitFilters:" ); - alFilteri(uiFilters[0], AL_FILTER_TYPE, AL_FILTER_LOWPASS); + alFilteri( uiFilters[0], AL_FILTER_TYPE, AL_FILTER_LOWPASS ); if(!palGetError()) MsgDev( D_NOTE, " ^3al_ext_lowpass" ); - alFilteri(uiFilters[0], AL_FILTER_TYPE, AL_FILTER_HIGHPASS); + alFilteri( uiFilters[0], AL_FILTER_TYPE, AL_FILTER_HIGHPASS ); if(!palGetError()) MsgDev( D_NOTE, " ^3al_ext_highpass" ); - alFilteri(uiFilters[0], AL_FILTER_TYPE, AL_FILTER_BANDPASS); + alFilteri( uiFilters[0], AL_FILTER_TYPE, AL_FILTER_BANDPASS ); if(!palGetError()) MsgDev( D_NOTE, " ^3al_ext_bandpass" ); MsgDev( D_NOTE, "\n" ); } - alDeleteFilters(1, &uiFilters[0]); + alDeleteFilters( 1, &uiFilters[0] ); } /* @@ -259,8 +262,8 @@ static void S_InitExtensions( void ) // check I3DL2 extension for NVidia's Sound Storm chips. I3DL2 is hidden and can be missed in extension list. if( !com.strcmp( NVIDIA_DEVICE_NAME, al_config.deviceList[0] )) { - I3DL2Get = (void *)palGetProcAddress("I3DL2Get"); - I3DL2Set = (void *)palGetProcAddress("I3DL2Set"); + I3DL2Get = (void *)palGetProcAddress( "I3DL2Get" ); + I3DL2Set = (void *)palGetProcAddress( "I3DL2Set" ); if( I3DL2Get && I3DL2Set ) { al_config.allow_3DMode = true; @@ -269,7 +272,7 @@ static void S_InitExtensions( void ) MsgDev( D_NOTE, "S_InitExtensions: enable I3DL2\n" ); } } - if( palIsExtensionPresent("EAX3.0") && !al_config.allow_3DMode ) + if( palIsExtensionPresent( "EAX3.0" ) && !al_config.allow_3DMode ) { alEAXSet = (void *)palGetProcAddress( "EAXSet" ); alEAXGet = (void *)palGetProcAddress( "EAXGet" ); @@ -281,7 +284,7 @@ static void S_InitExtensions( void ) MsgDev( D_NOTE, "S_InitExtensions: enable EAX 3.0\n" ); } } - if( palIsExtensionPresent("EAX2.0") && !al_config.allow_3DMode ) + if( palIsExtensionPresent( "EAX2.0" ) && !al_config.allow_3DMode ) { alEAXSet = (void *)palGetProcAddress( "EAXSet" ); alEAXGet = (void *)palGetProcAddress( "EAXGet" ); @@ -293,7 +296,7 @@ static void S_InitExtensions( void ) MsgDev( D_NOTE, "S_InitExtensions: enable EAX 2.0\n" ); } } - if( palIsExtensionPresent("EAX") && !al_config.allow_3DMode ) + if( palIsExtensionPresent( "EAX" ) && !al_config.allow_3DMode ) { alEAXSet = (void *)palGetProcAddress( "EAXSet" ); alEAXGet = (void *)palGetProcAddress( "EAXGet" ); @@ -306,18 +309,17 @@ static void S_InitExtensions( void ) } } - if(palcIsExtensionPresent( al_state.hDevice, "ALC_EXT_EFX")) + if( palcIsExtensionPresent( al_state.hDevice, "ALC_EXT_EFX" )) { - uint uiEffectSlots[MAX_EFFECTS] = { 0 }; - if(!S_SetupEFX()) return; + if( !S_SetupEFX( )) return; // testing effect slots for( al_config.num_slots = 0; al_config.num_slots < MAX_EFFECTS; al_config.num_slots++ ) { alGenAuxiliaryEffectSlots( 1, &uiEffectSlots[al_config.num_slots] ); - if( palGetError() != AL_NO_ERROR) break; + if( palGetError() != AL_NO_ERROR ) break; } palcGetIntegerv( al_state.hDevice, ALC_MAX_AUXILIARY_SENDS, 1, &al_config.num_sends ); @@ -340,7 +342,7 @@ bool S_Init_OpenAL( void ) } // Get device list - if( palcIsExtensionPresent( NULL, "ALC_ENUMERATION_EXT")) + if( palcIsExtensionPresent( NULL, "ALC_ENUMERATION_EXT" )) { // get list of devices const char *device_enum = palcGetString( NULL, ALC_DEVICE_SPECIFIER ); @@ -361,13 +363,13 @@ bool S_Init_OpenAL( void ) } // initialize the device, context, etc... - if(!S_InitDriver()) return false; + if( !S_InitDriver( )) return false; // get some openal strings - al_config.vendor_string = palGetString(AL_VENDOR); - al_config.renderer_string = palGetString(AL_RENDERER); // stupid name :) - al_config.version_string = palGetString(AL_VERSION); - al_config.extensions_string = palGetString(AL_EXTENSIONS); + al_config.vendor_string = palGetString( AL_VENDOR ); + al_config.renderer_string = palGetString( AL_RENDERER ); // stupid name :-) + al_config.version_string = palGetString( AL_VERSION ); + al_config.extensions_string = palGetString( AL_EXTENSIONS ); MsgDev( D_INFO, "Audio: %s\n", al_config.renderer_string ); // Initialize extensions @@ -386,6 +388,7 @@ void S_Free_OpenAL( void ) palcDestroyContext( al_state.hALC ); al_state.hALC = NULL; } + if( al_state.hDevice ) { if( palcCloseDevice ) @@ -394,6 +397,6 @@ void S_Free_OpenAL( void ) } Sys_FreeLibrary( &openal_dll ); - Mem_Set(&al_config, 0, sizeof(alconfig_t)); - Mem_Set(&al_state, 0, sizeof(alstate_t)); + Mem_Set( &al_config, 0, sizeof( alconfig_t )); + Mem_Set( &al_state, 0, sizeof( alstate_t )); } \ No newline at end of file diff --git a/snd_al/s_stream.c b/snd_al/s_stream.c index 1d890c0a..44bdabce 100644 --- a/snd_al/s_stream.c +++ b/snd_al/s_stream.c @@ -210,8 +210,6 @@ S_StartBackgroundTrack */ void S_StartBackgroundTrack( const char *introTrack, const char *loopTrack ) { - if( !al_state.initialized ) return; - // stop any playing tracks S_StopBackgroundTrack(); @@ -237,8 +235,6 @@ S_StopBackgroundTrack */ void S_StopBackgroundTrack( void ) { - if( !al_state.initialized ) return; - S_StopStreaming(); S_CloseBackgroundTrack(&s_bgTrack); Mem_Set(&s_bgTrack, 0, sizeof(bg_track_t)); @@ -251,13 +247,12 @@ S_StartStreaming */ void S_StartStreaming( void ) { - if( !al_state.initialized ) return; if( s_streamingChannel ) return; // already started - s_streamingChannel = S_PickChannel( 0, 0 ); + s_streamingChannel = SND_PickStaticChannel( 0, NULL ); if( !s_streamingChannel ) return; - s_streamingChannel->streaming = true; + s_streamingChannel->entchannel = CHAN_STREAM; // FIXME: OpenAL bug? //palDeleteSources(1, &s_streamingChannel->sourceNum); @@ -287,7 +282,7 @@ void S_StopStreaming( void ) if( !al_state.initialized ) return; if( !s_streamingChannel ) return; // already stopped - s_streamingChannel->streaming = false; + s_streamingChannel->entchannel = CHAN_AUTO; // clean up the source palSourceStop(s_streamingChannel->sourceNum); diff --git a/snd_al/sound.h b/snd_al/sound.h index 4a5a576e..4da6db29 100644 --- a/snd_al/sound.h +++ b/snd_al/sound.h @@ -37,22 +37,14 @@ enum CHAN_NORMAL, }; -typedef struct -{ - int rate; - int width; - int loopstart; - int channels; - int samples; -} wavinfo_t; - typedef struct sfx_s { string name; bool loaded; - int loopstart; // looping point (in samples) + int loopStart; // looping point (in samples) int samples; int rate; + int sampleStep; // ( samples / rate ) * 100 uint format; uint bufferNum; @@ -74,24 +66,6 @@ typedef struct void *vorbisFile; } bg_track_t; -// a playSound will be generated by each call to S_StartSound. -// when the mixer reaches playSound->beginTime, the playSound will be -// assigned to a channel. -typedef struct playsound_s -{ - struct playsound_s *prev, *next; - sfx_t *sfx; - int entnum; - int entchannel; - bool fixedPosition; // Use position instead of fetching entity's origin - bool use_loop; // ignore looping sounds for local sound - vec3_t position; // Only use if fixedPosition is set - float volume; - float attenuation; - float beginTime; // Begin at this time - float pitch; -} playSound_t; - // structure used for fading in and out client sound volume. typedef struct { @@ -105,24 +79,20 @@ typedef struct typedef struct { - bool streaming; sfx_t *sfx; // NULL if unused int state; // channel state + int entnum; // to allow overriding a specific sound int entchannel; - float startTime; // for overriding oldest sounds - - bool loopsound; // is looping sound ? - int loopnum; // looping entity number - int loopframe; // for stopping looping sounds - int loopstart; // check it for set properly offset in samples - - bool fixedPosition; // use position instead of fetching entity's origin + uint startTime; // for overriding oldest sounds + bool staticsound; // use position instead of fetching entity's origin vec3_t position; // only use if fixedPosition is set float volume; - float pitch; - float distanceMult; + float pitch; // real-time pitch after any modulation or shift by dynamic data + float dist_mult; uint sourceNum; // openAL source + bool use_loop; // don't loop default and local sounds + bool isSentence; // bit who indicated sentence } channel_t; typedef struct @@ -164,14 +134,15 @@ typedef struct bool active; bool paused; uint framecount; - int num_channels; + int max_channels; // max channels that can be allocated by openAL + int total_channels; // total playing channels at current time int clientnum; } alstate_t; -extern alconfig_t al_config; -extern alstate_t al_state; +extern alconfig_t al_config; +extern alstate_t al_state; -#define Host_Error com.error +#define Host_Error com.error #define Z_Malloc( size ) Mem_Alloc( sndpool, size ) // cvars @@ -180,6 +151,12 @@ extern cvar_t *s_allowEAX; extern cvar_t *s_musicvolume; extern cvar_t *s_check_errors; +// +// s_load.c +// +bool S_TestSoundChar( const char *pch, char c ); +char *S_SkipSoundChar( const char *pch ); + bool S_Init( void *hInst ); void S_Shutdown( void ); void S_Activate( bool active ); @@ -187,13 +164,15 @@ void S_SoundList_f( void ); bool S_CheckForErrors( void ); void S_Update( ref_params_t *fd ); void S_StartSound( const vec3_t pos, int ent, int chan, sound_t sfx, float vol, float attn, int pitch, int flags ); +void S_StaticSound( const vec3_t pos, int ent, int chan, sound_t handle, float fvol, float attn, int pitch, int flags ); void S_StreamRawSamples( int samples, int rate, int width, int channels, const byte *data ); void S_StartBackgroundTrack( const char *intro, const char *loop ); -channel_t *S_PickChannel( int entNum, int entChannel ); +channel_t *SND_PickStaticChannel( int entnum, sfx_t *sfx ); +channel_t *SND_PickDynamicChannel( int entnum, int channel, sfx_t *sfx ); void S_FadeClientVolume( float fadePercent, float fadeOutSeconds, float holdTime, float fadeInSeconds ); int S_StartLocalSound( const char *name, float volume, int pitch, const float *org ); sfx_t *S_GetSfxByHandle( sound_t handle ); -void S_StopSound( int entnum, int channel ); +void S_StopSound( int entnum, int channel, const char *soundname ); void S_StreamBackgroundTrack( void ); void S_StopBackgroundTrack( void ); void S_ClearSoundBuffer( void ); diff --git a/snd_dx/s_export.c b/snd_dx/s_export.c index 44903e3b..befbbb54 100644 --- a/snd_dx/s_export.c +++ b/snd_dx/s_export.c @@ -33,6 +33,7 @@ vsound_exp_t DLLEXPORT *CreateAPI( stdlib_api_t *input, vsound_imp_t *engfuncs ) snd.FadeClientVolume = S_FadeClientVolume; snd.StartSound = S_StartSound; + snd.StaticSound = S_StartStaticSound; snd.StreamRawSamples = S_StreamRawSamples; snd.StartLocalSound = S_StartLocalSound; snd.StartBackgroundTrack = S_StartBackgroundTrack; diff --git a/snd_dx/s_main.c b/snd_dx/s_main.c index 917544c4..85f1604a 100644 --- a/snd_dx/s_main.c +++ b/snd_dx/s_main.c @@ -374,8 +374,10 @@ channel_t *SND_PickStaticChannel( int entnum, sfx_t *sfx ) { // no empty slots, alloc a new static sound channel if( total_channels == MAX_CHANNELS ) + { + MsgDev( D_ERROR, "S_PickChannel: no free channels\n" ); return NULL; - + } // get a channel for the static sound ch = &channels[total_channels]; total_channels++; @@ -407,7 +409,7 @@ int S_AlterChannel( int entnum, int channel, sfx_t *sfx, int vol, int pitch, int // at a time, so we can just shut off // any channel that has ch->isSentence >= 0 and matches the entnum. - for( i = 0, ch = channels; i < total_channels; i++ ) + for( i = 0, ch = channels; i < total_channels; i++, ch++ ) { if( ch->entnum == entnum && ch->entchannel == channel && ch->sfx && ch->isSentence ) { @@ -429,7 +431,7 @@ int S_AlterChannel( int entnum, int channel, sfx_t *sfx, int vol, int pitch, int } // regular sound or streaming sound - for( i = 0, ch = channels; i < total_channels; i++ ) + for( i = 0, ch = channels; i < total_channels; i++, ch++ ) { if( ch->entnum == entnum && ch->entchannel == channel && ch->sfx ) { @@ -438,7 +440,7 @@ int S_AlterChannel( int entnum, int channel, sfx_t *sfx, int vol, int pitch, int if( flags & SND_CHANGE_VOL ) ch->master_vol = vol; - + if( flags & SND_STOP ) S_FreeChannel( ch ); @@ -986,13 +988,7 @@ void S_StartSound( const vec3_t pos, int ent, int chan, sound_t handle, float fv sfx_t *sfx = NULL; channel_t *target_chan, *check; int vol, fsentence = 0; - int soundlevel, ch_idx; - - if( pos ) - { - S_StartStaticSound( pos, ent, chan, handle, fvol, attn, pitch, flags ); - return; - } + int ch_idx; sfx = S_GetSfxByHandle( handle ); if( !sfx ) return; @@ -1027,7 +1023,6 @@ void S_StartSound( const vec3_t pos, int ent, int chan, sound_t handle, float fv if( S_TestSoundChar( sfx->name, '!' )) fsentence = true; - soundlevel = ATTN_TO_SNDLVL( attn ); // spatialize Mem_Set( target_chan, 0, sizeof( *target_chan )); @@ -1036,7 +1031,7 @@ void S_StartSound( const vec3_t pos, int ent, int chan, sound_t handle, float fv VectorCopy( vec3_origin, target_chan->direction ); // initially unused target_chan->staticsound = ( ent == 0 ) ? true : false; // world static sound target_chan->use_loop = (flags & SND_STOP_LOOPING) ? false : true; - target_chan->dist_mult = SNDLVL_TO_DIST_MULT( soundlevel ); + target_chan->dist_mult = (attn / 1000.0f); target_chan->master_vol = vol; target_chan->entnum = ent; target_chan->entchannel = chan; @@ -1141,7 +1136,6 @@ void S_StartStaticSound( const vec3_t pos, int ent, int chan, sound_t handle, fl int vol, fvox = 0; float flSoundRadius = 0.0f; bool looping = false; - int soundlevel; sfx = S_GetSfxByHandle( handle ); if( !sfx ) return; @@ -1161,6 +1155,8 @@ void S_StartStaticSound( const vec3_t pos, int ent, int chan, sound_t handle, fl return; } + if( !pos ) pos = vec3_origin; + // First, make sure the sound source entity is even in the PVS. SndInfo.pOrigin = NULL; SndInfo.pAngles = NULL; @@ -1172,8 +1168,6 @@ void S_StartStaticSound( const vec3_t pos, int ent, int chan, sound_t handle, fl ch = SND_PickStaticChannel( ent, sfx ); // autolooping sounds are always fixed origin(?) if( !ch ) return; - soundlevel = ATTN_TO_SNDLVL( attn ); - if( S_TestSoundChar( sfx->name, '!' )) { // this is a sentence. link words to play in sequence. @@ -1198,8 +1192,9 @@ void S_StartStaticSound( const vec3_t pos, int ent, int chan, sound_t handle, fl // never update positions if source entity is 0 ch->staticsound = ( ent == 0 ) ? true : false; + ch->use_loop = (flags & SND_STOP_LOOPING) ? false : true; ch->master_vol = vol; - ch->dist_mult = SNDLVL_TO_DIST_MULT( soundlevel ); + ch->dist_mult = (attn / 1000.0f); ch->basePitch = pitch; ch->entnum = ent; ch->entchannel = chan; @@ -1213,6 +1208,8 @@ void S_StartStaticSound( const vec3_t pos, int ent, int chan, sound_t handle, fl ch->ob_gain_inc = 0.0; ch->ob_gain_target = 0.0; ch->bTraced = false; + ch->pos = 0; + ch->end = paintedtime + sfx->cache->samples; SND_Spatialize( ch ); } @@ -1254,19 +1251,26 @@ void S_ClearBuffer( void ) /* ================== -S_StopAllSounds +S_StopSound stop all sounds for entity on a channel. ================== */ -void S_StopSound( int entnum, int channel ) +void S_StopSound( int entnum, int channel, const char *soundname ) { int i; for( i = 0; i < total_channels; i++ ) { - if( channels[i].entnum == entnum && channels[i].entchannel == channel ) - S_FreeChannel( &channels[i] ); + channel_t *ch = &channels[i]; + + if( !ch->sfx ) continue; // already freed + if( ch->entnum == entnum && ch->entchannel == channel ) + { + if( soundname && com.strcmp( ch->sfx->name, soundname )) + continue; + S_FreeChannel( ch ); + } } } @@ -1346,10 +1350,9 @@ void S_RenderFrame( ref_params_t *fd ) // if the loading plaque is up, clear everything // out to make sure we aren't looping a dirty // dma buffer while loading - if( fd->paused ) + if( fd->paused && !s_listener.paused ) { S_ClearBuffer(); - return; } // update any client side sound fade @@ -1365,6 +1368,9 @@ void S_RenderFrame( ref_params_t *fd ) s_listener.frametime = fd->frametime; s_listener.waterlevel = fd->waterlevel; s_listener.ingame = si.IsInGame(); + s_listener.paused = fd->paused; + + if( s_listener.paused ) return; VectorCopy( fd->simorg, s_listener.origin ); VectorCopy( fd->vieworg, s_listener.vieworg ); @@ -1508,10 +1514,9 @@ void S_Shutdown( void ) Cmd_RemoveCommand( "s_info" ); S_StopAllSounds (); - SNDDMA_Shutdown (); - - S_FreeSounds(); + S_FreeSounds (); SX_Free (); + SNDDMA_Shutdown (); Mem_FreePool( &sndpool ); } \ No newline at end of file diff --git a/snd_dx/s_mix.c b/snd_dx/s_mix.c index 2cd51b8c..8f52da14 100644 --- a/snd_dx/s_mix.c +++ b/snd_dx/s_mix.c @@ -128,45 +128,54 @@ CHANNEL MIXING =============================================================================== */ -void S_PaintChannelFrom8( channel_t *ch, wavdata_t *sc, int count ) +void S_PaintChannelFrom8( channel_t *ch, wavdata_t *sc, int count, int offset ) { - int i, data; - int *lscale, *rscale; - byte *sfx; + int data; + int *lscale, *rscale; + byte *sfx; + portable_samplepair_t *samp; + int i; - ch->leftvol = bound( 0, ch->leftvol, 255 ); - ch->rightvol = bound( 0, ch->rightvol, 255 ); + if( ch->leftvol > 255 ) ch->leftvol = 255; + if( ch->rightvol > 255 ) ch->rightvol = 255; lscale = snd_scaletable[ch->leftvol>>3]; rscale = snd_scaletable[ch->rightvol>>3]; sfx = (signed char *)sc->buffer + ch->pos; - for( i = 0; i < count; i++ ) + samp = &paintbuffer[offset]; + + for( i = 0; i < count; i++, samp++ ) { data = sfx[i]; - paintbuffer[i].left += lscale[data]; - paintbuffer[i].right += rscale[data]; + samp->left += lscale[data]; + samp->right += rscale[data]; } ch->pos += count; } -void S_PaintChannelFrom16( channel_t *ch, wavdata_t *sc, int count ) +void S_PaintChannelFrom16( channel_t *ch, wavdata_t *sc, int count, int offset ) { - int i, data; - int left, right; - signed short *sfx; + int data; + int left, right; + int leftvol, rightvol; + signed short *sfx; + portable_samplepair_t *samp; + int i; - ch->leftvol = bound( 0, ch->leftvol, 255 ); - ch->rightvol = bound( 0, ch->rightvol, 255 ); + leftvol = ch->leftvol * snd_vol; + rightvol = ch->rightvol * snd_vol; sfx = (signed short *)sc->buffer + ch->pos; - for( i = 0; i < count; i++ ) + samp = &paintbuffer[offset]; + + for( i = 0; i < count; i++, samp++ ) { data = sfx[i]; - left = ( data * ch->leftvol ) >> 8; - right = (data * ch->rightvol) >> 8; - paintbuffer[i].left += left; - paintbuffer[i].right += right; + left = ( data * leftvol ) >> 8; + right = (data * rightvol) >> 8; + samp->left += left; + samp->right += right; } ch->pos += count; } @@ -192,16 +201,17 @@ void S_MixAllChannels( int endtime, int end ) while( ltime < end ) { - // paint up to end - if( ch->end < end ) - count = ch->end - ltime; - else count = end - ltime; + // max painting is to the end of the buffer + count = end - ltime; + + // might be stopped by running out of data + if( ch->end - ltime < count ) count = ch->end - ltime; if( count > 0 ) { if( sc->width == 1 ) - S_PaintChannelFrom8( ch, sc, count ); - else S_PaintChannelFrom16( ch, sc, count ); + S_PaintChannelFrom8( ch, sc, count, ltime - paintedtime ); + else S_PaintChannelFrom16( ch, sc, count, ltime - paintedtime ); ltime += count; } @@ -209,13 +219,7 @@ void S_MixAllChannels( int endtime, int end ) // if at end of loop, restart if( ltime >= ch->end ) { - if( ch->autosound && ch->use_loop ) - { - // autolooped sounds always go back to start - ch->pos = 0; - ch->end = ltime + sc->samples; - } - else if( sc->loopStart >= 0 && ch->use_loop ) + if( sc->loopStart >= 0 && ch->use_loop ) { ch->pos = sc->loopStart; ch->end = ltime + sc->samples - ch->pos; diff --git a/snd_dx/sound.h b/snd_dx/sound.h index 571d8492..5fd3ebb4 100644 --- a/snd_dx/sound.h +++ b/snd_dx/sound.h @@ -86,14 +86,6 @@ typedef struct bool bTraced; // true if channel was already checked this frame for obscuring float radius; // radius of this sound effect bool doppler_effect; // this chanel has doppler effect - - // obsolete. remove ? - int looping; // where to loop, -1 = no looping OBSOLETE? - - int loopnum; // entity num that playing autosound - int loopframe; // for stopping looping sounds - - bool autosound; // from an entity->sound, cleared each frame bool use_loop; // don't loop default and local sounds } channel_t; @@ -110,6 +102,7 @@ typedef struct int waterlevel; float frametime; // used for sound fade bool ingame; // listener in-game ? + bool paused; } listener_t; typedef struct @@ -206,7 +199,7 @@ channel_t *SND_PickStaticChannel( int entnum, sfx_t *sfx ); void S_FadeClientVolume( float fadePercent, float fadeOutSeconds, float holdTime, float fadeInSeconds ); int S_StartLocalSound( const char *name, float volume, int pitch, const float *org ); sfx_t *S_GetSfxByHandle( sound_t handle ); -void S_StopSound( int entnum, int channel ); +void S_StopSound( int entnum, int channel, const char *soundname ); void S_StopBackgroundTrack( void ); void S_RenderFrame( ref_params_t *fd ); void S_StartStreaming( void ); diff --git a/spirit/cbase.cpp b/spirit/cbase.cpp index 7c9e4f26..07d80ae3 100644 --- a/spirit/cbase.cpp +++ b/spirit/cbase.cpp @@ -1039,13 +1039,6 @@ int CBaseEntity::Restore( CRestore &restore ) SET_MODEL(ENT(pev), STRING(pev->model)); UTIL_SetSize(pev, mins, maxs); // Reset them } - - if( pev->soundindex != 0 && !FStringNull( pev->noise )) - { - PRECACHE_SOUND( (char *)STRING( pev->noise )); - LINK_ENTITY( ENT( pev ), false ); - } - return status; } diff --git a/spirit/client.cpp b/spirit/client.cpp index bee8adc3..bbeb2d0d 100644 --- a/spirit/client.cpp +++ b/spirit/client.cpp @@ -1100,11 +1100,11 @@ void UpdateEntityState( entity_state_t *to, edict_t *from, int baseline ) to->skin = pNet->pev->skin; // studio model skin to->body = pNet->pev->body; // studio model submodel to->effects = pNet->pev->effects; // shared client and render flags - to->soundindex = pNet->pev->soundindex; // soundindex to->renderfx = pNet->pev->renderfx; // renderer flags to->rendermode = pNet->pev->rendermode; // rendering mode to->renderamt = pNet->pev->renderamt; // alpha value to->animtime = (int)(1000.0 * pNet->pev->animtime) * 0.001; // sequence time + to->localtime = (int)(1000.0 * pNet->pev->ltime) * 0.001; // movement time to->scale = pNet->pev->scale; // shared client and render flags to->movetype = (movetype_t)pNet->pev->movetype; to->frame = pNet->pev->frame; // any model current frame @@ -1177,16 +1177,6 @@ void UpdateEntityState( entity_state_t *to, edict_t *from, int baseline ) } else if( to->ed_type == ED_AMBIENT ) { - to->soundindex = pNet->pev->soundindex; - - if( pNet->pev->solid == SOLID_TRIGGER ) - { - Vector midPoint; - - // NOTE: no reason to compute this shit on the client - save bandwidth - midPoint = pNet->pev->mins + pNet->pev->maxs * 0.5f; - to->origin += midPoint; - } } else if( to->ed_type == ED_MOVER || to->ed_type == ED_BSPBRUSH || to->ed_type == ED_PORTAL ) { diff --git a/spirit/util.cpp b/spirit/util.cpp index eaebdcc7..fb592a32 100644 --- a/spirit/util.cpp +++ b/spirit/util.cpp @@ -471,8 +471,6 @@ TYPEDESCRIPTION gEntvarsDescription[] = DEFINE_ENTITY_FIELD( modelindex, FIELD_INTEGER ), DEFINE_ENTITY_GLOBAL_FIELD( model, FIELD_MODELNAME ), - DEFINE_ENTITY_FIELD( soundindex, FIELD_INTEGER ), - DEFINE_ENTITY_FIELD( viewmodel, FIELD_MODELNAME ), DEFINE_ENTITY_FIELD( weaponmodel, FIELD_MODELNAME ), diff --git a/todo.log b/todo.log index 7178bf73..5d74ddc8 100644 --- a/todo.log +++ b/todo.log @@ -35,5 +35,6 @@ Xash 0.71 Beta 05.05.10 11.rewrite EntitiesInPVS check OK 12.revision MOVETYPE_BOUNCE physic OK 13.revision MOVETYPE_COMPOUND physic OK -14.re-design sound library -15. move loding sounds into launch.dll OK \ No newline at end of file +14.re-design sound library OK +15. move loding sounds into launch.dll OK +16.implement generic streaming background track \ No newline at end of file diff --git a/vid_gl/r_opengl.c b/vid_gl/r_opengl.c index 4e4f9113..9e93568d 100644 --- a/vid_gl/r_opengl.c +++ b/vid_gl/r_opengl.c @@ -242,7 +242,7 @@ bool R_SetPixelformat( void ) Sys_LoadLibrary( NULL, &opengl_dll ); // load opengl32.dll if( !opengl_dll.link ) return false; - glw_state.minidriver = false; // FIXME + glw_state.minidriver = false; // FIXME: allow 3dfx drivers too if( glw_state.minidriver ) { @@ -417,6 +417,7 @@ void R_Free_OpenGL( void ) DestroyWindow ( glw_state.hWnd ); glw_state.hWnd = NULL; } + UnregisterClass( "Xash Window", glw_state.hInst ); if( glState.fullScreen ) @@ -433,16 +434,17 @@ void R_Free_OpenGL( void ) void R_SaveVideoMode( int vid_mode ) { - int i = bound( 0, vid_mode, num_vidmodes ); // check range + int mode = bound( 0, vid_mode, num_vidmodes ); // check range - glState.width = vidmode[i].width; - glState.height = vidmode[i].height; - glState.wideScreen = vidmode[i].wideScreen; + glState.width = vidmode[mode].width; + glState.height = vidmode[mode].height; + glState.wideScreen = vidmode[mode].wideScreen; - Cvar_FullSet( "width", va( "%i", vidmode[i].width ), CVAR_READ_ONLY ); - Cvar_FullSet( "height", va( "%i", vidmode[i].height ), CVAR_READ_ONLY ); - Cvar_SetValue( "r_mode", i ); // merge if out of bounds - MsgDev( D_NOTE, "Set: %s [%dx%d]\n", vidmode[i].desc, vidmode[i].width, vidmode[i].height ); + Cvar_FullSet( "width", va( "%i", vidmode[mode].width ), CVAR_READ_ONLY ); + Cvar_FullSet( "height", va( "%i", vidmode[mode].height ), CVAR_READ_ONLY ); + Cvar_SetValue( "r_mode", mode ); // merge if it out of bounds + + MsgDev( D_NOTE, "Set: %s [%dx%d]\n", vidmode[mode].desc, vidmode[mode].width, vidmode[mode].height ); } bool R_CreateWindow( int width, int height, bool fullscreen ) @@ -504,7 +506,7 @@ bool R_CreateWindow( int width, int height, bool fullscreen ) if( Cvar_VariableInteger( "r_mode" ) != glConfig.prev_mode ) { - if((x + w > glw_state.desktopWidth) || (y + h > glw_state.desktopHeight)) + if(( x + w > glw_state.desktopWidth ) || ( y + h > glw_state.desktopHeight )) { x = ( glw_state.desktopWidth - w ) / 2; y = ( glw_state.desktopHeight - h ) / 2; @@ -516,7 +518,7 @@ bool R_CreateWindow( int width, int height, bool fullscreen ) if( !glw_state.hWnd ) { - MsgDev( D_ERROR, "R_CreateWindow: couldn't create window %s\n", wndname ); + MsgDev( D_ERROR, "R_CreateWindow: couldn't create '%s'\n", wndname ); return false; }