diff --git a/include/asm_i386.h b/include/asm_i386.h index e64d4cf..5b51d26 100644 --- a/include/asm_i386.h +++ b/include/asm_i386.h @@ -89,11 +89,13 @@ #define ch_pos 16 #define ch_looping 20 #define ch_entnum 24 -#define ch_entchannel 28 +#define ch_entchannel 28 #define ch_origin 32 -#define ch_dist_mult 44 -#define ch_master_vol 48 -#define ch_size 52 +#define ch_dist_mult 44 +#define ch_master_vol 48 +#define ch_phase 52 +#define ch_oldphase 56 +#define ch_size 60 // portable_samplepair_t structure // !!! if this is changed, it much be changed in sound.h too !!! @@ -102,4 +104,3 @@ #define psp_size 8 #endif - diff --git a/include/sound.h b/include/sound.h index c30d84f..2608664 100644 --- a/include/sound.h +++ b/include/sound.h @@ -34,7 +34,7 @@ #include "cvar.h" #include "zone.h" -// !!! if this is changed, it much be changed in asm_i386.h too !!! +// !!! if this is changed, it must be changed in asm_i386.h too !!! typedef struct { int left; @@ -79,13 +79,15 @@ typedef struct int leftvol; // 0-255 volume int rightvol; // 0-255 volume int end; // end time in global paintsamples - int pos; // sample position in sfx + int pos; // sample position in sfx int looping; // where to loop, -1 = no looping int entnum; // to allow overriding a specific sound int entchannel; // vec3_t origin; // origin of sound effect vec_t dist_mult; // distance multiplier (attenuation/clipK) - int master_vol; // 0-255 master volume + int master_vol; // 0-255 master volume + int phase; // phase shift between l-r in samples + int oldphase; // phase shift between l-r in samples } channel_t; typedef struct @@ -137,7 +139,7 @@ void SNDDMA_Shutdown(void); // User-setable variables // ==================================================================== -#define MAX_CHANNELS 128 +#define MAX_CHANNELS 256 #define MAX_DYNAMIC_CHANNELS 8 extern channel_t channels[MAX_CHANNELS]; @@ -170,6 +172,7 @@ extern cvar_t *bgmvolume; extern cvar_t *volume; extern cvar_t *snd_interp; +extern cvar_t *snd_stereo_phase_separation; extern qboolean snd_initialized; diff --git a/source/snd_dma.c b/source/snd_dma.c index ae3fe2e..846ac24 100644 --- a/source/snd_dma.c +++ b/source/snd_dma.c @@ -30,13 +30,13 @@ # include "config.h" #endif -#include "host.h" -#include "sys.h" -#include "sound.h" +#include "client.h" #include "cmd.h" #include "console.h" -#include "client.h" +#include "host.h" #include "qargs.h" +#include "sys.h" +#include "sound.h" // fixme: Damn crappy complier doesn't allow me to UNDEF _win32 on command line! #ifdef WIN32SDL @@ -54,7 +54,7 @@ void S_Play (void); void S_PlayVol (void); void S_SoundList (void); -void S_Update_ (); +void S_Update_ (void); void S_StopAllSounds (qboolean clear); void S_StopAllSoundsC (void); @@ -108,6 +108,8 @@ cvar_t *ambient_fade; cvar_t *snd_noextraupdate; cvar_t *snd_show; cvar_t *snd_interp; +cvar_t *snd_phasesep; +cvar_t *snd_volumesep; cvar_t *_snd_mixahead; @@ -198,7 +200,7 @@ void S_Init (void) { -// Con_Printf("\nSound Initialization\n"); + Con_Printf("\nSound Initialization\n"); Cmd_AddCommand ("play", S_Play); Cmd_AddCommand ("playvol", S_PlayVol); @@ -206,7 +208,6 @@ S_Init (void) Cmd_AddCommand ("soundlist", S_SoundList); Cmd_AddCommand ("soundinfo", S_SoundInfo_f); - if (COM_CheckParm ("-nosound")) return; @@ -219,12 +220,11 @@ S_Init (void) } - snd_initialized = true; S_Startup (); - if (sound_started == 0) // sound startup failed? Bail out. + if (sound_started == 0) // sound startup failed? Bail out. return; SND_InitScaletable (); @@ -276,6 +276,8 @@ S_Init_Cvars (void) snd_interp = Cvar_Get ("snd_interp", "1", CVAR_ARCHIVE, "control sample interpolation"); + snd_phasesep = Cvar_Get ("snd_phasesep", "0.0", CVAR_ARCHIVE, "max stereo phase separation in ms. 0.6 is for 20cm head"); + snd_volumesep = Cvar_Get("snd_volumesep", "1.0", CVAR_ARCHIVE, "max stereo volume separation in ms. 1.0 is max"); _snd_mixahead = Cvar_Get ("_snd_mixahead", "0.1", CVAR_ARCHIVE, "None"); } @@ -406,12 +408,8 @@ SND_PickChannel (int entnum, int entchannel) ch_idx++) { if (entchannel != 0 // channel 0 never overrides && channels[ch_idx].entnum == entnum - && (channels[ch_idx].entchannel == entchannel || entchannel == -1)) { // allways - // override - // sound - // from - // same - // entity + && (channels[ch_idx].entchannel == entchannel || entchannel == -1)) { + // always override sound from same entity first_to_die = ch_idx; break; } @@ -445,6 +443,7 @@ SND_Spatialize (channel_t *ch) { vec_t dot; vec_t dist; + int phase; // in samples vec_t lscale, rscale, scale; vec3_t source_vec; sfx_t *snd; @@ -453,6 +452,7 @@ SND_Spatialize (channel_t *ch) if (ch->entnum == cl.viewentity) { ch->leftvol = ch->master_vol; ch->rightvol = ch->master_vol; + ch->phase = 0; return; } // calculate stereo seperation and distance attenuation @@ -467,9 +467,11 @@ SND_Spatialize (channel_t *ch) if (shm->channels == 1) { rscale = 1.0; lscale = 1.0; + phase = 0; } else { - rscale = 1.0 + dot; - lscale = 1.0 - dot; + rscale = 1.0 + dot * snd_volumesep->value; + lscale = 1.0 - dot * snd_volumesep->value; + phase = snd_phasesep->value * 0.001 * shm->speed * dot; } // add in distance effect @@ -482,6 +484,8 @@ SND_Spatialize (channel_t *ch) ch->leftvol = (int) (ch->master_vol * scale); if (ch->leftvol < 0) ch->leftvol = 0; + + ch->phase = phase; } @@ -690,6 +694,7 @@ S_StaticSound (sfx_t *sfx, vec3_t origin, float vol, float attenuation) ss->end = paintedtime + sc->length; SND_Spatialize (ss); + ss->oldphase = ss->phase; } @@ -780,6 +785,7 @@ S_Update (vec3_t origin, vec3_t forward, vec3_t right, vec3_t up) for (i = NUM_AMBIENTS; i < total_channels; i++, ch++) { if (!ch->sfx) continue; + ch->oldphase = ch->phase; // prepare to lerp from prev to next phase SND_Spatialize (ch); // respatialize channel if (!ch->leftvol && !ch->rightvol) continue; diff --git a/source/snd_mix.c b/source/snd_mix.c index 1d6c607..e7090ea 100644 --- a/source/snd_mix.c +++ b/source/snd_mix.c @@ -32,8 +32,9 @@ #ifdef HAVE_STRING_H #include #endif -#include "sound.h" + #include "console.h" +#include "sound.h" // fixme: Damn crappy complier doesn't allow me to UNDEF _win32 on command line! #ifdef WIN32SDL @@ -47,7 +48,8 @@ #endif #define PAINTBUFFER_SIZE 512 -portable_samplepair_t paintbuffer[PAINTBUFFER_SIZE]; +portable_samplepair_t paintbuffer[PAINTBUFFER_SIZE * 2]; +int max_overpaint; // number of extra samples painted due to phase shift int snd_scaletable[32][256]; int *snd_p, snd_linear_count, snd_vol; short *snd_out; @@ -289,9 +291,9 @@ S_PaintChannels (int endtime) end = paintedtime + PAINTBUFFER_SIZE; // clear the paint buffer - memset (paintbuffer, 0, - - (end - paintedtime) * sizeof (portable_samplepair_t)); +// memset (paintbuffer, 0, +// (end - paintedtime) * sizeof (portable_samplepair_t)); + max_overpaint = 0; // paint in the channels. ch = channels; @@ -336,6 +338,12 @@ S_PaintChannels (int endtime) // transfer out according to DMA format S_TransferPaintBuffer (end); + + memmove (paintbuffer, paintbuffer + end - paintedtime, + max_overpaint * sizeof (paintbuffer[0])); + memset (paintbuffer + max_overpaint, 0, sizeof (paintbuffer) + - max_overpaint * sizeof (paintbuffer[0])); + paintedtime = end; } } @@ -389,19 +397,96 @@ SND_PaintChannelFrom16 (channel_t *ch, sfxcache_t *sc, int count) int left, right; int leftvol, rightvol; signed short *sfx; - int i; + unsigned int i = 0; + unsigned int left_phase, right_phase; // Never allowed < 0 anyway leftvol = ch->leftvol; rightvol = ch->rightvol; + + max_overpaint = max (abs (ch->phase), + max (abs (ch->oldphase), max_overpaint)); + sfx = (signed short *) sc->data + ch->pos; + ch->pos += count; + + if (ch->phase >= 0) { + left_phase = ch->phase; + right_phase = 0; + } else { + left_phase = 0; + right_phase = -ch->phase; + } + + if (ch->oldphase != ch->phase) { + unsigned int old_phase_left, old_phase_right; + unsigned int new_phase_left, new_phase_right; + unsigned int count_left, count_right, c; + + if (ch->oldphase >= 0) { + old_phase_left = ch->oldphase; + old_phase_right = 0; + } else { + old_phase_left = 0; + old_phase_right = -ch->oldphase; + } + new_phase_left = left_phase; + new_phase_right = right_phase; + + if (new_phase_left > old_phase_left) + count_left = 2 * (new_phase_left - old_phase_left); + else + count_left = old_phase_left - new_phase_left; + + if (new_phase_right > old_phase_right) + count_right = 2 * (new_phase_right - old_phase_right); + else + count_right = old_phase_right - new_phase_right; + + c = min (count, max (count_right, count_left)); + count -= c; + while (c) { + int data = sfx[i]; + int left = (data * leftvol) >> 8; + int right = (data * rightvol) >> 8; + + if (new_phase_left < old_phase_left) { + if (!(count_left & 1)) { + paintbuffer[i + old_phase_left].left += left; + old_phase_left--; + } + count_left--; + } else if (new_phase_left > old_phase_left) { + paintbuffer[i + old_phase_left].left += left; + old_phase_left++; + paintbuffer[i + old_phase_left].left += left; + } else { + paintbuffer[i + old_phase_left].left += left; + } + + if (new_phase_right < old_phase_right) { + if (!(count_right & 1)) { + paintbuffer[i + old_phase_right].right += right; + old_phase_right--; + } + count_right--; + } else if (new_phase_right > old_phase_right) { + paintbuffer[i + old_phase_right].right += right; + old_phase_right++; + paintbuffer[i + old_phase_right].right += right; + } else { + paintbuffer[i + old_phase_right].right += right; + } + + c--; + i++; + } + } for (i = 0; i < count; i++) { data = sfx[i]; left = (data * leftvol) >> 8; right = (data * rightvol) >> 8; - paintbuffer[i].left += left; - paintbuffer[i].right += right; + paintbuffer[i + left_phase].left += left; + paintbuffer[i + right_phase].right += right; } - - ch->pos += count; }