Browse Source

WIP FMOD sound system:

- Quick hack channel userdata for attenuation to test normal entity sounds
- Always set full volume for sounds coming from the view entity (i.e. the player)
- It's starting to sound like Quake!
console
Nico de Poel 5 years ago
parent
commit
f5b948af3a
  1. 35
      engine/Quake/snd_fmod.c

35
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)

Loading…
Cancel
Save