X-Git-Url: http://git.xonotic.org/?a=blobdiff_plain;f=snd_main.c;h=4030d3878dcd94a36aee7c4ce853f48ad3f7b67d;hb=0bb405b5672b23600a696e546900eeaabe4935b6;hp=019c59be499c6531d7f5a931b6a6b453eaba1747;hpb=63194da5789fa949671e4a3cb7309ea0b6b15b68;p=xonotic%2Fdarkplaces.git diff --git a/snd_main.c b/snd_main.c index 019c59be..4030d387 100644 --- a/snd_main.c +++ b/snd_main.c @@ -24,6 +24,26 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. #include "snd_main.h" #include "snd_ogg.h" +#if SND_LISTENERS != 8 +#error this data only supports up to 8 channel, update it! +#endif +typedef struct listener_s +{ + float yawangle; + float dotscale; + float dotbias; + float ambientvolume; +} +listener_t; +typedef struct speakerlayout_s +{ + const char *name; + unsigned int channels; + listener_t listeners[SND_LISTENERS]; +} +speakerlayout_t; + +static speakerlayout_t snd_speakerlayout; void S_Play(void); void S_PlayVol(void); @@ -31,8 +51,6 @@ void S_Play2(void); void S_SoundList(void); void S_Update_(); -void S_ClearBuffer (void); - // ======================================================================= // Internal sound data & structures @@ -42,14 +60,14 @@ channel_t channels[MAX_CHANNELS]; unsigned int total_channels; int snd_blocked = 0; -cvar_t snd_initialized = { CVAR_READONLY, "snd_initialized", "0"}; -cvar_t snd_streaming = { CVAR_SAVE, "snd_streaming", "1"}; +cvar_t snd_initialized = { CVAR_READONLY, "snd_initialized", "0", "indicates the sound subsystem is active"}; +cvar_t snd_streaming = { CVAR_SAVE, "snd_streaming", "1", "enables keeping compressed ogg sound files compressed, decompressing them only as needed, otherwise they will be decompressed completely at load (may use a lot of memory)"}; volatile dma_t *shm = 0; volatile dma_t sn; vec3_t listener_origin; -matrix4x4_t listener_matrix; +matrix4x4_t listener_matrix[SND_LISTENERS]; vec_t sound_nominal_clip_dist=1000.0; mempool_t *snd_mempool; @@ -59,26 +77,25 @@ int paintedtime; // Linked list of known sfx sfx_t *known_sfx = NULL; -qboolean sound_started = false; qboolean sound_spatialized = false; // Fake dma is a synchronous faking of the DMA progress used for // isolating performance in the renderer. qboolean fakedma = false; -cvar_t bgmvolume = {CVAR_SAVE, "bgmvolume", "1"}; -cvar_t volume = {CVAR_SAVE, "volume", "0.7"}; -cvar_t snd_staticvolume = {CVAR_SAVE, "snd_staticvolume", "1"}; +cvar_t bgmvolume = {CVAR_SAVE, "bgmvolume", "1", "volume of background music (such as CD music or replacement files such as sound/cdtracks/track002.ogg)"}; +cvar_t volume = {CVAR_SAVE, "volume", "0.7", "volume of sound effects"}; +cvar_t snd_staticvolume = {CVAR_SAVE, "snd_staticvolume", "1", "volume of ambient sound effects (such as swampy sounds at the start of e1m2)"}; -cvar_t nosound = {0, "nosound", "0"}; -cvar_t snd_precache = {0, "snd_precache", "1"}; -cvar_t bgmbuffer = {0, "bgmbuffer", "4096"}; -cvar_t ambient_level = {0, "ambient_level", "0.3"}; -cvar_t ambient_fade = {0, "ambient_fade", "100"}; -cvar_t snd_noextraupdate = {0, "snd_noextraupdate", "0"}; -cvar_t snd_show = {0, "snd_show", "0"}; -cvar_t _snd_mixahead = {CVAR_SAVE, "_snd_mixahead", "0.1"}; -cvar_t snd_swapstereo = {CVAR_SAVE, "snd_swapstereo", "0"}; +cvar_t nosound = {0, "nosound", "0", "disables sound"}; +cvar_t snd_precache = {0, "snd_precache", "1", "loads sounds before they are used"}; +//cvar_t bgmbuffer = {0, "bgmbuffer", "4096", "unused quake cvar"}; +cvar_t ambient_level = {0, "ambient_level", "0.3", "volume of environment noises (water and wind)"}; +cvar_t ambient_fade = {0, "ambient_fade", "100", "rate of volume fading when moving from one environment to another"}; +cvar_t snd_noextraupdate = {0, "snd_noextraupdate", "0", "disables extra sound mixer calls that are meant to reduce the chance of sound breakup at very low framerates"}; +cvar_t snd_show = {0, "snd_show", "0", "shows some statistics about sound mixing"}; +cvar_t _snd_mixahead = {CVAR_SAVE, "_snd_mixahead", "0.1", "how much sound to mix ahead of time"}; +cvar_t snd_swapstereo = {CVAR_SAVE, "snd_swapstereo", "0", "swaps left/right speakers for old ISA soundblaster cards"}; // Ambient sounds sfx_t* ambient_sfxs [2] = { NULL, NULL }; @@ -94,13 +111,14 @@ void S_FreeSfx (sfx_t *sfx, qboolean force); void S_SoundInfo_f(void) { - if (!sound_started) + if (!shm) { Con_Print("sound system not started\n"); return; } - Con_Printf("%5d stereo\n", shm->format.channels - 1); + Con_Printf("%5d speakers\n", shm->format.channels); + Con_Printf("%5d frames\n", shm->sampleframes); Con_Printf("%5d samples\n", shm->samples); Con_Printf("%5d samplepos\n", shm->samplepos); Con_Printf("%5d samplebits\n", shm->format.width * 8); @@ -124,9 +142,10 @@ void S_Startup(void) shm->format.width = 2; shm->format.speed = 22050; shm->format.channels = 2; - shm->samples = 32768; + shm->sampleframes = 16384; + shm->samples = shm->sampleframes * shm->format.channels; shm->samplepos = 0; - shm->buffer = Mem_Alloc(snd_mempool, shm->format.channels * shm->samples * shm->format.width); + shm->buffer = (unsigned char *)Mem_Alloc(snd_mempool, shm->samples * shm->format.width); } else { @@ -134,22 +153,18 @@ void S_Startup(void) { Con_Print("S_Startup: SNDDMA_Init failed.\n"); shm = NULL; - sound_started = false; sound_spatialized = false; return; } } - sound_started = true; - - Con_DPrintf("Sound sampling rate: %i\n", shm->format.speed); - - S_StopAllSounds (); + Con_Printf("Sound format: %dHz, %d bit, %d channels\n", shm->format.speed, + shm->format.width * 8, shm->format.channels); } void S_Shutdown(void) { - if (!sound_started) + if (!shm) return; if (fakedma) @@ -158,7 +173,6 @@ void S_Shutdown(void) SNDDMA_Shutdown(); shm = NULL; - sound_started = false; sound_spatialized = false; } @@ -191,19 +205,19 @@ void S_Init(void) if (COM_CheckParm("-simsound")) fakedma = true; - Cmd_AddCommand("play", S_Play); - Cmd_AddCommand("play2", S_Play2); - Cmd_AddCommand("playvol", S_PlayVol); - Cmd_AddCommand("stopsound", S_StopAllSounds); - Cmd_AddCommand("soundlist", S_SoundList); - Cmd_AddCommand("soundinfo", S_SoundInfo_f); - Cmd_AddCommand("snd_restart", S_Restart_f); + Cmd_AddCommand("play", S_Play, "play a sound at your current location (not heard by anyone else)"); + Cmd_AddCommand("play2", S_Play2, "play a sound globally throughout the level (not heard by anyone else)"); + Cmd_AddCommand("playvol", S_PlayVol, "play a sound at the specified volume level at your current location (not heard by anyone else)"); + Cmd_AddCommand("stopsound", S_StopAllSounds, "silence"); + Cmd_AddCommand("soundlist", S_SoundList, "list loaded sounds"); + Cmd_AddCommand("soundinfo", S_SoundInfo_f, "print sound system information (such as channels and speed)"); + Cmd_AddCommand("snd_restart", S_Restart_f, "restart sound system"); Cvar_RegisterVariable(&nosound); Cvar_RegisterVariable(&snd_precache); Cvar_RegisterVariable(&snd_initialized); Cvar_RegisterVariable(&snd_streaming); - Cvar_RegisterVariable(&bgmbuffer); + //Cvar_RegisterVariable(&bgmbuffer); Cvar_RegisterVariable(&ambient_level); Cvar_RegisterVariable(&ambient_fade); Cvar_RegisterVariable(&snd_noextraupdate); @@ -260,9 +274,11 @@ sfx_t *S_FindName (const char *name) if (!snd_initialized.integer) return NULL; - // Add the default sound directory to the path if (strlen (name) >= sizeof (sfx->name)) - Host_Error ("S_FindName: sound name too long (%s)", name); + { + Con_Printf ("S_FindName: sound name too long (%s)\n", name); + return NULL; + } // Look for this sound in the list of known sfx for (sfx = known_sfx; sfx != NULL; sfx = sfx->next) @@ -270,9 +286,10 @@ sfx_t *S_FindName (const char *name) return sfx; // Add a sfx_t struct for this sound - sfx = Mem_Alloc (snd_mempool, sizeof (*sfx)); + sfx = (sfx_t *)Mem_Alloc (snd_mempool, sizeof (*sfx)); memset (sfx, 0, sizeof(*sfx)); strlcpy (sfx->name, name, sizeof (sfx->name)); + sfx->memsize = sizeof(*sfx); sfx->next = known_sfx; known_sfx = sfx; @@ -288,6 +305,8 @@ S_FreeSfx */ void S_FreeSfx (sfx_t *sfx, qboolean force) { + unsigned int i; + // Never free a locked sfx unless forced if (!force && (sfx->locks > 0 || (sfx->flags & SFXFLAG_PERMANENTLOCK))) return; @@ -308,11 +327,20 @@ void S_FreeSfx (sfx_t *sfx, qboolean force) break; } if (prev_sfx == NULL) - Sys_Error ("S_FreeSfx: Can't find SFX %s in the list!\n", sfx->name); + { + Con_Printf ("S_FreeSfx: Can't find SFX %s in the list!\n", sfx->name); + return; + } } + // Stop all channels using this sfx + for (i = 0; i < total_channels; i++) + if (channels[i].sfx == sfx) + S_StopChannel (i); + // Free it - Mem_FreePool (&sfx->mempool); + if (sfx->fetcher != NULL && sfx->fetcher->free != NULL) + sfx->fetcher->free (sfx); Mem_Free (sfx); } @@ -326,6 +354,7 @@ S_ServerSounds void S_ServerSounds (char serversound [][MAX_QPATH], unsigned int numsounds) { sfx_t *sfx; + sfx_t *sfxnext; unsigned int i; // Start the ambient sounds and make them loop @@ -366,16 +395,10 @@ void S_ServerSounds (char serversound [][MAX_QPATH], unsigned int numsounds) } // Free all unlocked sfx - sfx = known_sfx; - while (sfx != NULL) + for (sfx = known_sfx;sfx;sfx = sfxnext) { - sfx_t* crtsfx; - - // We may lose the "next" pointer after S_FreeSfx - crtsfx = sfx; - sfx = sfx->next; - - S_FreeSfx (crtsfx, false); + sfxnext = sfx->next; + S_FreeSfx (sfx, false); } } @@ -453,22 +476,36 @@ channel_t *SND_PickChannel(int entnum, int entchannel) for (ch_idx=NUM_AMBIENTS ; ch_idx < NUM_AMBIENTS + MAX_DYNAMIC_CHANNELS ; ch_idx++) { ch = &channels[ch_idx]; - if (entchannel != 0 // channel 0 never overrides - && ch->entnum == entnum - && (ch->entchannel == entchannel || entchannel == -1) ) - { // always override sound from same entity - first_to_die = ch_idx; - break; + if (entchannel != 0) + { + // try to override an existing channel + if (ch->entnum == entnum && (ch->entchannel == entchannel || entchannel == -1) ) + { + // always override sound from same entity + first_to_die = ch_idx; + break; + } + } + else + { + if (!ch->sfx) + { + // no sound on this channel + first_to_die = ch_idx; + break; + } } - // don't let monster sounds override player sounds - if (ch->entnum == cl.viewentity && entnum != cl.viewentity && ch->sfx) - continue; + if (ch->sfx) + { + // don't let monster sounds override player sounds + if (ch->entnum == cl.viewentity && entnum != cl.viewentity) + continue; - // don't override looped sounds - if ((ch->flags & CHANNELFLAG_FORCELOOP) != 0 || - (ch->sfx != NULL && ch->sfx->loopstart >= 0)) - continue; + // don't override looped sounds + if ((ch->flags & CHANNELFLAG_FORCELOOP) || ch->sfx->loopstart >= 0) + continue; + } if (ch->end - paintedtime < life_left) { @@ -494,49 +531,54 @@ Spatializes a channel */ void SND_Spatialize(channel_t *ch, qboolean isstatic) { - vec_t dist, scale, pan; + int i; + vec_t dist, mastervol, intensity, vol; vec3_t source_vec; + // update sound origin if we know about the entity + if (ch->entnum > 0 && cls.state == ca_connected && cl_entities[ch->entnum].state_current.active) + { + //Con_Printf("-- entnum %i origin %f %f %f neworigin %f %f %f\n", ch->entnum, ch->origin[0], ch->origin[1], ch->origin[2], cl_entities[ch->entnum].state_current.origin[0], cl_entities[ch->entnum].state_current.origin[1], cl_entities[ch->entnum].state_current.origin[2]); + VectorCopy(cl_entities[ch->entnum].state_current.origin, ch->origin); + if (cl_entities[ch->entnum].state_current.modelindex && cl.model_precache[cl_entities[ch->entnum].state_current.modelindex] && cl.model_precache[cl_entities[ch->entnum].state_current.modelindex]->soundfromcenter) + VectorMAMAM(1.0f, ch->origin, 0.5f, cl.model_precache[cl_entities[ch->entnum].state_current.modelindex]->normalmins, 0.5f, cl.model_precache[cl_entities[ch->entnum].state_current.modelindex]->normalmaxs, ch->origin); + } + + mastervol = ch->master_vol; + // Adjust volume of static sounds + if (isstatic) + mastervol *= snd_staticvolume.value; + // anything coming from the view entity will always be full volume // LordHavoc: make sounds with ATTN_NONE have no spatialization if (ch->entnum == cl.viewentity || ch->dist_mult == 0) { - ch->leftvol = ch->master_vol; - ch->rightvol = ch->master_vol; + for (i = 0;i < SND_LISTENERS;i++) + { + vol = mastervol * snd_speakerlayout.listeners[i].ambientvolume; + ch->listener_volume[i] = bound(0, vol, 255); + } } else { - // update sound origin if we know about the entity - if (ch->entnum > 0 && cls.state == ca_connected && cl_entities[ch->entnum].state_current.active) + // calculate stereo seperation and distance attenuation + VectorSubtract(listener_origin, ch->origin, source_vec); + dist = VectorLength(source_vec); + intensity = mastervol * (1.0 - dist * ch->dist_mult); + if (intensity > 0) { - //Con_Printf("-- entnum %i origin %f %f %f neworigin %f %f %f\n", ch->entnum, ch->origin[0], ch->origin[1], ch->origin[2], cl_entities[ch->entnum].state_current.origin[0], cl_entities[ch->entnum].state_current.origin[1], cl_entities[ch->entnum].state_current.origin[2]); - VectorCopy(cl_entities[ch->entnum].state_current.origin, ch->origin); - if (cl_entities[ch->entnum].state_current.modelindex && cl.model_precache[cl_entities[ch->entnum].state_current.modelindex] && cl.model_precache[cl_entities[ch->entnum].state_current.modelindex]->soundfromcenter) - VectorMAMAM(1.0f, ch->origin, 0.5f, cl.model_precache[cl_entities[ch->entnum].state_current.modelindex]->normalmins, 0.5f, cl.model_precache[cl_entities[ch->entnum].state_current.modelindex]->normalmaxs, ch->origin); + for (i = 0;i < SND_LISTENERS;i++) + { + Matrix4x4_Transform(&listener_matrix[i], ch->origin, source_vec); + VectorNormalize(source_vec); + vol = intensity * max(0, source_vec[0] * snd_speakerlayout.listeners[i].dotscale + snd_speakerlayout.listeners[i].dotbias); + ch->listener_volume[i] = bound(0, vol, 255); + } } - - // calculate stereo seperation and distance attenuation - Matrix4x4_Transform(&listener_matrix, ch->origin, source_vec); - dist = VectorNormalizeLength(source_vec); - // distance - scale = ch->master_vol * (1.0 - (dist * ch->dist_mult)); - // panning - pan = scale * source_vec[1]; - // calculate the volumes - ch->leftvol = (int) (scale + pan); - ch->rightvol = (int) (scale - pan); - } - - // Adjust volume of static sounds - if (isstatic) - { - ch->leftvol *= snd_staticvolume.value; - ch->rightvol *= snd_staticvolume.value; + else + for (i = 0;i < SND_LISTENERS;i++) + ch->listener_volume[i] = 0; } - - // clamp volumes - ch->leftvol = bound(0, ch->leftvol, 255); - ch->rightvol = bound(0, ch->rightvol, 255); } @@ -574,9 +616,9 @@ int S_StartSound (int entnum, int entchannel, sfx_t *sfx, vec3_t origin, float f { channel_t *target_chan, *check; int ch_idx; - size_t skip; + int skip; - if (!sound_started || !sfx || nosound.integer) + if (!shm || !sfx || nosound.integer) return -1; if (!sfx->fetcher) { @@ -584,6 +626,9 @@ int S_StartSound (int entnum, int entchannel, sfx_t *sfx, vec3_t origin, float f return -1; } + if (entnum && entnum >= cl_max_entities) + CL_ExpandEntities(entnum); + // Pick a channel to play on target_chan = SND_PickChannel(entnum, entchannel); if (!target_chan) @@ -605,8 +650,8 @@ int S_StartSound (int entnum, int entchannel, sfx_t *sfx, vec3_t origin, float f if (check->sfx == sfx && !check->pos) { skip = 0.1 * sfx->format.speed; - if (skip > sfx->total_length) - skip = sfx->total_length; + if (skip > (int)sfx->total_length) + skip = (int)sfx->total_length; if (skip > 0) skip = rand() % skip; target_chan->pos += skip; @@ -632,9 +677,9 @@ void S_StopChannel (unsigned int channel_ind) if (sfx->fetcher != NULL) { - snd_fetcher_end_t fetcher_end = sfx->fetcher->end; - if (fetcher_end != NULL) - fetcher_end (ch); + snd_fetcher_endsb_t fetcher_endsb = sfx->fetcher->endsb; + if (fetcher_endsb != NULL) + fetcher_endsb (ch); } // Remove the lock it holds @@ -681,7 +726,7 @@ void S_StopAllSounds (void) unsigned int i; unsigned char *pbuf; - if (!sound_started) + if (!shm) return; for (i = 0; i < total_channels; i++) @@ -691,7 +736,7 @@ void S_StopAllSounds (void) memset(channels, 0, MAX_CHANNELS * sizeof(channel_t)); // Clear sound buffer - pbuf = S_LockBuffer(); + pbuf = (unsigned char *)S_LockBuffer(); if (pbuf != NULL) { int setsize = shm->samples * shm->format.width; @@ -738,7 +783,7 @@ void S_StaticSound (sfx_t *sfx, vec3_t origin, float fvol, float attenuation) { channel_t *target_chan; - if (!sound_started || !sfx || nosound.integer) + if (!shm || !sfx || nosound.integer) return; if (!sfx->fetcher) { @@ -769,15 +814,15 @@ S_UpdateAmbientSounds */ void S_UpdateAmbientSounds (void) { + int i; float vol; int ambient_channel; channel_t *chan; - qbyte ambientlevels[NUM_AMBIENTS]; - - if (ambient_level.value <= 0 || !cl.worldmodel || !cl.worldmodel->brush.AmbientSoundLevelsForPoint) - return; + unsigned char ambientlevels[NUM_AMBIENTS]; - cl.worldmodel->brush.AmbientSoundLevelsForPoint(cl.worldmodel, listener_origin, ambientlevels, sizeof(ambientlevels)); + memset(ambientlevels, 0, sizeof(ambientlevels)); + if (cl.worldmodel && cl.worldmodel->brush.AmbientSoundLevelsForPoint) + cl.worldmodel->brush.AmbientSoundLevelsForPoint(cl.worldmodel, listener_origin, ambientlevels, sizeof(ambientlevels)); // Calc ambient sound levels for (ambient_channel = 0 ; ambient_channel< NUM_AMBIENTS ; ambient_channel++) @@ -786,7 +831,7 @@ void S_UpdateAmbientSounds (void) if (chan->sfx == NULL || chan->sfx->fetcher == NULL) continue; - vol = ambient_level.value * ambientlevels[ambient_channel]; + vol = ambientlevels[ambient_channel]; if (vol < 8) vol = 0; @@ -804,10 +849,84 @@ void S_UpdateAmbientSounds (void) chan->master_vol = vol; } - chan->leftvol = chan->rightvol = chan->master_vol; + for (i = 0;i < SND_LISTENERS;i++) + chan->listener_volume[i] = (int)(chan->master_vol * ambient_level.value * snd_speakerlayout.listeners[i].ambientvolume); } } +#define SND_SPEAKERLAYOUTS 5 +static speakerlayout_t snd_speakerlayouts[SND_SPEAKERLAYOUTS] = +{ + { + "surround71", 8, + { + {45, 0.2, 0.2, 0.5}, // front left + {315, 0.2, 0.2, 0.5}, // front right + {135, 0.2, 0.2, 0.5}, // rear left + {225, 0.2, 0.2, 0.5}, // rear right + {0, 0.2, 0.2, 0.5}, // front center + {0, 0, 0, 0}, // lfe (we don't have any good lfe sound sources and it would take some filtering work to generate them (and they'd probably still be wrong), so... no lfe) + {90, 0.2, 0.2, 0.5}, // side left + {180, 0.2, 0.2, 0.5}, // side right + } + }, + { + "surround51", 6, + { + {45, 0.2, 0.2, 0.5}, // front left + {315, 0.2, 0.2, 0.5}, // front right + {135, 0.2, 0.2, 0.5}, // rear left + {225, 0.2, 0.2, 0.5}, // rear right + {0, 0.2, 0.2, 0.5}, // front center + {0, 0, 0, 0}, // lfe (we don't have any good lfe sound sources and it would take some filtering work to generate them (and they'd probably still be wrong), so... no lfe) + {0, 0, 0, 0}, + {0, 0, 0, 0}, + } + }, + { + // these systems sometimes have a subwoofer as well, but it has no + // channel of its own + "surround40", 4, + { + {45, 0.3, 0.3, 0.8}, // front left + {315, 0.3, 0.3, 0.8}, // front right + {135, 0.3, 0.3, 0.8}, // rear left + {225, 0.3, 0.3, 0.8}, // rear right + {0, 0, 0, 0}, + {0, 0, 0, 0}, + {0, 0, 0, 0}, + {0, 0, 0, 0}, + } + }, + { + // these systems sometimes have a subwoofer as well, but it has no + // channel of its own + "stereo", 2, + { + {90, 0.5, 0.5, 1}, // side left + {270, 0.5, 0.5, 1}, // side right + {0, 0, 0, 0}, + {0, 0, 0, 0}, + {0, 0, 0, 0}, + {0, 0, 0, 0}, + {0, 0, 0, 0}, + {0, 0, 0, 0}, + } + }, + { + "mono", 1, + { + {0, 0, 1, 1}, // center + {0, 0, 0, 0}, + {0, 0, 0, 0}, + {0, 0, 0, 0}, + {0, 0, 0, 0}, + {0, 0, 0, 0}, + {0, 0, 0, 0}, + {0, 0, 0, 0}, + } + } +}; /* ============ @@ -820,13 +939,37 @@ void S_Update(const matrix4x4_t *listenermatrix) { unsigned int i, j, total; channel_t *ch, *combine; + matrix4x4_t basematrix, rotatematrix; - if (!snd_initialized.integer || (snd_blocked > 0)) + if (!snd_initialized.integer || (snd_blocked > 0) || !shm) return; - Matrix4x4_Invert_Simple(&listener_matrix, listenermatrix); + Matrix4x4_Invert_Simple(&basematrix, listenermatrix); Matrix4x4_OriginFromMatrix(listenermatrix, listener_origin); + // select speaker layout + for (i = 0;i < SND_SPEAKERLAYOUTS - 1;i++) + if (snd_speakerlayouts[i].channels == shm->format.channels) + break; + snd_speakerlayout = snd_speakerlayouts[i]; + + // calculate the current matrices + for (j = 0;j < SND_LISTENERS;j++) + { + Matrix4x4_CreateFromQuakeEntity(&rotatematrix, 0, 0, 0, 0, -snd_speakerlayout.listeners[j].yawangle, 0, 1); + Matrix4x4_Concat(&listener_matrix[j], &rotatematrix, &basematrix); + // I think this should now do this: + // 1. create a rotation matrix for rotating by e.g. -90 degrees CCW + // (note: the matrix will rotate the OBJECT, not the VIEWER, so its + // angle has to be taken negative) + // 2. create a transform which first rotates and moves its argument + // into the player's view coordinates (using basematrix which is + // an inverted "absolute" listener matrix), then applies the + // rotation matrix for the ear + // Isn't Matrix4x4_CreateFromQuakeEntity a bit misleading because this + // does not actually refer to an entity? + } + // update general area ambient sound sources S_UpdateAmbientSounds (); @@ -838,39 +981,41 @@ void S_Update(const matrix4x4_t *listenermatrix) { if (!ch->sfx) continue; - SND_Spatialize(ch, i >= MAX_DYNAMIC_CHANNELS + NUM_AMBIENTS); // respatialize channel - if (!ch->leftvol && !ch->rightvol) - continue; + + // respatialize channel + SND_Spatialize(ch, i >= MAX_DYNAMIC_CHANNELS + NUM_AMBIENTS); // try to combine static sounds with a previous channel of the same // sound effect so we don't mix five torches every frame if (i > MAX_DYNAMIC_CHANNELS + NUM_AMBIENTS) { - // see if it can just use the last one - if (combine && combine->sfx == ch->sfx) - { - combine->leftvol += ch->leftvol; - combine->rightvol += ch->rightvol; - ch->leftvol = ch->rightvol = 0; - continue; - } - // search for one - combine = channels+MAX_DYNAMIC_CHANNELS + NUM_AMBIENTS; - for (j=MAX_DYNAMIC_CHANNELS + NUM_AMBIENTS ; jsfx == ch->sfx) + // no need to merge silent channels + for (j = 0;j < SND_LISTENERS;j++) + if (ch->listener_volume[j]) break; - - if (j == total_channels) + if (j == SND_LISTENERS) + continue; + // if the last combine chosen isn't suitable, find a new one + if (!(combine && combine != ch && combine->sfx == ch->sfx)) + { + // search for one combine = NULL; - else + for (j = MAX_DYNAMIC_CHANNELS + NUM_AMBIENTS;j < i;j++) + { + if (channels[j].sfx == ch->sfx) + { + combine = channels + j; + break; + } + } + } + if (combine && combine != ch && combine->sfx == ch->sfx) { - if (combine != ch) + for (j = 0;j < SND_LISTENERS;j++) { - combine->leftvol += ch->leftvol; - combine->rightvol += ch->rightvol; - ch->leftvol = ch->rightvol = 0; + combine->listener_volume[j] += ch->listener_volume[j]; + ch->listener_volume[j] = 0; } - continue; } } } @@ -883,8 +1028,16 @@ void S_Update(const matrix4x4_t *listenermatrix) total = 0; ch = channels; for (i=0 ; isfx && (ch->leftvol || ch->rightvol) ) - total++; + { + if (ch->sfx) + { + for (j = 0;j < SND_LISTENERS;j++) + if (ch->listener_volume[j]) + break; + if (j < SND_LISTENERS) + total++; + } + } Con_Printf("----(%u)----\n", total); } @@ -899,7 +1052,7 @@ void GetSoundtime(void) static int oldsamplepos; int fullsamples; - fullsamples = shm->samples / shm->format.channels; + fullsamples = shm->sampleframes; // it is possible to miscount buffers if it has wrapped twice between // calls to S_Update. Oh well. @@ -932,9 +1085,8 @@ void S_ExtraUpdate (void) void S_Update_(void) { unsigned endtime; - int samps; - if (!sound_started || (snd_blocked > 0)) + if (!shm || (snd_blocked > 0)) return; // Updates DMA time @@ -946,9 +1098,7 @@ void S_Update_(void) // mix ahead of current position endtime = soundtime + _snd_mixahead.value * shm->format.speed; - samps = shm->samples >> (shm->format.channels - 1); - if (endtime > (unsigned int)(soundtime + samps)) - endtime = soundtime + samps; + endtime = min(endtime, (unsigned int)(soundtime + shm->sampleframes)); S_PaintChannels (endtime); @@ -966,7 +1116,7 @@ console functions static void S_Play_Common(float fvol, float attenuation) { int i, ch_ind; - char name[256]; + char name[MAX_QPATH]; sfx_t *sfx; i = 1; @@ -1025,7 +1175,7 @@ void S_SoundList(void) { if (sfx->fetcher != NULL) { - size = sfx->mempool->totalsize; + size = (int)sfx->memsize; total += size; Con_Printf ("%c%c%c%c(%2db, %6s) %8i : %s\n", (sfx->loopstart >= 0) ? 'L' : ' ', @@ -1062,7 +1212,7 @@ qboolean S_LocalSound (const char *sound) // Local sounds must not be freed sfx->flags |= SFXFLAG_PERMANENTLOCK; - ch_ind = S_StartSound (cl.viewentity, 0, sfx, vec3_origin, 1, 1); + ch_ind = S_StartSound (cl.viewentity, 0, sfx, vec3_origin, 1, 0); if (ch_ind < 0) return false;