diff --git a/engine/Quake/snd_fmod.c b/engine/Quake/snd_fmod.c index 911dc0f..23b5404 100644 --- a/engine/Quake/snd_fmod.c +++ b/engine/Quake/snd_fmod.c @@ -22,7 +22,6 @@ static float SND_FMOD_Attenuation(FMOD_CHANNELCONTROL *channelControl, float dis typedef struct entchannel_s { - sfx_t *sfx; int entnum; int entchannel; float dist_mult; @@ -134,6 +133,12 @@ static float SND_FMOD_Attenuation(FMOD_CHANNELCONTROL *channelcontrol, float dis return 1.0f; } + // Anything coming from the view entity will always be full volume + if (userdata->entnum == cl.viewentity) + { + return 1.0f; + } + scale = 1.0f - (distance * userdata->dist_mult); if (scale < 0.0f) scale = 0.0f; @@ -190,7 +195,7 @@ static float SND_FMOD_Attenuation(FMOD_CHANNELCONTROL *channelcontrol, float dis // return channel; //} -void S_StartSound(int entnum, int entchannel, sfx_t *sfx, vec3_t origin, float fvol, float attenuation) +void S_StartSound(int entnum, int entchannel, sfx_t *sfx, vec3_t origin, float fvol, float attenuation) // Note: volume and attenuation are properly normalized here { FMOD_CHANNEL *channel; FMOD_VECTOR position; @@ -200,7 +205,7 @@ void S_StartSound(int entnum, int entchannel, sfx_t *sfx, vec3_t origin, float f return; // TODO: check nosound cvar - return; // HACK play no entity sfx for now + //return; // HACK play no entity sfx for now S_LoadSound(sfx); if (!sfx->sound) @@ -208,12 +213,13 @@ void S_StartSound(int entnum, int entchannel, sfx_t *sfx, vec3_t origin, float f // Find channel group for entity number (or create) => note entnum can also be some random hash value // ChannelControl::setMode => set to 3D + // Can use channel group per entity to store entity-specific userdata, with maybe 16 fixed channel slots // Pre-define channels for each entity (could be an array of ints, probably array of entchannel_t structs) // For entchannel 0, dynamically select a free channel (or just play without doing anything, let FMOD handle it) // If channel at index entchannel >0 is already playing: stop // Set userdata pointer to entchannel_t so we can check if the FMOD channel still belongs to this entity & entchannel, before checking if it's already playing - // Special case entchannel -1 => just play locally on listener, no 3D + // Special case entchannel -1 => just play locally on listener, no 3D (also override any sound already playing on entity) // System::playSound with paused = true result = FMOD_System_PlaySound(fmod_system, sfx->sound, sfx_channelGroup, 1, &channel); @@ -229,7 +235,14 @@ void S_StartSound(int entnum, int entchannel, sfx_t *sfx, vec3_t origin, float f FMOD_Channel_SetMode(channel, FMOD_LOOP_OFF); // TODO: some entity sounds do need to loop, e.g. moving elevators. How is this done? FMOD_Channel_SetVolume(channel, fvol); FMOD_Channel_Set3DLevel(channel, entchannel < 0 ? 0.0f : 1.0f); // entchannel -1 is used for local sounds - // TODO: attenuation + + // TODO: attenuation (this is just a quick hack to test) + entchannel_t *userdata = (entchannel_t*)malloc(sizeof(entchannel_t)); // TODO: we REALLY need to allocate this properly, this is now a memory leak!! + userdata->entnum = entnum; + userdata->entchannel = entchannel; + userdata->channel = channel; + userdata->dist_mult = attenuation / sound_nominal_clip_dist; + FMOD_Channel_SetUserData(channel, userdata); // TODO: use ChannelControl Callback to detect when the sound ends, then clear it from the entchannel_t list @@ -249,9 +262,6 @@ void S_StaticSound(sfx_t *sfx, vec3_t origin, float vol, float attenuation) // N FMOD_RESULT result; unsigned long long dspclock; - // Similar to above, but without the per-entity channel group song and dance - // Check if sound is looped (should be) and FMOD_Channel_SetMode to looped - // Set Channel::setLoopPoints if the sfxcache specifies something non-standard if (!fmod_system || !sfx) return; @@ -271,14 +281,15 @@ void S_StaticSound(sfx_t *sfx, vec3_t origin, float vol, float attenuation) // N FMOD_Channel_SetMode(channel, FMOD_LOOP_NORMAL); FMOD_Channel_SetVolume(channel, vol / 255); - // TODO: attenuation (which is pre-multiplied by 64) + // Set up attenuation info for use by the rolloff callback entchannel_t *userdata = (entchannel_t*)malloc(sizeof(entchannel_t)); // This is rather convenient. Can we use Z_Malloc here perhaps? - userdata->sfx = sfx; + userdata->entnum = -1; userdata->channel = channel; userdata->dist_mult = (attenuation / 64) / sound_nominal_clip_dist; FMOD_Channel_SetUserData(channel, userdata); - // Add a random delay so that similar sounds don't phase together (note: this isn't really authentic to original Quake, but it improves the sense of directionality) + // Add a random delay so that similar sounds don't phase together + // Note: this isn't really authentic to the original Quake sound system, but it does improve the sense of directionality FMOD_ChannelGroup_GetDSPClock(sfx_channelGroup, &dspclock, NULL); FMOD_Channel_SetDelay(channel, dspclock + SND_GetDelay(sfx), 0, 0); @@ -302,7 +313,7 @@ void S_StopAllSounds(qboolean clear) void S_ClearBuffer(void) { - + // TODO Use this to remove per-entity channel group and clear all userdata? } void S_Update(vec3_t origin, vec3_t forward, vec3_t right, vec3_t up)