From 309ece3425957096f18a5521316e1983a37ea904 Mon Sep 17 00:00:00 2001 From: divverent Date: Tue, 5 Jul 2011 19:48:04 +0000 Subject: [PATCH 1/1] DP_SND_SOUND7_WIP1 sound7() function, supporting more sound channels (-128 to 127, negative ones being additional auto-channels, positive ones being additional single-channels) git-svn-id: svn://svn.icculus.org/twilight/trunk/darkplaces@11232 d7cf8633-e32d-0410-b094-e92efae38249 --- cl_parse.c | 4 +- clvm_cmds.c | 21 ++++++-- csprogs.c | 4 +- cvar.c | 17 +++++-- cvar.h | 6 +++ dpdefs/dpextensions.qc | 27 +++++++++++ prvm_cmds.c | 3 +- server.h | 2 +- snd_main.c | 106 +++++++++++++++++++++++++++-------------- sound.h | 22 +++++++++ sv_main.c | 38 +++++++++------ sv_phys.c | 4 +- svvm_cmds.c | 32 +++++++++++-- 13 files changed, 217 insertions(+), 69 deletions(-) diff --git a/cl_parse.c b/cl_parse.c index ca4bec30..3d56d111 100644 --- a/cl_parse.c +++ b/cl_parse.c @@ -247,7 +247,7 @@ void CL_ParseStartSoundPacket(int largesoundindex) if (field_mask & SND_LARGEENTITY) { ent = (unsigned short) MSG_ReadShort (); - channel = MSG_ReadByte (); + channel = MSG_ReadChar (); } else { @@ -262,6 +262,8 @@ void CL_ParseStartSoundPacket(int largesoundindex) sound_num = MSG_ReadByte (); } + channel = CHAN_NET2ENGINE(channel); + MSG_ReadVector(pos, cls.protocol); if (sound_num >= MAX_SOUNDS) diff --git a/clvm_cmds.c b/clvm_cmds.c index cedd2081..5b0b8043 100644 --- a/clvm_cmds.c +++ b/clvm_cmds.c @@ -161,9 +161,11 @@ static void VM_CL_sound (void) prvm_edict_t *entity; float volume; float attenuation; + float pitchchange; + int flags; vec3_t org; - VM_SAFEPARMCOUNT(5, VM_CL_sound); + VM_SAFEPARMCOUNTRANGE(5, 7, VM_CL_sound); entity = PRVM_G_EDICT(OFS_PARM0); channel = (int)PRVM_G_FLOAT(OFS_PARM1); @@ -183,9 +185,22 @@ static void VM_CL_sound (void) return; } - if (channel < 0 || channel > 7) + if (prog->argc < 6) + pitchchange = 0; + else + pitchchange = PRVM_G_FLOAT(OFS_PARM5); + // ignoring prog->argc < 7 for now (no flags supported yet) + + if (prog->argc < 7) + flags = 0; + else + flags = PRVM_G_FLOAT(OFS_PARM6); + + channel = CHAN_USER2ENGINE(channel); + + if (!IS_CHAN(channel)) { - VM_Warning("VM_CL_sound: channel must be in range 0-7\n"); + VM_Warning("VM_CL_sound: channel must be in range 0-127\n"); return; } diff --git a/csprogs.c b/csprogs.c index 6a6ca993..55bf6bf1 100644 --- a/csprogs.c +++ b/csprogs.c @@ -704,11 +704,13 @@ qboolean CL_VM_Event_Sound(int sound_num, float volume, int channel, float atten PRVM_clientglobalfloat(time) = cl.time; PRVM_clientglobaledict(self) = cl.csqc_server2csqcentitynumber[cl.playerentity]; PRVM_G_FLOAT(OFS_PARM0) = ent; - PRVM_G_FLOAT(OFS_PARM1) = channel; + PRVM_G_FLOAT(OFS_PARM1) = CHAN_ENGINE2USER(channel); PRVM_G_INT(OFS_PARM2) = PRVM_SetTempString(cl.sound_name[sound_num] ); PRVM_G_FLOAT(OFS_PARM3) = volume; PRVM_G_FLOAT(OFS_PARM4) = attenuation; VectorCopy(pos, PRVM_G_VECTOR(OFS_PARM5) ); + PRVM_G_FLOAT(OFS_PARM6) = 0; // pitch shift not supported yet + PRVM_G_FLOAT(OFS_PARM7) = 0; // flags - none can come in at this point yet PRVM_ExecuteProgram(PRVM_clientfunction(CSQC_Event_Sound), "QC function CSQC_Event_Sound is missing"); r = CSQC_RETURNVAL != 0; } diff --git a/cvar.c b/cvar.c index bb5c3ce7..3dee0406 100644 --- a/cvar.c +++ b/cvar.c @@ -105,32 +105,41 @@ cvar_t *Cvar_FindVarLink (const char *var_name, cvar_t **parent, cvar_t ***link, Cvar_VariableValue ============ */ -float Cvar_VariableValue (const char *var_name) +float Cvar_VariableValueOr (const char *var_name, float def) { cvar_t *var; var = Cvar_FindVar (var_name); if (!var) - return 0; + return def; return atof (var->string); } +float Cvar_VariableValue (const char *var_name) +{ + return Cvar_VariableValueOr(var_name, 0); +} /* ============ Cvar_VariableString ============ */ -const char *Cvar_VariableString (const char *var_name) +const char *Cvar_VariableStringOr (const char *var_name, const char *def) { cvar_t *var; var = Cvar_FindVar (var_name); if (!var) - return cvar_null_string; + return def; return var->string; } +const char *Cvar_VariableString (const char *var_name) +{ + return Cvar_VariableStringOr(var_name, cvar_null_string); +} + /* ============ Cvar_VariableDefString diff --git a/cvar.h b/cvar.h index e80edc07..4fd177d6 100644 --- a/cvar.h +++ b/cvar.h @@ -165,9 +165,15 @@ void Cvar_SetValue (const char *var_name, float value); void Cvar_SetQuick (cvar_t *var, const char *value); void Cvar_SetValueQuick (cvar_t *var, float value); +float Cvar_VariableValueOr (const char *var_name, float def); +// returns def if not defined + float Cvar_VariableValue (const char *var_name); // returns 0 if not defined or non numeric +const char *Cvar_VariableStringOr (const char *var_name, const char *def); +// returns def if not defined + const char *Cvar_VariableString (const char *var_name); // returns an empty string if not defined diff --git a/dpdefs/dpextensions.qc b/dpdefs/dpextensions.qc index a5f30877..1aba127a 100644 --- a/dpdefs/dpextensions.qc +++ b/dpdefs/dpextensions.qc @@ -1206,6 +1206,33 @@ float(string name, string value) registercvar = #93; //the engine plays sound/cdtracks/track001.wav instead of cd track 1 and so on if found, this allows games and mods to have music tracks without using ambientsound. //Note: also plays .ogg with DP_SND_OGGVORBIS extension. +//DP_SND_SOUND7_WIP1 +//idea: divVerent +//darkplaces implementation: divVerent +//builtin definitions: +void(entity e, float chan, string samp, float vol, float atten, float speed, float flags) sound7 = #8; +float SOUNDFLAG_RELIABLE = 1; +//description: +//plays a sound, with some more flags +//extensions to sound(): +//- channel may be in the range from -128 to 127; channels -128 to 0 are "auto", +// i.e. support multiple sounds at once, but cannot be stopped/restarted +//- a speed parameter has been reserved for later addition of pitch shifting. +// it MUST be set to 0 for now, meaning "no pitch change" +//- the flag SOUNDFLAG_RELIABLE can be specified, which makes the sound send +// to MSG_ALL (reliable) instead of MSG_BROADCAST (unreliable, default); +// similarily, SOUNDFLAG_RELIABLE_TO_ONE sends to MSG_ONE +//- channel 0 is controlled by snd_channel0volume; channel 1 and -1 by +// snd_channel1volume, etc. (so, a channel shares the cvar with its respective +// auto-channel); however, the mod MUST define snd_channel8volume and upwards +// in default.cfg if they are to be used, as the engine does not create them +// to not litter the cvar list +//- this extension applies to CSQC as well; CSQC_Event_Sound will get speed and +// flags as extra 7th and 8th argument +//- WIP2 ideas: SOUNDFLAG_RELIABLE_TO_ONE, SOUNDFLAG_NOPHS, SOUNDFLAG_FORCELOOP +//- NOTE: to check for this, ALSO OR a check with DP_SND_SOUND7 to also support +// the finished extension once done + //DP_SND_OGGVORBIS //idea: Transfusion //darkplaces implementation: Elric diff --git a/prvm_cmds.c b/prvm_cmds.c index df5ea5ea..c0b34d4a 100644 --- a/prvm_cmds.c +++ b/prvm_cmds.c @@ -2923,7 +2923,8 @@ void VM_getsoundtime (void) } entnum = ((pnum == PRVM_CLIENTPROG) ? MAX_EDICTS : 0) + PRVM_NUM_FOR_EDICT(PRVM_G_EDICT(OFS_PARM0)); entchannel = (int)PRVM_G_FLOAT(OFS_PARM1); - if (entchannel <= 0 || entchannel > 8) + entchannel = CHAN_USER2ENGINE(entchannel); + if (!IS_CHAN(entchannel)) VM_Warning("VM_getsoundtime: %s: bad channel %i\n", PRVM_NAME, entchannel); PRVM_G_FLOAT(OFS_RETURN) = (float)S_GetEntChannelPosition(entnum, entchannel); } diff --git a/server.h b/server.h index d64db17b..cb32fe42 100644 --- a/server.h +++ b/server.h @@ -490,7 +490,7 @@ void SV_Init (void); void SV_StartParticle (vec3_t org, vec3_t dir, int color, int count); void SV_StartEffect (vec3_t org, int modelindex, int startframe, int framecount, int framerate); -void SV_StartSound (prvm_edict_t *entity, int channel, const char *sample, int volume, float attenuation); +void SV_StartSound (prvm_edict_t *entity, int channel, const char *sample, int volume, float attenuation, qboolean reliable); void SV_StartPointSound (vec3_t origin, const char *sample, int volume, float attenuation); void SV_ConnectClient (int clientnum, netconn_t *netconnection); diff --git a/snd_main.c b/snd_main.c index 71669fe9..e537d838 100644 --- a/snd_main.c +++ b/snd_main.c @@ -182,38 +182,46 @@ cvar_t snd_swapstereo = {CVAR_SAVE, "snd_swapstereo", "0", "swaps left/right spe extern cvar_t v_flipped; cvar_t snd_channellayout = {0, "snd_channellayout", "0", "channel layout. Can be 0 (auto - snd_restart needed), 1 (standard layout), or 2 (ALSA layout)"}; cvar_t snd_mutewhenidle = {CVAR_SAVE, "snd_mutewhenidle", "1", "whether to disable sound output when game window is inactive"}; -cvar_t snd_entchannel0volume = {CVAR_SAVE, "snd_entchannel0volume", "1", "volume multiplier of the auto-allocate entity channel of regular entities"}; -cvar_t snd_entchannel1volume = {CVAR_SAVE, "snd_entchannel1volume", "1", "volume multiplier of the 1st entity channel of regular entities"}; -cvar_t snd_entchannel2volume = {CVAR_SAVE, "snd_entchannel2volume", "1", "volume multiplier of the 2nd entity channel of regular entities"}; -cvar_t snd_entchannel3volume = {CVAR_SAVE, "snd_entchannel3volume", "1", "volume multiplier of the 3rd entity channel of regular entities"}; -cvar_t snd_entchannel4volume = {CVAR_SAVE, "snd_entchannel4volume", "1", "volume multiplier of the 4th entity channel of regular entities"}; -cvar_t snd_entchannel5volume = {CVAR_SAVE, "snd_entchannel5volume", "1", "volume multiplier of the 5th entity channel of regular entities"}; -cvar_t snd_entchannel6volume = {CVAR_SAVE, "snd_entchannel6volume", "1", "volume multiplier of the 6th entity channel of regular entities"}; -cvar_t snd_entchannel7volume = {CVAR_SAVE, "snd_entchannel7volume", "1", "volume multiplier of the 7th entity channel of regular entities"}; -cvar_t snd_playerchannel0volume = {CVAR_SAVE, "snd_playerchannel0volume", "1", "volume multiplier of the auto-allocate entity channel of player entities"}; -cvar_t snd_playerchannel1volume = {CVAR_SAVE, "snd_playerchannel1volume", "1", "volume multiplier of the 1st entity channel of player entities"}; -cvar_t snd_playerchannel2volume = {CVAR_SAVE, "snd_playerchannel2volume", "1", "volume multiplier of the 2nd entity channel of player entities"}; -cvar_t snd_playerchannel3volume = {CVAR_SAVE, "snd_playerchannel3volume", "1", "volume multiplier of the 3rd entity channel of player entities"}; -cvar_t snd_playerchannel4volume = {CVAR_SAVE, "snd_playerchannel4volume", "1", "volume multiplier of the 4th entity channel of player entities"}; -cvar_t snd_playerchannel5volume = {CVAR_SAVE, "snd_playerchannel5volume", "1", "volume multiplier of the 5th entity channel of player entities"}; -cvar_t snd_playerchannel6volume = {CVAR_SAVE, "snd_playerchannel6volume", "1", "volume multiplier of the 6th entity channel of player entities"}; -cvar_t snd_playerchannel7volume = {CVAR_SAVE, "snd_playerchannel7volume", "1", "volume multiplier of the 7th entity channel of player entities"}; -cvar_t snd_worldchannel0volume = {CVAR_SAVE, "snd_worldchannel0volume", "1", "volume multiplier of the auto-allocate entity channel of the world entity"}; -cvar_t snd_worldchannel1volume = {CVAR_SAVE, "snd_worldchannel1volume", "1", "volume multiplier of the 1st entity channel of the world entity"}; -cvar_t snd_worldchannel2volume = {CVAR_SAVE, "snd_worldchannel2volume", "1", "volume multiplier of the 2nd entity channel of the world entity"}; -cvar_t snd_worldchannel3volume = {CVAR_SAVE, "snd_worldchannel3volume", "1", "volume multiplier of the 3rd entity channel of the world entity"}; -cvar_t snd_worldchannel4volume = {CVAR_SAVE, "snd_worldchannel4volume", "1", "volume multiplier of the 4th entity channel of the world entity"}; -cvar_t snd_worldchannel5volume = {CVAR_SAVE, "snd_worldchannel5volume", "1", "volume multiplier of the 5th entity channel of the world entity"}; -cvar_t snd_worldchannel6volume = {CVAR_SAVE, "snd_worldchannel6volume", "1", "volume multiplier of the 6th entity channel of the world entity"}; -cvar_t snd_worldchannel7volume = {CVAR_SAVE, "snd_worldchannel7volume", "1", "volume multiplier of the 7th entity channel of the world entity"}; -cvar_t snd_csqcchannel0volume = {CVAR_SAVE, "snd_csqcchannel0volume", "1", "volume multiplier of the auto-allocate entity channel of the world entity"}; -cvar_t snd_csqcchannel1volume = {CVAR_SAVE, "snd_csqcchannel1volume", "1", "volume multiplier of the 1st entity channel of the world entity"}; -cvar_t snd_csqcchannel2volume = {CVAR_SAVE, "snd_csqcchannel2volume", "1", "volume multiplier of the 2nd entity channel of the world entity"}; -cvar_t snd_csqcchannel3volume = {CVAR_SAVE, "snd_csqcchannel3volume", "1", "volume multiplier of the 3rd entity channel of the world entity"}; -cvar_t snd_csqcchannel4volume = {CVAR_SAVE, "snd_csqcchannel4volume", "1", "volume multiplier of the 4th entity channel of the world entity"}; -cvar_t snd_csqcchannel5volume = {CVAR_SAVE, "snd_csqcchannel5volume", "1", "volume multiplier of the 5th entity channel of the world entity"}; -cvar_t snd_csqcchannel6volume = {CVAR_SAVE, "snd_csqcchannel6volume", "1", "volume multiplier of the 6th entity channel of the world entity"}; -cvar_t snd_csqcchannel7volume = {CVAR_SAVE, "snd_csqcchannel7volume", "1", "volume multiplier of the 7th entity channel of the world entity"}; +cvar_t snd_entchannel0volume = {CVAR_SAVE, "snd_entchannel0volume", "1", "volume multiplier of the auto-allocate entity channel of regular entities (DEPRECATED)"}; +cvar_t snd_entchannel1volume = {CVAR_SAVE, "snd_entchannel1volume", "1", "volume multiplier of the 1st entity channel of regular entities (DEPRECATED)"}; +cvar_t snd_entchannel2volume = {CVAR_SAVE, "snd_entchannel2volume", "1", "volume multiplier of the 2nd entity channel of regular entities (DEPRECATED)"}; +cvar_t snd_entchannel3volume = {CVAR_SAVE, "snd_entchannel3volume", "1", "volume multiplier of the 3rd entity channel of regular entities (DEPRECATED)"}; +cvar_t snd_entchannel4volume = {CVAR_SAVE, "snd_entchannel4volume", "1", "volume multiplier of the 4th entity channel of regular entities (DEPRECATED)"}; +cvar_t snd_entchannel5volume = {CVAR_SAVE, "snd_entchannel5volume", "1", "volume multiplier of the 5th entity channel of regular entities (DEPRECATED)"}; +cvar_t snd_entchannel6volume = {CVAR_SAVE, "snd_entchannel6volume", "1", "volume multiplier of the 6th entity channel of regular entities (DEPRECATED)"}; +cvar_t snd_entchannel7volume = {CVAR_SAVE, "snd_entchannel7volume", "1", "volume multiplier of the 7th entity channel of regular entities (DEPRECATED)"}; +cvar_t snd_playerchannel0volume = {CVAR_SAVE, "snd_playerchannel0volume", "1", "volume multiplier of the auto-allocate entity channel of player entities (DEPRECATED)"}; +cvar_t snd_playerchannel1volume = {CVAR_SAVE, "snd_playerchannel1volume", "1", "volume multiplier of the 1st entity channel of player entities (DEPRECATED)"}; +cvar_t snd_playerchannel2volume = {CVAR_SAVE, "snd_playerchannel2volume", "1", "volume multiplier of the 2nd entity channel of player entities (DEPRECATED)"}; +cvar_t snd_playerchannel3volume = {CVAR_SAVE, "snd_playerchannel3volume", "1", "volume multiplier of the 3rd entity channel of player entities (DEPRECATED)"}; +cvar_t snd_playerchannel4volume = {CVAR_SAVE, "snd_playerchannel4volume", "1", "volume multiplier of the 4th entity channel of player entities (DEPRECATED)"}; +cvar_t snd_playerchannel5volume = {CVAR_SAVE, "snd_playerchannel5volume", "1", "volume multiplier of the 5th entity channel of player entities (DEPRECATED)"}; +cvar_t snd_playerchannel6volume = {CVAR_SAVE, "snd_playerchannel6volume", "1", "volume multiplier of the 6th entity channel of player entities (DEPRECATED)"}; +cvar_t snd_playerchannel7volume = {CVAR_SAVE, "snd_playerchannel7volume", "1", "volume multiplier of the 7th entity channel of player entities (DEPRECATED)"}; +cvar_t snd_worldchannel0volume = {CVAR_SAVE, "snd_worldchannel0volume", "1", "volume multiplier of the auto-allocate entity channel of the world entity (DEPRECATED)"}; +cvar_t snd_worldchannel1volume = {CVAR_SAVE, "snd_worldchannel1volume", "1", "volume multiplier of the 1st entity channel of the world entity (DEPRECATED)"}; +cvar_t snd_worldchannel2volume = {CVAR_SAVE, "snd_worldchannel2volume", "1", "volume multiplier of the 2nd entity channel of the world entity (DEPRECATED)"}; +cvar_t snd_worldchannel3volume = {CVAR_SAVE, "snd_worldchannel3volume", "1", "volume multiplier of the 3rd entity channel of the world entity (DEPRECATED)"}; +cvar_t snd_worldchannel4volume = {CVAR_SAVE, "snd_worldchannel4volume", "1", "volume multiplier of the 4th entity channel of the world entity (DEPRECATED)"}; +cvar_t snd_worldchannel5volume = {CVAR_SAVE, "snd_worldchannel5volume", "1", "volume multiplier of the 5th entity channel of the world entity (DEPRECATED)"}; +cvar_t snd_worldchannel6volume = {CVAR_SAVE, "snd_worldchannel6volume", "1", "volume multiplier of the 6th entity channel of the world entity (DEPRECATED)"}; +cvar_t snd_worldchannel7volume = {CVAR_SAVE, "snd_worldchannel7volume", "1", "volume multiplier of the 7th entity channel of the world entity (DEPRECATED)"}; +cvar_t snd_csqcchannel0volume = {CVAR_SAVE, "snd_csqcchannel0volume", "1", "volume multiplier of the auto-allocate entity channel CSQC entities (DEPRECATED)"}; +cvar_t snd_csqcchannel1volume = {CVAR_SAVE, "snd_csqcchannel1volume", "1", "volume multiplier of the 1st entity channel of CSQC entities (DEPRECATED)"}; +cvar_t snd_csqcchannel2volume = {CVAR_SAVE, "snd_csqcchannel2volume", "1", "volume multiplier of the 2nd entity channel of CSQC entities (DEPRECATED)"}; +cvar_t snd_csqcchannel3volume = {CVAR_SAVE, "snd_csqcchannel3volume", "1", "volume multiplier of the 3rd entity channel of CSQC entities (DEPRECATED)"}; +cvar_t snd_csqcchannel4volume = {CVAR_SAVE, "snd_csqcchannel4volume", "1", "volume multiplier of the 4th entity channel of CSQC entities (DEPRECATED)"}; +cvar_t snd_csqcchannel5volume = {CVAR_SAVE, "snd_csqcchannel5volume", "1", "volume multiplier of the 5th entity channel of CSQC entities (DEPRECATED)"}; +cvar_t snd_csqcchannel6volume = {CVAR_SAVE, "snd_csqcchannel6volume", "1", "volume multiplier of the 6th entity channel of CSQC entities (DEPRECATED)"}; +cvar_t snd_csqcchannel7volume = {CVAR_SAVE, "snd_csqcchannel7volume", "1", "volume multiplier of the 7th entity channel of CSQC entities (DEPRECATED)"}; +cvar_t snd_channel0volume = {CVAR_SAVE, "snd_channel0volume", "1", "volume multiplier of the auto-allocate entity channel"}; +cvar_t snd_channel1volume = {CVAR_SAVE, "snd_channel1volume", "1", "volume multiplier of the 1st entity channel"}; +cvar_t snd_channel2volume = {CVAR_SAVE, "snd_channel2volume", "1", "volume multiplier of the 2nd entity channel"}; +cvar_t snd_channel3volume = {CVAR_SAVE, "snd_channel3volume", "1", "volume multiplier of the 3rd entity channel"}; +cvar_t snd_channel4volume = {CVAR_SAVE, "snd_channel4volume", "1", "volume multiplier of the 4th entity channel"}; +cvar_t snd_channel5volume = {CVAR_SAVE, "snd_channel5volume", "1", "volume multiplier of the 5th entity channel"}; +cvar_t snd_channel6volume = {CVAR_SAVE, "snd_channel6volume", "1", "volume multiplier of the 6th entity channel"}; +cvar_t snd_channel7volume = {CVAR_SAVE, "snd_channel7volume", "1", "volume multiplier of the 7th entity channel"}; // Local cvars static cvar_t nosound = {0, "nosound", "0", "disables sound"}; @@ -813,6 +821,14 @@ void S_Init(void) Cvar_RegisterVariable(&snd_csqcchannel5volume); Cvar_RegisterVariable(&snd_csqcchannel6volume); Cvar_RegisterVariable(&snd_csqcchannel7volume); + Cvar_RegisterVariable(&snd_channel0volume); + Cvar_RegisterVariable(&snd_channel1volume); + Cvar_RegisterVariable(&snd_channel2volume); + Cvar_RegisterVariable(&snd_channel3volume); + Cvar_RegisterVariable(&snd_channel4volume); + Cvar_RegisterVariable(&snd_channel5volume); + Cvar_RegisterVariable(&snd_channel6volume); + Cvar_RegisterVariable(&snd_channel7volume); Cvar_RegisterVariable(&snd_spatialization_min_radius); Cvar_RegisterVariable(&snd_spatialization_max_radius); @@ -1186,12 +1202,13 @@ channel_t *SND_PickChannel(int entnum, int entchannel) first_life_left = 0x7fffffff; // entity channels try to replace the existing sound on the channel - if (entchannel != 0) + // channels <= 0 are autochannels + if (IS_CHAN_SINGLE(entchannel)) { for (ch_idx=NUM_AMBIENTS ; ch_idx < NUM_AMBIENTS + MAX_DYNAMIC_CHANNELS ; ch_idx++) { ch = &channels[ch_idx]; - if (ch->entnum == entnum && (ch->entchannel == entchannel || entchannel == -1) ) + if (ch->entnum == entnum && ch->entchannel == entchannel) { // always override sound from same entity S_StopChannel (ch_idx, true, false); @@ -1283,6 +1300,7 @@ void SND_Spatialize_WithSfx(channel_t *ch, qboolean isstatic, sfx_t *sfx) mastervol *= snd_staticvolume.value; else if(!(ch->flags & CHANNELFLAG_FULLVOLUME)) // same as SND_PaintChannel uses { + // old legacy separated cvars if(ch->entnum >= MAX_EDICTS) { switch(ch->entchannel) @@ -1343,6 +1361,19 @@ void SND_Spatialize_WithSfx(channel_t *ch, qboolean isstatic, sfx_t *sfx) default: break; } } + + switch(ch->entchannel) + { + case 0: mastervol *= snd_channel0volume.value; break; + case 1: mastervol *= snd_channel1volume.value; break; + case 2: mastervol *= snd_channel2volume.value; break; + case 3: mastervol *= snd_channel3volume.value; break; + case 4: mastervol *= snd_channel4volume.value; break; + case 5: mastervol *= snd_channel5volume.value; break; + case 6: mastervol *= snd_channel6volume.value; break; + case 7: mastervol *= snd_channel7volume.value; break; + default: mastervol *= Cvar_VariableValueOr(va("snd_channel%dvolume", CHAN_ENGINE2CVAR(ch->entchannel)), 1.0); break; + } } // If this channel does not manage its own volume (like CD tracks) @@ -1598,12 +1629,12 @@ int S_StartSound_StartPosition_Flags (int entnum, int entchannel, sfx_t *sfx, ve if(sfx == &changevolume_sfx) { - if(entchannel == 0) + if (!IS_CHAN_SINGLE(entchannel)) return -1; for (ch_idx=NUM_AMBIENTS ; ch_idx < NUM_AMBIENTS + MAX_DYNAMIC_CHANNELS ; ch_idx++) { ch = &channels[ch_idx]; - if (ch->entnum == entnum && (ch->entchannel == entchannel || entchannel == -1) ) + if (ch->entnum == entnum && ch->entchannel == entchannel) { S_SetChannelVolume(ch_idx, fvol); ch->dist_mult = attenuation / snd_soundradius.value; @@ -2239,6 +2270,9 @@ qboolean S_LocalSound (const char *sound) // menu sounds must not be freed on level change sfx->flags |= SFXFLAG_MENUSOUND; + // fun fact: in Quake 1, this used -1 "replace any entity channel", + // which we no longer support anyway + // changed by Black in r4297 "Changed S_LocalSound to play multiple sounds at a time." ch_ind = S_StartSound (cl.viewentity, 0, sfx, vec3_origin, 1, 0); if (ch_ind < 0) return false; diff --git a/sound.h b/sound.h index cb35c112..ff1e9187 100644 --- a/sound.h +++ b/sound.h @@ -73,6 +73,28 @@ void S_ClearUsed (void); void S_PurgeUnused (void); qboolean S_IsSoundPrecached (const sfx_t *sfx); +// for sound() builtins +#define CHANFLAG_RELIABLE 1 + +// these define the "engine" channel namespace +#define CHAN_MIN_AUTO -128 +#define CHAN_MAX_AUTO 0 +#define CHAN_MIN_SINGLE 1 +#define CHAN_MAX_SINGLE 127 +#define IS_CHAN_AUTO(n) ((n) >= CHAN_MIN_AUTO && (n) <= CHAN_MAX_AUTO) +#define IS_CHAN_SINGLE(n) ((n) >= CHAN_MIN_SINGLE && (n) <= CHAN_MAX_SINGLE) +#define IS_CHAN(n) (IS_CHAN_AUTO(n) || IS_CHAN_SINGLE(n)) + +// engine channel == network channel +#define CHAN_ENGINE2NET(c) (c) +#define CHAN_NET2ENGINE(c) (c) + +// engine view of channel encodes the auto flag into the channel number (see CHAN_ constants below) +// user view uses the flags bitmask for it +#define CHAN_USER2ENGINE(c) (c) +#define CHAN_ENGINE2USER(c) (c) +#define CHAN_ENGINE2CVAR(c) (abs(c)) + // S_StartSound returns the channel index, or -1 if an error occurred int S_StartSound (int entnum, int entchannel, sfx_t *sfx, vec3_t origin, float fvol, float attenuation); int S_StartSound_StartPosition (int entnum, int entchannel, sfx_t *sfx, vec3_t origin, float fvol, float attenuation, float startposition); diff --git a/sv_main.c b/sv_main.c index 75255fed..bc6eaf0a 100644 --- a/sv_main.c +++ b/sv_main.c @@ -693,10 +693,13 @@ Larger attenuations will drop off. (max 4 attenuation) ================== */ -void SV_StartSound (prvm_edict_t *entity, int channel, const char *sample, int volume, float attenuation) +void SV_StartSound (prvm_edict_t *entity, int channel, const char *sample, int volume, float attenuation, qboolean reliable) { + sizebuf_t *dest; int sound_num, field_mask, i, ent; + dest = (reliable ? &sv.reliable_datagram : &sv.datagram); + if (volume < 0 || volume > 255) { Con_Printf ("SV_StartSound: volume = %i\n", volume); @@ -709,12 +712,14 @@ void SV_StartSound (prvm_edict_t *entity, int channel, const char *sample, int v return; } - if (channel < 0 || channel > 7) + if (!IS_CHAN(channel)) { Con_Printf ("SV_StartSound: channel = %i\n", channel); return; } + channel = CHAN_ENGINE2NET(channel); + if (sv.datagram.cursize > MAX_PACKETFRAGMENT-21) return; @@ -730,32 +735,35 @@ void SV_StartSound (prvm_edict_t *entity, int channel, const char *sample, int v field_mask |= SND_VOLUME; if (attenuation != DEFAULT_SOUND_PACKET_ATTENUATION) field_mask |= SND_ATTENUATION; - if (ent >= 8192) + if (ent >= 8192 || channel < 0 || channel > 7) field_mask |= SND_LARGEENTITY; - if (sound_num >= 256 || channel >= 8) + if (sound_num >= 256) field_mask |= SND_LARGESOUND; // directed messages go only to the entity they are targeted on - MSG_WriteByte (&sv.datagram, svc_sound); - MSG_WriteByte (&sv.datagram, field_mask); + MSG_WriteByte (dest, svc_sound); + MSG_WriteByte (dest, field_mask); if (field_mask & SND_VOLUME) - MSG_WriteByte (&sv.datagram, volume); + MSG_WriteByte (dest, volume); if (field_mask & SND_ATTENUATION) - MSG_WriteByte (&sv.datagram, (int)(attenuation*64)); + MSG_WriteByte (dest, (int)(attenuation*64)); if (field_mask & SND_LARGEENTITY) { - MSG_WriteShort (&sv.datagram, ent); - MSG_WriteByte (&sv.datagram, channel); + MSG_WriteShort (dest, ent); + MSG_WriteChar (dest, channel); } else - MSG_WriteShort (&sv.datagram, (ent<<3) | channel); + MSG_WriteShort (dest, (ent<<3) | channel); if ((field_mask & SND_LARGESOUND) || sv.protocol == PROTOCOL_NEHAHRABJP2) - MSG_WriteShort (&sv.datagram, sound_num); + MSG_WriteShort (dest, sound_num); else - MSG_WriteByte (&sv.datagram, sound_num); + MSG_WriteByte (dest, sound_num); for (i = 0;i < 3;i++) - MSG_WriteCoord (&sv.datagram, PRVM_serveredictvector(entity, origin)[i]+0.5*(PRVM_serveredictvector(entity, mins)[i]+PRVM_serveredictvector(entity, maxs)[i]), sv.protocol); - SV_FlushBroadcastMessages(); + MSG_WriteCoord (dest, PRVM_serveredictvector(entity, origin)[i]+0.5*(PRVM_serveredictvector(entity, mins)[i]+PRVM_serveredictvector(entity, maxs)[i]), sv.protocol); + + // TODO do we have to do anything here when dest is &sv.reliable_datagram? + if(!reliable) + SV_FlushBroadcastMessages(); } /* diff --git a/sv_phys.c b/sv_phys.c index 9c8b532b..0e3ac330 100644 --- a/sv_phys.c +++ b/sv_phys.c @@ -2440,7 +2440,7 @@ void SV_CheckWaterTransition (prvm_edict_t *ent) { // Contents Transition Function Invalid; Potentially Play Water Sound // check if the entity crossed into or out of water if (sv_sound_watersplash.string && ((PRVM_serveredictfloat(ent, watertype) == CONTENTS_WATER || PRVM_serveredictfloat(ent, watertype) == CONTENTS_SLIME) != (cont == CONTENTS_WATER || cont == CONTENTS_SLIME))) - SV_StartSound (ent, 0, sv_sound_watersplash.string, 255, 1); + SV_StartSound (ent, 0, sv_sound_watersplash.string, 255, 1, false); } if (cont <= CONTENTS_WATER) @@ -2683,7 +2683,7 @@ void SV_Physics_Step (prvm_edict_t *ent) else // Check for Engine Landing Sound if(sv_sound_land.string) - SV_StartSound(ent, 0, sv_sound_land.string, 255, 1); + SV_StartSound(ent, 0, sv_sound_land.string, 255, 1, false); } ent->priv.server->waterposition_forceupdate = true; } diff --git a/svvm_cmds.c b/svvm_cmds.c index 5c7de143..f252ade1 100644 --- a/svvm_cmds.c +++ b/svvm_cmds.c @@ -140,6 +140,7 @@ const char *vm_sv_extensions = "DP_SKELETONOBJECTS " "DP_SND_DIRECTIONLESSATTNNONE " "DP_SND_FAKETRACKS " +"DP_SND_SOUND7_WIP1 " "DP_SND_OGGVORBIS " "DP_SND_SETPARAMS " "DP_SND_STEREOWAV " @@ -510,20 +511,39 @@ static void VM_SV_sound (void) int channel; prvm_edict_t *entity; int volume; + int flags; float attenuation; + float pitchchange; - VM_SAFEPARMCOUNTRANGE(4, 5, VM_SV_sound); + VM_SAFEPARMCOUNTRANGE(4, 7, VM_SV_sound); entity = PRVM_G_EDICT(OFS_PARM0); channel = (int)PRVM_G_FLOAT(OFS_PARM1); sample = PRVM_G_STRING(OFS_PARM2); volume = (int)(PRVM_G_FLOAT(OFS_PARM3) * 255); - attenuation = PRVM_G_FLOAT(OFS_PARM4); if (prog->argc < 5) { Con_DPrintf("VM_SV_sound: given only 4 parameters, expected 5, assuming attenuation = ATTN_NORMAL\n"); attenuation = 1; } + else + attenuation = PRVM_G_FLOAT(OFS_PARM4); + if (prog->argc < 6) + pitchchange = 0; + else + pitchchange = PRVM_G_FLOAT(OFS_PARM5); + + if (prog->argc < 7) + { + flags = 0; + if(channel >= 8 && channel <= 15) // weird QW feature + { + flags |= CHANFLAG_RELIABLE; + channel -= 8; + } + } + else + flags = PRVM_G_FLOAT(OFS_PARM6); if (volume < 0 || volume > 255) { @@ -537,13 +557,15 @@ static void VM_SV_sound (void) return; } - if (channel < 0 || channel > 7) + channel = CHAN_USER2ENGINE(channel); + + if (!IS_CHAN(channel)) { - VM_Warning("SV_StartSound: channel must be in range 0-7\n"); + VM_Warning("SV_StartSound: channel must be in range 0-127\n"); return; } - SV_StartSound (entity, channel, sample, volume, attenuation); + SV_StartSound (entity, channel, sample, volume, attenuation, flags & CHANFLAG_RELIABLE); } /* -- 2.39.2