From 15eabfd05591d7b762328c6da815b722c2eda5e8 Mon Sep 17 00:00:00 2001 From: Major Cooke Date: Tue, 23 Jul 2019 19:40:19 -0500 Subject: [PATCH] Added A_SoundPitch and an optional pitch parameter to A_PlaySound and S_Sound. - Note: Because sound channels are not in zscript, there's no way to modify a sound made by S_Sound. --- src/scripting/vmthunks_actors.cpp | 12 ++++- src/sound/backend/i_sound.cpp | 3 ++ src/sound/backend/i_sound.h | 4 ++ src/sound/backend/i_soundinternal.h | 1 + src/sound/backend/oalsound.cpp | 62 +++++++++++++++++++---- src/sound/backend/oalsound.h | 3 ++ src/sound/s_sound.cpp | 73 ++++++++++++++++++++++----- src/sound/s_sound.h | 11 +++- wadsrc/static/zscript/actors/actor.zs | 3 +- wadsrc/static/zscript/base.zs | 2 +- 10 files changed, 144 insertions(+), 30 deletions(-) diff --git a/src/scripting/vmthunks_actors.cpp b/src/scripting/vmthunks_actors.cpp index 1a68b340c0..e2548489f8 100644 --- a/src/scripting/vmthunks_actors.cpp +++ b/src/scripting/vmthunks_actors.cpp @@ -142,6 +142,15 @@ DEFINE_ACTION_FUNCTION_NATIVE(AActor, A_StopSound, NativeStopSound) return 0; } +DEFINE_ACTION_FUNCTION_NATIVE(AActor, A_SoundPitch, S_ChangeSoundPitch) +{ + PARAM_SELF_PROLOGUE(AActor); + PARAM_INT(channel); + PARAM_FLOAT(pitch); + S_ChangeSoundPitch(self, channel, pitch); + return 0; +} + DEFINE_ACTION_FUNCTION_NATIVE(AActor, A_SoundVolume, S_ChangeSoundVolume) { PARAM_SELF_PROLOGUE(AActor); @@ -160,7 +169,8 @@ DEFINE_ACTION_FUNCTION_NATIVE(AActor, A_PlaySound, A_PlaySound) PARAM_BOOL(looping); PARAM_FLOAT(attenuation); PARAM_BOOL(local); - A_PlaySound(self, soundid, channel, volume, looping, attenuation, local); + PARAM_FLOAT(pitch); + A_PlaySound(self, soundid, channel, volume, looping, attenuation, local, pitch); return 0; } diff --git a/src/sound/backend/i_sound.cpp b/src/sound/backend/i_sound.cpp index 7820d57340..c7aae60ec2 100644 --- a/src/sound/backend/i_sound.cpp +++ b/src/sound/backend/i_sound.cpp @@ -158,6 +158,9 @@ public: void ChannelVolume(FISoundChannel *, float) { } + void ChannelPitch(FISoundChannel *, float) + { + } // Streaming sounds. SoundStream *CreateStream (SoundStreamCallback callback, int buffbytes, int flags, int samplerate, void *userdata) diff --git a/src/sound/backend/i_sound.h b/src/sound/backend/i_sound.h index ce02f73569..4346118f76 100644 --- a/src/sound/backend/i_sound.h +++ b/src/sound/backend/i_sound.h @@ -39,6 +39,7 @@ #include "i_soundinternal.h" class FileReader; +struct FSoundChan; enum ECodecType { @@ -130,6 +131,9 @@ public: // Changes a channel's volume. virtual void ChannelVolume (FISoundChannel *chan, float volume) = 0; + // Changes a channel's pitch. + virtual void ChannelPitch(FISoundChannel *chan, float volume) = 0; + // Marks a channel's start time without actually playing it. virtual void MarkStartTime (FISoundChannel *chan) = 0; diff --git a/src/sound/backend/i_soundinternal.h b/src/sound/backend/i_soundinternal.h index 6c926b431c..18259c1be3 100644 --- a/src/sound/backend/i_soundinternal.h +++ b/src/sound/backend/i_soundinternal.h @@ -109,6 +109,7 @@ struct FISoundChannel float DistanceScale; float DistanceSqr; bool ManualRolloff; + int ChanFlags; }; diff --git a/src/sound/backend/oalsound.cpp b/src/sound/backend/oalsound.cpp index 7369020e0d..12860b8e67 100644 --- a/src/sound/backend/oalsound.cpp +++ b/src/sound/backend/oalsound.cpp @@ -1870,6 +1870,20 @@ void OpenALSoundRenderer::ChannelVolume(FISoundChannel *chan, float volume) alSourcef(source, AL_GAIN, SfxVolume * volume); } +void OpenALSoundRenderer::ChannelPitch(FISoundChannel *chan, float pitch) +{ + if (chan == NULL || chan->SysChannel == NULL) + return; + + alDeferUpdatesSOFT(); + + ALuint source = GET_PTRID(chan->SysChannel); + if (WasInWater && !(chan->ChanFlags & CHAN_UI)) + alSourcef(source, AL_PITCH, MAX(pitch, 0.0001f)*PITCH_MULT); + else + alSourcef(source, AL_PITCH, MAX(pitch, 0.0001f)); +} + void OpenALSoundRenderer::FreeSource(ALuint source) { alSourceRewind(source); @@ -2118,7 +2132,7 @@ void OpenALSoundRenderer::UpdateListener(SoundListener *listener) const_cast(env)->Modified = false; } - + // NOTE: Moving into and out of water will undo pitch variations on sounds. if(listener->underwater || env->SoftwareWater) { @@ -2138,20 +2152,33 @@ void OpenALSoundRenderer::UpdateListener(SoundListener *listener) alFilterf(EnvFilters[1], AL_LOWPASS_GAINHF, 1.f); // Apply the updated filters on the sources - for(uint32_t i = 0;i < ReverbSfx.Size();++i) + FSoundChan *schan = Channels; + while (schan) { - alSourcei(ReverbSfx[i], AL_DIRECT_FILTER, EnvFilters[0]); - alSource3i(ReverbSfx[i], AL_AUXILIARY_SEND_FILTER, EnvSlot, 0, EnvFilters[1]); + ALuint source = GET_PTRID(schan->SysChannel); + if (source && !(schan->ChanFlags & CHAN_UI)) + { + alSourcei(source, AL_DIRECT_FILTER, EnvFilters[0]); + alSource3i(source, AL_AUXILIARY_SEND_FILTER, EnvSlot, 0, EnvFilters[1]); + } + schan = schan->NextChan; } } - for(uint32_t i = 0;i < ReverbSfx.Size();++i) - alSourcef(ReverbSfx[i], AL_PITCH, PITCH_MULT); + FSoundChan *schan = Channels; + while (schan) + { + ALuint source = GET_PTRID(schan->SysChannel); + if (source && !(schan->ChanFlags & CHAN_UI)) + alSourcef(source, AL_PITCH, schan->Pitch / 128.0f * PITCH_MULT); + schan = schan->NextChan; + } getALError(); } } else if(WasInWater) { + WasInWater = false; if(EnvSlot != 0) @@ -2162,15 +2189,28 @@ void OpenALSoundRenderer::UpdateListener(SoundListener *listener) alFilterf(EnvFilters[0], AL_LOWPASS_GAINHF, 1.f); alFilterf(EnvFilters[1], AL_LOWPASS_GAIN, 1.f); alFilterf(EnvFilters[1], AL_LOWPASS_GAINHF, 1.f); - for(uint32_t i = 0;i < ReverbSfx.Size();++i) + + FSoundChan *schan = Channels; + while (schan) { - alSourcei(ReverbSfx[i], AL_DIRECT_FILTER, EnvFilters[0]); - alSource3i(ReverbSfx[i], AL_AUXILIARY_SEND_FILTER, EnvSlot, 0, EnvFilters[1]); + ALuint source = GET_PTRID(schan->SysChannel); + if (source && !(schan->ChanFlags & CHAN_UI)) + { + alSourcei(source, AL_DIRECT_FILTER, EnvFilters[0]); + alSource3i(source, AL_AUXILIARY_SEND_FILTER, EnvSlot, 0, EnvFilters[1]); + } + schan = schan->NextChan; } } - for(uint32_t i = 0;i < ReverbSfx.Size();++i) - alSourcef(ReverbSfx[i], AL_PITCH, 1.f); + FSoundChan *schan = Channels; + while (schan) + { + ALuint source = GET_PTRID(schan->SysChannel); + if (source && !(schan->ChanFlags & CHAN_UI)) + alSourcef(source, AL_PITCH, schan->Pitch / 128.0f); + schan = schan->NextChan; + } getALError(); } } diff --git a/src/sound/backend/oalsound.h b/src/sound/backend/oalsound.h index 0cf72a1339..2b1a50fd4a 100644 --- a/src/sound/backend/oalsound.h +++ b/src/sound/backend/oalsound.h @@ -144,6 +144,9 @@ public: // Changes a channel's volume. virtual void ChannelVolume(FISoundChannel *chan, float volume); + // Changes a channel's pitch. + virtual void ChannelPitch(FISoundChannel *chan, float pitch); + // Stops a sound channel. virtual void StopChannel(FISoundChannel *chan); diff --git a/src/sound/s_sound.cpp b/src/sound/s_sound.cpp index f114e10356..16a47bd8f6 100644 --- a/src/sound/s_sound.cpp +++ b/src/sound/s_sound.cpp @@ -132,7 +132,7 @@ static void CalcPosVel(int type, const AActor *actor, const sector_t *sector, co static void CalcSectorSoundOrg(const DVector3 &listenpos, const sector_t *sec, int channum, FVector3 &res); static void CalcPolyobjSoundOrg(const DVector3 &listenpos, const FPolyObj *poly, FVector3 &res); static FSoundChan *S_StartSound(AActor *mover, const sector_t *sec, const FPolyObj *poly, - const FVector3 *pt, int channel, FSoundID sound_id, float volume, float attenuation, FRolloffInfo *rolloff); + const FVector3 *pt, int channel, FSoundID sound_id, float volume, float attenuation, FRolloffInfo *rolloff, float spitch); static void S_SetListener(SoundListener &listener, AActor *listenactor); // PRIVATE DATA DEFINITIONS ------------------------------------------------ @@ -929,7 +929,7 @@ static void CalcPolyobjSoundOrg(const DVector3 &listenpos, const FPolyObj *poly, static FSoundChan *S_StartSound(AActor *actor, const sector_t *sec, const FPolyObj *poly, const FVector3 *pt, int channel, FSoundID sound_id, float volume, float attenuation, - FRolloffInfo *forcedrolloff=NULL) + FRolloffInfo *forcedrolloff=NULL, float spitch = 0.0f) { sfxinfo_t *sfx; int chanflags; @@ -1235,6 +1235,10 @@ static FSoundChan *S_StartSound(AActor *actor, const sector_t *sec, const FPolyO default: break; } } + + if (spitch > 0.0) + S_SetPitch(chan, spitch); + return chan; } @@ -1318,9 +1322,14 @@ void S_RestartSound(FSoundChan *chan) // //========================================================================== -void S_Sound (int channel, FSoundID sound_id, float volume, float attenuation) +void S_SoundPitch(int channel, FSoundID sound_id, float volume, float attenuation, float pitch) { - S_StartSound (NULL, NULL, NULL, NULL, channel, sound_id, volume, attenuation); + S_StartSound(NULL, NULL, NULL, NULL, channel, sound_id, volume, attenuation, 0, pitch); +} + +void S_Sound(int channel, FSoundID sound_id, float volume, float attenuation) +{ + S_StartSound (NULL, NULL, NULL, NULL, channel, sound_id, volume, attenuation, 0, 0.f); } DEFINE_ACTION_FUNCTION(DObject, S_Sound) @@ -1330,7 +1339,8 @@ DEFINE_ACTION_FUNCTION(DObject, S_Sound) PARAM_INT(channel); PARAM_FLOAT(volume); PARAM_FLOAT(attn); - S_Sound(channel, id, static_cast(volume), static_cast(attn)); + PARAM_FLOAT(pitch); + S_SoundPitch(channel, id, static_cast(volume), static_cast(attn), static_cast(pitch)); return 0; } @@ -1339,14 +1349,17 @@ DEFINE_ACTION_FUNCTION(DObject, S_Sound) // S_Sound - An actor is source // //========================================================================== - -void S_Sound (AActor *ent, int channel, FSoundID sound_id, float volume, float attenuation) +void S_SoundPitchActor(AActor *ent, int channel, FSoundID sound_id, float volume, float attenuation, float pitch) { if (ent == nullptr || ent->Sector->Flags & SECF_SILENT || ent->Level != primaryLevel) return; - S_StartSound (ent, nullptr, nullptr, nullptr, channel, sound_id, volume, attenuation); + S_StartSound (ent, nullptr, nullptr, nullptr, channel, sound_id, volume, attenuation, 0, pitch); } +void S_Sound(AActor *ent, int channel, FSoundID sound_id, float volume, float attenuation) +{ + S_SoundPitchActor(ent, channel, sound_id, volume, attenuation, 0.f); +} //========================================================================== // // S_SoundMinMaxDist - An actor is source @@ -1414,38 +1427,43 @@ void S_Sound (const sector_t *sec, int channel, FSoundID sfxid, float volume, fl // //========================================================================== -void S_PlaySound(AActor *a, int chan, FSoundID sid, float vol, float atten, bool local) +void S_PlaySoundPitch(AActor *a, int chan, FSoundID sid, float vol, float atten, bool local, float pitch) { if (a == nullptr || a->Sector->Flags & SECF_SILENT || a->Level != primaryLevel) return; if (!local) { - S_Sound(a, chan, sid, vol, atten); + S_SoundPitchActor(a, chan, sid, vol, atten, pitch); } else { if (a->CheckLocalView()) { - S_Sound(chan, sid, vol, ATTN_NONE); + S_SoundPitch(chan, sid, vol, ATTN_NONE, pitch); } } } -void A_PlaySound(AActor *self, int soundid, int channel, double volume, int looping, double attenuation, int local) +void S_PlaySound(AActor *a, int chan, FSoundID sid, float vol, float atten, bool local) +{ + S_PlaySoundPitch(a, chan, sid, vol, atten, local, 0.f); +} + +void A_PlaySound(AActor *self, int soundid, int channel, double volume, int looping, double attenuation, int local, double pitch) { if (!looping) { if (!(channel & CHAN_NOSTOP) || !S_IsActorPlayingSomething(self, channel & 7, soundid)) { - S_PlaySound(self, channel, soundid, (float)volume, (float)attenuation, local); + S_PlaySoundPitch(self, channel, soundid, (float)volume, (float)attenuation, local, (float)pitch); } } else { if (!S_IsActorPlayingSomething(self, channel & 7, soundid)) { - S_PlaySound(self, channel | CHAN_LOOP, soundid, (float)volume, (float)attenuation, local); + S_PlaySoundPitch(self, channel | CHAN_LOOP, soundid, (float)volume, (float)attenuation, local, (float)pitch); } } } @@ -1843,6 +1861,33 @@ void S_ChangeSoundVolume(AActor *actor, int channel, double dvolume) return; } +//========================================================================== +// +// S_ChangeSoundPitch +// +//========================================================================== + +void S_ChangeSoundPitch(AActor *actor, int channel, double pitch) +{ + for (FSoundChan *chan = Channels; chan != NULL; chan = chan->NextChan) + { + if (chan->SourceType == SOURCE_Actor && + chan->Actor == actor && + chan->EntChannel == channel) + { + S_SetPitch(chan, (float)pitch); + return; + } + } + return; +} + +void S_SetPitch(FSoundChan *chan, float pitch) +{ + GSnd->ChannelPitch(chan, MAX(0.0001f, pitch)); + chan->Pitch = MAX(1, int(float(NORM_PITCH) * pitch)); +} + //========================================================================== // // S_GetSoundPlayingInfo diff --git a/src/sound/s_sound.h b/src/sound/s_sound.h index 4118967169..795a8b338f 100644 --- a/src/sound/s_sound.h +++ b/src/sound/s_sound.h @@ -179,7 +179,6 @@ struct FSoundChan : public FISoundChannel FSoundID SoundID; // Sound ID of playing sound. FSoundID OrgID; // Sound ID of sound used to start this channel. float Volume; - int ChanFlags; int16_t Pitch; // Pitch variation. uint8_t EntChannel; // Actor's sound channel. int8_t Priority; @@ -231,8 +230,12 @@ void S_Sound (const FPolyObj *poly, int channel, FSoundID sfxid, float volume, f void S_Sound (const sector_t *sec, int channel, FSoundID sfxid, float volume, float attenuation); void S_Sound(FLevelLocals *Level, const DVector3 &pos, int channel, FSoundID sfxid, float volume, float attenuation); +void S_SoundPitch (int channel, FSoundID sfxid, float volume, float attenuation, float pitch); +void S_SoundPitchActor (AActor *ent, int channel, FSoundID sfxid, float volume, float attenuation, float pitch); + // [Nash] Used by ACS and DECORATE void S_PlaySound(AActor *a, int chan, FSoundID sid, float vol, float atten, bool local); +void S_PlaySoundPitch(AActor *a, int chan, FSoundID sid, float vol, float atten, bool local, float pitch); // sound channels // channel 0 never willingly overrides @@ -310,6 +313,10 @@ bool S_IsActorPlayingSomething (AActor *actor, int channel, int sound_id); // Change a playing sound's volume void S_ChangeSoundVolume(AActor *actor, int channel, double volume); +// Change a playing sound's pitch +void S_ChangeSoundPitch(AActor *actor, int channel, double pitch); +void S_SetPitch(FSoundChan *chan, float dpitch); + // Moves all sounds from one mobj to another void S_RelinkSound (AActor *from, AActor *to); @@ -372,7 +379,7 @@ sfxinfo_t *S_LoadSound(sfxinfo_t *sfx, FSoundLoadBuffer *pBuffer = nullptr); unsigned int S_GetMSLength(FSoundID sound); void S_ParseMusInfo(); bool S_ParseTimeTag(const char *tag, bool *as_samples, unsigned int *time); -void A_PlaySound(AActor *self, int soundid, int channel, double volume, int looping, double attenuation, int local); +void A_PlaySound(AActor *self, int soundid, int channel, double volume, int looping, double attenuation, int local, double pitch); // [RH] Prints sound debug info to the screen. // Modelled after Hexen's noise cheat. diff --git a/wadsrc/static/zscript/actors/actor.zs b/wadsrc/static/zscript/actors/actor.zs index 367e98dcc4..95b162a7a8 100644 --- a/wadsrc/static/zscript/actors/actor.zs +++ b/wadsrc/static/zscript/actors/actor.zs @@ -1052,8 +1052,9 @@ class Actor : Thinker native deprecated("2.3") native void A_BulletAttack(); native void A_WolfAttack(int flags = 0, sound whattoplay = "weapons/pistol", double snipe = 1.0, int maxdamage = 64, int blocksize = 128, int pointblank = 2, int longrange = 4, double runspeed = 160.0, class pufftype = "BulletPuff"); - native clearscope void A_PlaySound(sound whattoplay = "weapons/pistol", int slot = CHAN_BODY, double volume = 1.0, bool looping = false, double attenuation = ATTN_NORM, bool local = false); + native clearscope void A_PlaySound(sound whattoplay = "weapons/pistol", int slot = CHAN_BODY, double volume = 1.0, bool looping = false, double attenuation = ATTN_NORM, bool local = false, double pitch = 0.0); native void A_SoundVolume(int slot, double volume); + native void A_SoundPitch(int slot, double pitch); deprecated("2.3") void A_PlayWeaponSound(sound whattoplay) { A_PlaySound(whattoplay, CHAN_WEAPON); } native void A_StopSound(int slot = CHAN_VOICE); // Bad default but that's what is originally was... deprecated("2.3") native void A_PlaySoundEx(sound whattoplay, name slot, bool looping = false, int attenuation = 0); diff --git a/wadsrc/static/zscript/base.zs b/wadsrc/static/zscript/base.zs index 636b60701c..3d343e8968 100644 --- a/wadsrc/static/zscript/base.zs +++ b/wadsrc/static/zscript/base.zs @@ -442,7 +442,7 @@ class Object native { return level.PickPlayerStart(pnum, flags); } - native static void S_Sound (Sound sound_id, int channel, float volume = 1, float attenuation = ATTN_NORM); + native static void S_Sound (Sound sound_id, int channel, float volume = 1, float attenuation = ATTN_NORM, float pitch = 0.0); native static void S_PauseSound (bool notmusic, bool notsfx); native static void S_ResumeSound (bool notsfx); native static bool S_ChangeMusic(String music_name, int order = 0, bool looping = true, bool force = false);