From 8e5d3750fe6c2938222b1a6547b0d26b7a1ede60 Mon Sep 17 00:00:00 2001 From: Mario Date: Wed, 22 Jul 2020 05:07:09 +1000 Subject: [PATCH] Add support for pitch shifting to the QC sound sending implementation, apply pitch shifting to player sounds --- qcsrc/common/effects/qc/globalsound.qc | 66 ++++++++++++------- qcsrc/common/effects/qc/globalsound.qh | 2 + .../gamemode/onslaught/sv_onslaught.qc | 2 +- qcsrc/common/mapobjects/func/bobbing.qc | 2 +- qcsrc/common/mapobjects/func/breakable.qc | 2 +- qcsrc/common/mapobjects/func/fourier.qc | 2 +- qcsrc/common/mapobjects/func/pendulum.qc | 2 +- qcsrc/common/mapobjects/func/rotating.qc | 2 +- qcsrc/common/mapobjects/func/vectormamamam.qc | 2 +- qcsrc/common/mapobjects/target/speaker.qc | 2 +- qcsrc/common/sounds/all.qc | 14 ++-- qcsrc/common/t_items.qc | 2 +- qcsrc/common/vehicles/vehicle/raptor.qc | 2 +- qcsrc/server/miscfunctions.qh | 4 +- qcsrc/server/weapons/tracing.qc | 2 +- 15 files changed, 66 insertions(+), 42 deletions(-) diff --git a/qcsrc/common/effects/qc/globalsound.qc b/qcsrc/common/effects/qc/globalsound.qc index 8ce2b6ed3..06b8baa1a 100644 --- a/qcsrc/common/effects/qc/globalsound.qc +++ b/qcsrc/common/effects/qc/globalsound.qc @@ -17,7 +17,7 @@ * @param gs the global sound def * @param r a random number in 0..1 */ - void globalsound(int channel, entity from, entity gs, float r, int chan, float _vol, float _atten) + void globalsound(int channel, entity from, entity gs, float r, int chan, float _vol, float _atten, float _pitch) { //assert(IS_PLAYER(from), eprint(from)); if (channel == MSG_ONE && !IS_REAL_CLIENT(msg_entity)) return; @@ -25,14 +25,16 @@ string sample = GlobalSound_sample(gs.m_globalsoundstr, r); switch (channel) { case MSG_ONE: - soundto(channel, from, chan, sample, _vol, _atten); + soundto(channel, from, chan, sample, _vol, _atten, _pitch); break; case MSG_ALL: - _sound(from, chan, sample, _vol, _atten); + if(sound_allowed(MSG_BROADCAST, from)) + sound7(from, chan, sample, _vol, _atten, _pitch, 0); break; } return; } + // FIXME: pitch not implemented WriteHeader(channel, globalsound); WriteByte(channel, gs.m_id); WriteByte(channel, r * 255); @@ -50,7 +52,7 @@ * @param ps the player sound def * @param r a random number in 0..1 */ - void playersound(int channel, entity from, entity ps, float r, int chan, float _vol, float _atten) + void playersound(int channel, entity from, entity ps, float r, int chan, float _vol, float _atten, float _pitch) { //assert(IS_PLAYER(from), eprint(from)); if (channel == MSG_ONE && !IS_REAL_CLIENT(msg_entity)) return; @@ -60,14 +62,16 @@ string sample = GlobalSound_sample(s, r); switch (channel) { case MSG_ONE: - soundto(channel, from, chan, sample, _vol, _atten); + soundto(channel, from, chan, sample, _vol, _atten, _pitch); break; case MSG_ALL: - _sound(from, chan, sample, _vol, _atten); + if(sound_allowed(MSG_BROADCAST, from)) + sound7(from, chan, sample, _vol, _atten, _pitch, 0); break; } return; } + // FIXME: pitch not implemented WriteHeader(channel, playersound); WriteByte(channel, ps.m_id); WriteByte(channel, r * 255); @@ -155,6 +159,18 @@ return sample; } + float GlobalSound_pitch(float _pitch) + { + // customizable gradient function that crosses (0,a), (c,1) and asymptotically approaches b + float a = 1.5; // max pitch + float b = 0.75; // min pitch + float c = 100; // standard pitch (scale * 100) + float d = _pitch; + float pitch_shift = (b*d*(a-1) + a*c*(1-b)) / (d*(a-1) + c*(1-b)); + + return pitch_shift * 100; + } + void PrecacheGlobalSound(string sample) { int n; @@ -305,6 +321,8 @@ if (gs == NULL && ps == NULL && sample == "") return; if(this.classname == "body") return; float r = random(); + float myscale = ((this.scale) ? this.scale : 1); // safety net + float thepitch = ((myscale == 1) ? 0 : GlobalSound_pitch(myscale * 100)); if (sample != "") sample = GlobalSound_sample(sample, r); switch (voicetype) { @@ -318,18 +336,18 @@ if (IS_REAL_CLIENT(msg_entity)) { float atten = (CS(msg_entity).cvar_cl_voice_directional == 1) ? ATTEN_MIN : ATTEN_NONE; - if (gs) globalsound(MSG_ONE, this, gs, r, chan, vol, atten); - else if (ps) playersound(MSG_ONE, this, ps, r, chan, vol, atten); - else soundto(MSG_ONE, this, chan, sample, vol, atten); + if (gs) globalsound(MSG_ONE, this, gs, r, chan, vol, atten, thepitch); + else if (ps) playersound(MSG_ONE, this, ps, r, chan, vol, atten, thepitch); + else soundto(MSG_ONE, this, chan, sample, vol, atten, thepitch); } } if (voicetype == VOICETYPE_LASTATTACKER_ONLY) break; msg_entity = this; if (IS_REAL_CLIENT(msg_entity)) { - if (gs) globalsound(MSG_ONE, this, gs, r, chan, VOL_BASE, ATTEN_NONE); - else if (ps) playersound(MSG_ONE, this, ps, r, chan, VOL_BASE, ATTEN_NONE); - else soundto(MSG_ONE, this, chan, sample, VOL_BASE, ATTEN_NONE); + if (gs) globalsound(MSG_ONE, this, gs, r, chan, VOL_BASE, ATTEN_NONE, thepitch); + else if (ps) playersound(MSG_ONE, this, ps, r, chan, VOL_BASE, ATTEN_NONE, thepitch); + else soundto(MSG_ONE, this, chan, sample, VOL_BASE, ATTEN_NONE, thepitch); } break; } @@ -338,9 +356,9 @@ #define X() \ MACRO_BEGIN \ float atten = (CS(msg_entity).cvar_cl_voice_directional == 1) ? ATTEN_MIN : ATTEN_NONE; \ - if (gs) globalsound(MSG_ONE, this, gs, r, chan, vol, atten); \ - else if (ps) playersound(MSG_ONE, this, ps, r, chan, vol, atten); \ - else soundto(MSG_ONE, this, chan, sample, vol, atten); \ + if (gs) globalsound(MSG_ONE, this, gs, r, chan, vol, atten, thepitch); \ + else if (ps) playersound(MSG_ONE, this, ps, r, chan, vol, atten, thepitch); \ + else soundto(MSG_ONE, this, chan, sample, vol, atten, thepitch); \ MACRO_END if (fake) { msg_entity = this; X(); } @@ -377,9 +395,9 @@ ? bound(ATTEN_MIN, CS(msg_entity).cvar_cl_voice_directional_taunt_attenuation, \ ATTEN_MAX) \ : ATTEN_NONE; \ - if (gs) globalsound(MSG_ONE, this, gs, r, chan, vol, atten); \ - else if (ps) playersound(MSG_ONE, this, ps, r, chan, vol, atten); \ - else soundto(MSG_ONE, this, chan, sample, vol, atten); \ + if (gs) globalsound(MSG_ONE, this, gs, r, chan, vol, atten, thepitch); \ + else if (ps) playersound(MSG_ONE, this, ps, r, chan, vol, atten, thepitch); \ + else soundto(MSG_ONE, this, chan, sample, vol, atten, thepitch); \ } \ MACRO_END if (fake) @@ -402,15 +420,15 @@ msg_entity = this; if (fake) { - if (gs) globalsound(MSG_ONE, this, gs, r, chan, vol, ATTEN_NORM); - else if (ps) playersound(MSG_ONE, this, ps, r, chan, vol, ATTEN_NORM); - else soundto(MSG_ONE, this, chan, sample, vol, ATTEN_NORM); + if (gs) globalsound(MSG_ONE, this, gs, r, chan, vol, ATTEN_NORM, thepitch); + else if (ps) playersound(MSG_ONE, this, ps, r, chan, vol, ATTEN_NORM, thepitch); + else soundto(MSG_ONE, this, chan, sample, vol, ATTEN_NORM, thepitch); } else { - if (gs) globalsound(MSG_ALL, this, gs, r, chan, vol, ATTEN_NORM); - else if (ps) playersound(MSG_ALL, this, ps, r, chan, vol, ATTEN_NORM); - else _sound(this, chan, sample, vol, ATTEN_NORM); + if (gs) globalsound(MSG_ALL, this, gs, r, chan, vol, ATTEN_NORM, thepitch); + else if (ps) playersound(MSG_ALL, this, ps, r, chan, vol, ATTEN_NORM, thepitch); + else if (sound_allowed(MSG_BROADCAST, this)) sound7(this, chan, sample, vol, ATTEN_NORM, thepitch, 0); } break; } diff --git a/qcsrc/common/effects/qc/globalsound.qh b/qcsrc/common/effects/qc/globalsound.qh index 2b6b52896..5460d72ac 100644 --- a/qcsrc/common/effects/qc/globalsound.qh +++ b/qcsrc/common/effects/qc/globalsound.qh @@ -123,6 +123,8 @@ entity GetVoiceMessage(string type); string GlobalSound_sample(string pair, float r); +float GlobalSound_pitch(float _pitch); + #ifdef SVQC void _GlobalSound(entity this, entity gs, entity ps, string sample, float chan, float vol, float voicetype, bool fake); diff --git a/qcsrc/common/gamemodes/gamemode/onslaught/sv_onslaught.qc b/qcsrc/common/gamemodes/gamemode/onslaught/sv_onslaught.qc index 9675634ec..1f3e43378 100644 --- a/qcsrc/common/gamemodes/gamemode/onslaught/sv_onslaught.qc +++ b/qcsrc/common/gamemodes/gamemode/onslaught/sv_onslaught.qc @@ -998,7 +998,7 @@ void ons_GeneratorThink(entity this) { Send_Notification(NOTIF_ONE, it, MSG_CENTER, CENTER_ONS_NOTSHIELDED_TEAM); msg_entity = it; - soundto(MSG_ONE, this, CHAN_AUTO, SND(ONS_GENERATOR_ALARM), VOL_BASE, ATTEN_NONE); + soundto(MSG_ONE, this, CHAN_AUTO, SND(ONS_GENERATOR_ALARM), VOL_BASE, ATTEN_NONE, 0); } else Send_Notification(NOTIF_ONE, it, MSG_CENTER, APP_TEAM_NUM(this.team, CENTER_ONS_NOTSHIELDED)); diff --git a/qcsrc/common/mapobjects/func/bobbing.qc b/qcsrc/common/mapobjects/func/bobbing.qc index 60920fafb..3c4229a09 100644 --- a/qcsrc/common/mapobjects/func/bobbing.qc +++ b/qcsrc/common/mapobjects/func/bobbing.qc @@ -35,7 +35,7 @@ spawnfunc(func_bobbing) if (this.noise != "") { precache_sound(this.noise); - soundto(MSG_INIT, this, CH_TRIGGER_SINGLE, this.noise, VOL_BASE, ATTEN_IDLE); + soundto(MSG_INIT, this, CH_TRIGGER_SINGLE, this.noise, VOL_BASE, ATTEN_IDLE, 0); } if (!this.speed) this.speed = 4; diff --git a/qcsrc/common/mapobjects/func/breakable.qc b/qcsrc/common/mapobjects/func/breakable.qc index e92af677c..24d713943 100644 --- a/qcsrc/common/mapobjects/func/breakable.qc +++ b/qcsrc/common/mapobjects/func/breakable.qc @@ -187,7 +187,7 @@ void func_breakable_init_for_player(entity this, entity player) if (this.noise1 && this.state == STATE_ALIVE && IS_REAL_CLIENT(player)) { msg_entity = player; - soundto (MSG_ONE, this, CH_TRIGGER_SINGLE, this.noise1, VOL_BASE, ATTEN_NORM); + soundto (MSG_ONE, this, CH_TRIGGER_SINGLE, this.noise1, VOL_BASE, ATTEN_NORM, 0); } } diff --git a/qcsrc/common/mapobjects/func/fourier.qc b/qcsrc/common/mapobjects/func/fourier.qc index 28e0f0f7c..73bb60536 100644 --- a/qcsrc/common/mapobjects/func/fourier.qc +++ b/qcsrc/common/mapobjects/func/fourier.qc @@ -46,7 +46,7 @@ spawnfunc(func_fourier) if (this.noise != "") { precache_sound(this.noise); - soundto(MSG_INIT, this, CH_TRIGGER_SINGLE, this.noise, VOL_BASE, ATTEN_IDLE); + soundto(MSG_INIT, this, CH_TRIGGER_SINGLE, this.noise, VOL_BASE, ATTEN_IDLE, 0); } if (!this.speed) diff --git a/qcsrc/common/mapobjects/func/pendulum.qc b/qcsrc/common/mapobjects/func/pendulum.qc index a59f7a93b..c582f47f6 100644 --- a/qcsrc/common/mapobjects/func/pendulum.qc +++ b/qcsrc/common/mapobjects/func/pendulum.qc @@ -28,7 +28,7 @@ spawnfunc(func_pendulum) if (this.noise != "") { precache_sound(this.noise); - soundto(MSG_INIT, this, CH_TRIGGER_SINGLE, this.noise, VOL_BASE, ATTEN_IDLE); + soundto(MSG_INIT, this, CH_TRIGGER_SINGLE, this.noise, VOL_BASE, ATTEN_IDLE, 0); } this.active = ACTIVE_ACTIVE; diff --git a/qcsrc/common/mapobjects/func/rotating.qc b/qcsrc/common/mapobjects/func/rotating.qc index 35351ee08..1864b6dfe 100644 --- a/qcsrc/common/mapobjects/func/rotating.qc +++ b/qcsrc/common/mapobjects/func/rotating.qc @@ -47,7 +47,7 @@ void func_rotating_init_for_player(entity this, entity player) if (this.noise && this.noise != "" && this.active == ACTIVE_ACTIVE && IS_REAL_CLIENT(player)) { msg_entity = player; - soundto (MSG_ONE, this, CH_AMBIENT_SINGLE, this.noise, VOL_BASE, ATTEN_IDLE); + soundto (MSG_ONE, this, CH_AMBIENT_SINGLE, this.noise, VOL_BASE, ATTEN_IDLE, 0); } } diff --git a/qcsrc/common/mapobjects/func/vectormamamam.qc b/qcsrc/common/mapobjects/func/vectormamamam.qc index 61da52acb..4882fe37d 100644 --- a/qcsrc/common/mapobjects/func/vectormamamam.qc +++ b/qcsrc/common/mapobjects/func/vectormamamam.qc @@ -128,7 +128,7 @@ void func_vectormamamam_init_for_player(entity this, entity player) if (this.noise && this.noise != "" && this.active == ACTIVE_ACTIVE && IS_REAL_CLIENT(player)) { msg_entity = player; - soundto(MSG_ONE, this, CH_TRIGGER_SINGLE, this.noise, VOL_BASE, ATTEN_IDLE); + soundto(MSG_ONE, this, CH_TRIGGER_SINGLE, this.noise, VOL_BASE, ATTEN_IDLE, 0); } } diff --git a/qcsrc/common/mapobjects/target/speaker.qc b/qcsrc/common/mapobjects/target/speaker.qc index e67f4b34c..6766139c5 100644 --- a/qcsrc/common/mapobjects/target/speaker.qc +++ b/qcsrc/common/mapobjects/target/speaker.qc @@ -28,7 +28,7 @@ void target_speaker_use_activator(entity this, entity actor, entity trigger) else snd = this.noise; msg_entity = actor; - soundto(MSG_ONE, this, CH_TRIGGER, snd, VOL_BASE * this.volume, this.atten); + soundto(MSG_ONE, this, CH_TRIGGER, snd, VOL_BASE * this.volume, this.atten, 0); } void target_speaker_use_on(entity this, entity actor, entity trigger) { diff --git a/qcsrc/common/sounds/all.qc b/qcsrc/common/sounds/all.qc index fcd4d9a45..fdbf41180 100644 --- a/qcsrc/common/sounds/all.qc +++ b/qcsrc/common/sounds/all.qc @@ -34,8 +34,9 @@ const int SND_VOLUME = BIT(0); const int SND_ATTENUATION = BIT(1); const int SND_LARGEENTITY = BIT(3); const int SND_LARGESOUND = BIT(4); +const int SND_SPEEDUSHORT4000 = BIT(5); -void soundtoat(int to, entity e, vector o, int chan, string samp, float vol, float attenu) +void soundtoat(int to, entity e, vector o, int chan, string samp, float vol, float attenu, float _pitch) { if (!sound_allowed(to, e)) return; int entno = etof(e); @@ -43,14 +44,17 @@ void soundtoat(int to, entity e, vector o, int chan, string samp, float vol, flo attenu = floor(attenu * 64); vol = floor(vol * 255); int sflags = 0; + int speed4000 = floor((_pitch * 0.01) * 4000 + 0.5); if (vol != 255) sflags |= SND_VOLUME; if (attenu != 64) sflags |= SND_ATTENUATION; if (entno >= 8192 || chan < 0 || chan > 7) sflags |= SND_LARGEENTITY; if (idx >= 256) sflags |= SND_LARGESOUND; + if (speed4000 && speed4000 != 4000) sflags |= SND_SPEEDUSHORT4000; WriteByte(to, SVC_SOUND); WriteByte(to, sflags); if (sflags & SND_VOLUME) WriteByte(to, vol); if (sflags & SND_ATTENUATION) WriteByte(to, attenu); + if (sflags & SND_SPEEDUSHORT4000) WriteShort(to, speed4000); if (sflags & SND_LARGEENTITY) { WriteShort(to, entno); @@ -67,15 +71,15 @@ void soundtoat(int to, entity e, vector o, int chan, string samp, float vol, flo WriteCoord(to, o.z); } -void soundto(int _dest, entity e, int chan, string samp, float vol, float _atten) +void soundto(int _dest, entity e, int chan, string samp, float vol, float _atten, float _pitch) { if (!sound_allowed(_dest, e)) return; vector o = e.origin + 0.5 * (e.mins + e.maxs); - soundtoat(_dest, e, o, chan, samp, vol, _atten); + soundtoat(_dest, e, o, chan, samp, vol, _atten, _pitch); } void soundat(entity e, vector o, int chan, string samp, float vol, float _atten) { - soundtoat(((chan & 8) ? MSG_ALL : MSG_BROADCAST), e, o, chan, samp, vol, _atten); + soundtoat(((chan & 8) ? MSG_ALL : MSG_BROADCAST), e, o, chan, samp, vol, _atten, 0); } void stopsoundto(int _dest, entity e, int chan) { @@ -112,7 +116,7 @@ void stopsound(entity e, int chan) void play2(entity e, string filename) { msg_entity = e; - soundtoat(MSG_ONE, NULL, '0 0 0', CH_INFO, filename, VOL_BASE, ATTEN_NONE); + soundtoat(MSG_ONE, NULL, '0 0 0', CH_INFO, filename, VOL_BASE, ATTEN_NONE, 0); } .float spamtime; diff --git a/qcsrc/common/t_items.qc b/qcsrc/common/t_items.qc index 37cb77a7a..ef2923b86 100644 --- a/qcsrc/common/t_items.qc +++ b/qcsrc/common/t_items.qc @@ -540,7 +540,7 @@ void Item_RespawnCountdown(entity this) if(this.waypointsprite_attached.waypointsprite_visible_for_player(this.waypointsprite_attached, it, it)) { msg_entity = it; - soundto(MSG_ONE, this, CH_TRIGGER, SND(ITEMRESPAWNCOUNTDOWN), VOL_BASE, ATTEN_NORM); // play respawn sound + soundto(MSG_ONE, this, CH_TRIGGER, SND(ITEMRESPAWNCOUNTDOWN), VOL_BASE, ATTEN_NORM, 0); // play respawn sound } }); diff --git a/qcsrc/common/vehicles/vehicle/raptor.qc b/qcsrc/common/vehicles/vehicle/raptor.qc index 015f947b2..a868eb4aa 100644 --- a/qcsrc/common/vehicles/vehicle/raptor.qc +++ b/qcsrc/common/vehicles/vehicle/raptor.qc @@ -422,7 +422,7 @@ bool raptor_frame(entity this, float dt) if(incoming) { msg_entity = this; - soundto(MSG_ONE, vehic, CH_PAIN_SINGLE, SND(VEH_MISSILE_ALARM), VOL_BASE, ATTEN_NONE); + soundto(MSG_ONE, vehic, CH_PAIN_SINGLE, SND(VEH_MISSILE_ALARM), VOL_BASE, ATTEN_NONE, 0); } vehic.bomb1.cnt = time + 1; diff --git a/qcsrc/server/miscfunctions.qh b/qcsrc/server/miscfunctions.qh index e94ee9c6c..c61dc1e71 100644 --- a/qcsrc/server/miscfunctions.qh +++ b/qcsrc/server/miscfunctions.qh @@ -35,7 +35,7 @@ void soundat(entity e, vector o, float chan, string samp, float vol, float _atte void InitializeEntitiesRun(); void stopsoundto(float _dest, entity e, float chan); -void soundtoat(float _dest, entity e, vector o, float chan, string samp, float vol, float _atten); +void soundtoat(float _dest, entity e, vector o, float chan, string samp, float vol, float _atten, float _pitch); void droptofloor(entity this); @@ -82,7 +82,7 @@ void remove_unsafely(entity e); void SetMovetypeFollow(entity ent, entity e); -void soundto(float dest, entity e, float chan, string samp, float vol, float atten); +void soundto(float dest, entity e, float chan, string samp, float vol, float atten, float _pitch); void stopsound(entity e, float chan); diff --git a/qcsrc/server/weapons/tracing.qc b/qcsrc/server/weapons/tracing.qc index 6209710b6..3259523f0 100644 --- a/qcsrc/server/weapons/tracing.qc +++ b/qcsrc/server/weapons/tracing.qc @@ -285,7 +285,7 @@ void FireRailgunBullet (entity this, .entity weaponentity, vector start, vector msg_entity = it; // we want this to be very loud when close but fall off quickly -> using max base volume and high attenuation - soundtoat(MSG_ONE, pseudoprojectile, beampos, CH_SHOTS, SND(NEXWHOOSH_RANDOM()), VOL_BASEVOICE, ATTEN_IDLE); + soundtoat(MSG_ONE, pseudoprojectile, beampos, CH_SHOTS, SND(NEXWHOOSH_RANDOM()), VOL_BASEVOICE, ATTEN_IDLE, 0); }); if(pseudoprojectile) delete(pseudoprojectile); -- 2.39.2