From 35ba5b0de1a7999720fe62122ccd1c3f35329914 Mon Sep 17 00:00:00 2001 From: Yamagi Burmeister Date: Sat, 20 Apr 2013 08:40:53 +0200 Subject: [PATCH] Move all generic function used only by the SDL backend into it Additionally rename those function to SDL_ prefix and refactor them a little. --- src/backends/sdl/sound.c | 338 ++++++++++++++++++++++++++++++-- src/client/sound/header/local.h | 6 +- src/client/sound/snd_dma.c | 304 +--------------------------- 3 files changed, 328 insertions(+), 320 deletions(-) diff --git a/src/backends/sdl/sound.c b/src/backends/sdl/sound.c index be3f3505..d8c5230b 100644 --- a/src/backends/sdl/sound.c +++ b/src/backends/sdl/sound.c @@ -41,6 +41,9 @@ #include "../../client/header/client.h" #include "../../client/sound/header/local.h" +#define SDL_FULLVOLUME 80 +#define SDL_LOOPATTENUATE 0.003 + /* Global stuff */ int snd_inited = 0; static int dmapos = 0; @@ -48,21 +51,7 @@ static int dmasize = 0; static dma_t *dmabackend; cvar_t *s_sdldriver; -/* - * Gives information over user - * defineable variables - */ -void -SDL_SoundInfo(void) -{ - Com_Printf("%5d stereo\n", dma.channels - 1); - Com_Printf("%5d samples\n", dma.samples); - Com_Printf("%5d samplepos\n", dma.samplepos); - Com_Printf("%5d samplebits\n", dma.samplebits); - Com_Printf("%5d submission_chunk\n", dma.submission_chunk); - Com_Printf("%5d speed\n", dma.speed); - Com_Printf("%p dma buffer\n", dma.buffer); -} +/* ------------------------------------------------------------------ */ /* * Calculates when a sound @@ -91,6 +80,319 @@ SDL_DriftBeginofs(float timeofs) return timeofs ? start + timeofs * dma.speed : paintedtime; } +/* + * Spatialize a sound effect based on it's origin. + */ +void +SDL_SpatializeOrigin(vec3_t origin, float master_vol, float dist_mult, + int *left_vol, int *right_vol) +{ + vec_t dot; + vec_t dist; + vec_t lscale, rscale, scale; + vec3_t source_vec; + + if (cls.state != ca_active) + { + *left_vol = *right_vol = 255; + return; + } + + /* Calculate stereo seperation and distance attenuation */ + VectorSubtract(origin, listener_origin, source_vec); + + dist = VectorNormalize(source_vec); + dist -= SDL_FULLVOLUME; + + if (dist < 0) + { + dist = 0; /* Close enough to be at full volume */ + } + + dist *= dist_mult; + dot = DotProduct(listener_right, source_vec); + + if ((dma.channels == 1) || !dist_mult) + { + rscale = 1.0f; + lscale = 1.0f; + } + else + { + rscale = 0.5f * (1.0f + dot); + lscale = 0.5f * (1.0f - dot); + } + + /* Add in distance effect */ + scale = (1.0f - dist) * rscale; + *right_vol = (int)(master_vol * scale); + + if (*right_vol < 0) + { + *right_vol = 0; + } + + scale = (1.0 - dist) * lscale; + *left_vol = (int)(master_vol * scale); + + if (*left_vol < 0) + { + *left_vol = 0; + } +} + +/* + * Spatializes a channel. + */ +void +SDL_Spatialize(channel_t *ch) +{ + vec3_t origin; + + /* Anything coming from the view entity + will always be full volume */ + if (ch->entnum == cl.playernum + 1) + { + ch->leftvol = ch->master_vol; + ch->rightvol = ch->master_vol; + return; + } + + if (ch->fixed_origin) + { + VectorCopy(ch->origin, origin); + } + else + { + CL_GetEntitySoundOrigin(ch->entnum, origin); + } + + SDL_SpatializeOrigin(origin, (float)ch->master_vol, ch->dist_mult, + &ch->leftvol, &ch->rightvol); +} + +/* + * Entities with a "sound" field will generated looped sounds + * that are automatically started, stopped, and merged together + * as the entities are sent to the client + */ +void +SDL_AddLoopSounds(void) +{ + int i, j; + int sounds[MAX_EDICTS]; + int left, right, left_total, right_total; + channel_t *ch; + sfx_t *sfx; + sfxcache_t *sc; + int num; + entity_state_t *ent; + vec3_t origin; + + if (cl_paused->value) + { + return; + } + + if (cls.state != ca_active) + { + return; + } + + if (!cl.sound_prepped || !s_ambient->value) + { + return; + } + + memset(&sounds, 0, sizeof(int) * MAX_EDICTS); + S_BuildSoundList(sounds); + + for (i = 0; i < cl.frame.num_entities; i++) + { + if (!sounds[i]) + { + continue; + } + + sfx = cl.sound_precache[sounds[i]]; + + if (!sfx) + { + continue; /* bad sound effect */ + } + + sc = sfx->cache; + + if (!sc) + { + continue; + } + + num = (cl.frame.parse_entities + i) & (MAX_PARSE_ENTITIES - 1); + ent = &cl_parse_entities[num]; + + CL_GetEntitySoundOrigin(ent->number, origin); + + /* find the total contribution of all sounds of this type */ + SDL_SpatializeOrigin(ent->origin, 255.0f, SDL_LOOPATTENUATE, + &left_total, &right_total); + + for (j = i + 1; j < cl.frame.num_entities; j++) + { + if (sounds[j] != sounds[i]) + { + continue; + } + + sounds[j] = 0; /* don't check this again later */ + num = (cl.frame.parse_entities + j) & (MAX_PARSE_ENTITIES - 1); + ent = &cl_parse_entities[num]; + + SDL_SpatializeOrigin(ent->origin, 255.0f, SDL_LOOPATTENUATE, &left, &right); + + left_total += left; + right_total += right; + } + + if ((left_total == 0) && (right_total == 0)) + { + continue; /* not audible */ + } + + /* allocate a channel */ + ch = S_PickChannel(0, 0); + + if (!ch) + { + return; + } + + if (left_total > 255) + { + left_total = 255; + } + + if (right_total > 255) + { + right_total = 255; + } + + ch->leftvol = left_total; + ch->rightvol = right_total; + ch->autosound = true; /* remove next frame */ + ch->sfx = sfx; + + /* Sometimes, the sc->length argument can become 0, + and in that case we get a SIGFPE in the next + modulo operation. The workaround checks for this + situation and in that case, sets the pos and end + parameters to 0. */ + if (sc->length == 0) + { + ch->pos = 0; + ch->end = 0; + } + else + { + ch->pos = paintedtime % sc->length; + ch->end = paintedtime + sc->length - ch->pos; + } + } +} + +/* + * Clears the playback buffer so + * that all playback stops. + */ +void +SDL_ClearBuffer(void) +{ + int clear; + int i; + unsigned char *ptr = dma.buffer; + + if (!sound_started) + { + return; + } + + s_rawend = 0; + + if (dma.samplebits == 8) + { + clear = 0x80; + } + else + { + clear = 0; + } + + SDL_LockAudio(); + + if (dma.buffer) + { + i = dma.samples * dma.samplebits / 8; + + while (i--) + { + *ptr = clear; + ptr++; + } + } + + SDL_UnlockAudio(); +} + +/* + * Calculates the absolute timecode + * of current playback. + */ +void +SDL_UpdateSoundtime(void) +{ + static int buffers; + static int oldsamplepos; + int fullsamples; + + fullsamples = dma.samples / dma.channels; + + /* it is possible to miscount buffers if it has wrapped twice between + calls to S_Update. Oh well. This a hack around that. */ + if (dmapos < oldsamplepos) + { + buffers++; /* buffer wrapped */ + + if (paintedtime > 0x40000000) + { + /* time to chop things off to avoid 32 bit limits */ + buffers = 0; + paintedtime = fullsamples; + S_StopAllSounds(); + } + } + + oldsamplepos = dmapos; + soundtime = buffers * fullsamples + dmapos / dma.channels; +} + +/* ------------------------------------------------------------------ */ + +/* + * Gives information over user + * defineable variables + */ +void +SDL_SoundInfo(void) +{ + Com_Printf("%5d stereo\n", dma.channels - 1); + Com_Printf("%5d samples\n", dma.samples); + Com_Printf("%5d samplepos\n", dma.samplepos); + Com_Printf("%5d samplebits\n", dma.samplebits); + Com_Printf("%5d submission_chunk\n", dma.submission_chunk); + Com_Printf("%5d speed\n", dma.speed); + Com_Printf("%p dma buffer\n", dma.buffer); +} + /* * Callback funktion for SDL. Writes * sound data to SDL when requested. @@ -307,12 +609,6 @@ SDL_BackendShutdown(void) Com_Printf("SDL audio device shut down.\n"); } -int -SDL_GetPos(void) -{ - return dmapos; -} - /* * This sends the sound to the device. * In the SDL backend it's useless and diff --git a/src/client/sound/header/local.h b/src/client/sound/header/local.h index 1ff40346..815fd47c 100644 --- a/src/client/sound/header/local.h +++ b/src/client/sound/header/local.h @@ -124,6 +124,7 @@ typedef enum extern sndstarted_t sound_started; int s_beginofs; +int soundtime; /* initializes cycling through a DMA buffer and returns information on it */ @@ -139,6 +140,9 @@ void SDL_Submit(void); void SDL_SoundInfo(void); int SDL_DriftBeginofs(float); +void SDL_ClearBuffer(void); +void SDL_AddLoopSounds(void); +void SDL_UpdateSoundtime(void); #define MAX_CHANNELS 32 extern channel_t channels[MAX_CHANNELS]; @@ -175,7 +179,7 @@ void S_PaintChannels(int endtime); channel_t *S_PickChannel(int entnum, int entchannel); /* spatializes a channel */ -void S_Spatialize(channel_t *ch); +void SDL_Spatialize(channel_t *ch); void S_BuildSoundList(int *sounds); diff --git a/src/client/sound/snd_dma.c b/src/client/sound/snd_dma.c index fad273de..2ba35a81 100644 --- a/src/client/sound/snd_dma.c +++ b/src/client/sound/snd_dma.c @@ -55,8 +55,6 @@ vec3_t listener_right; vec3_t listener_up; static qboolean s_registering; - -static int soundtime; int paintedtime; /* during registration it is possible to have more sounds @@ -505,95 +503,6 @@ S_PickChannel(int entnum, int entchannel) return ch; } -/* - * Used for spatializing channels and autosounds - */ -void -S_SpatializeOrigin(vec3_t origin, float master_vol, float dist_mult, - int *left_vol, int *right_vol) -{ - vec_t dot; - vec_t dist; - vec_t lscale, rscale, scale; - vec3_t source_vec; - - if (cls.state != ca_active) - { - *left_vol = *right_vol = 255; - return; - } - - /* calculate stereo seperation and distance attenuation */ - VectorSubtract(origin, listener_origin, source_vec); - - dist = VectorNormalize(source_vec); - dist -= SOUND_FULLVOLUME; - - if (dist < 0) - { - dist = 0; /* close enough to be at full volume */ - } - - dist *= dist_mult; /* different attenuation levels */ - - dot = DotProduct(listener_right, source_vec); - - if ((dma.channels == 1) || !dist_mult) - { - /* no attenuation = no spatialization */ - rscale = 1.0f; - lscale = 1.0f; - } - else - { - rscale = 0.5f * (1.0f + dot); - lscale = 0.5f * (1.0f - dot); - } - - /* add in distance effect */ - scale = (1.0f - dist) * rscale; - *right_vol = (int)(master_vol * scale); - - if (*right_vol < 0) - { - *right_vol = 0; - } - - scale = (1.0 - dist) * lscale; - *left_vol = (int)(master_vol * scale); - - if (*left_vol < 0) - { - *left_vol = 0; - } -} - -void -S_Spatialize(channel_t *ch) -{ - vec3_t origin; - - /* anything coming from the view entity will always be full volume */ - if (ch->entnum == cl.playernum + 1) - { - ch->leftvol = ch->master_vol; - ch->rightvol = ch->master_vol; - return; - } - - if (ch->fixed_origin) - { - VectorCopy(ch->origin, origin); - } - else - { - CL_GetEntitySoundOrigin(ch->entnum, origin); - } - - S_SpatializeOrigin(origin, (float)ch->master_vol, ch->dist_mult, - &ch->leftvol, &ch->rightvol); -} - playsound_t * S_AllocPlaysound(void) { @@ -693,7 +602,7 @@ S_IssuePlaysound(playsound_t *ps) #endif { ch->master_vol = (int)ps->volume; - S_Spatialize(ch); + SDL_Spatialize(ch); } ch->pos = 0; @@ -879,46 +788,6 @@ S_StartLocalSound(char *sound) S_StartSound(NULL, cl.playernum + 1, 0, sfx, 1, 1, 0); } -void -S_ClearBuffer(void) -{ - int clear; - - if (!sound_started) - { - return; - } - - s_rawend = 0; - - if (dma.samplebits == 8) - { - clear = 0x80; - } - else - { - clear = 0; - } - - SDL_BeginPainting(); - - if (dma.buffer) - { - int i; - unsigned char *ptr = dma.buffer; - - i = dma.samples * dma.samplebits / 8; - - while (i--) - { - *ptr = clear; - ptr++; - } - } - - SDL_Submit(); -} - void S_StopAllSounds(void) { @@ -950,7 +819,7 @@ S_StopAllSounds(void) else #endif { - S_ClearBuffer(); + SDL_ClearBuffer(); } /* clear all the channels */ @@ -989,136 +858,6 @@ S_BuildSoundList(int *sounds) } } -/* - * Entities with a ->sound field will generated looped sounds - * that are automatically started, stopped, and merged together - * as the entities are sent to the client - */ -void -S_AddLoopSounds(void) -{ - int i, j; - int sounds[MAX_EDICTS]; - int left, right, left_total, right_total; - channel_t *ch; - sfx_t *sfx; - sfxcache_t *sc; - int num; - entity_state_t *ent; - vec3_t origin; - - if (cl_paused->value) - { - return; - } - - if (cls.state != ca_active) - { - return; - } - - if (!cl.sound_prepped || !s_ambient->value) - { - return; - } - - memset(&sounds, 0, sizeof(int) * MAX_EDICTS); - S_BuildSoundList(sounds); - - for (i = 0; i < cl.frame.num_entities; i++) - { - if (!sounds[i]) - { - continue; - } - - sfx = cl.sound_precache[sounds[i]]; - - if (!sfx) - { - continue; /* bad sound effect */ - } - - sc = sfx->cache; - - if (!sc) - { - continue; - } - - num = (cl.frame.parse_entities + i) & (MAX_PARSE_ENTITIES - 1); - ent = &cl_parse_entities[num]; - - CL_GetEntitySoundOrigin(ent->number, origin); - - /* find the total contribution of all sounds of this type */ - S_SpatializeOrigin(ent->origin, 255.0f, SOUND_LOOPATTENUATE, - &left_total, &right_total); - - for (j = i + 1; j < cl.frame.num_entities; j++) - { - if (sounds[j] != sounds[i]) - { - continue; - } - - sounds[j] = 0; /* don't check this again later */ - - num = (cl.frame.parse_entities + j) & (MAX_PARSE_ENTITIES - 1); - ent = &cl_parse_entities[num]; - - S_SpatializeOrigin(ent->origin, 255.0f, SOUND_LOOPATTENUATE, - &left, &right); - left_total += left; - right_total += right; - } - - if ((left_total == 0) && (right_total == 0)) - { - continue; /* not audible */ - } - - /* allocate a channel */ - ch = S_PickChannel(0, 0); - - if (!ch) - { - return; - } - - if (left_total > 255) - { - left_total = 255; - } - - if (right_total > 255) - { - right_total = 255; - } - - ch->leftvol = left_total; - ch->rightvol = right_total; - ch->autosound = true; /* remove next frame */ - ch->sfx = sfx; - - /* Sometimes, the sc->length argument can become 0, - and in that case we get a SIGFPE in the next - modulo operation. The workaround checks for this - situation and in that case, sets the pos and end - parameters to 0. */ - if (sc->length == 0) - { - ch->pos = 0; - ch->end = 0; - } - else - { - ch->pos = paintedtime % sc->length; - ch->end = paintedtime + sc->length - ch->pos; - } - } -} - /* * Cinematic streaming and voice over network * This could be used for chat over network, but that @@ -1231,37 +970,6 @@ S_RawSamples(int samples, int rate, int width, } } -void -GetSoundtime(void) -{ - int samplepos; - static int buffers; - static int oldsamplepos; - int fullsamples; - - fullsamples = dma.samples / dma.channels; - - /* it is possible to miscount buffers if it has wrapped twice between - calls to S_Update. Oh well. This a hack around that. */ - samplepos = SDL_GetPos(); - - if (samplepos < oldsamplepos) - { - buffers++; /* buffer wrapped */ - - if (paintedtime > 0x40000000) - { - /* time to chop things off to avoid 32 bit limits */ - buffers = 0; - paintedtime = fullsamples; - S_StopAllSounds(); - } - } - - oldsamplepos = samplepos; - soundtime = buffers * fullsamples + samplepos / dma.channels; -} - /* * Called once each time through the main loop */ @@ -1286,7 +994,7 @@ S_Update(vec3_t origin, vec3_t forward, vec3_t right, vec3_t up) { if (sound_started == SS_DMA) { - S_ClearBuffer(); + SDL_ClearBuffer(); } return; @@ -1328,7 +1036,7 @@ S_Update(vec3_t origin, vec3_t forward, vec3_t right, vec3_t up) continue; } - S_Spatialize(ch); /* respatialize channel */ + SDL_Spatialize(ch); /* respatialize channel */ if (!ch->leftvol && !ch->rightvol) { @@ -1338,7 +1046,7 @@ S_Update(vec3_t origin, vec3_t forward, vec3_t right, vec3_t up) } /* add loopsounds */ - S_AddLoopSounds(); + SDL_AddLoopSounds(); /* debugging output */ if (s_show->value) @@ -1378,7 +1086,7 @@ S_Update(vec3_t origin, vec3_t forward, vec3_t right, vec3_t up) } /* Updates DMA time */ - GetSoundtime(); + SDL_UpdateSoundtime(); if (!soundtime) {