From bb245f38395dbc7fc294e797c04a87059c3ac1b7 Mon Sep 17 00:00:00 2001 From: havoc Date: Mon, 14 May 2007 09:12:25 +0000 Subject: [PATCH] removed channel_t->end and lastptime, now only pos governs playback position, this should make the playback code safer reworked S_PaintChannels to advance channel pos regardless of volume changed S_StartSound to delay sounds rather than skip them, which may be important on short sound effects git-svn-id: svn://svn.icculus.org/twilight/trunk/darkplaces@7271 d7cf8633-e32d-0410-b094-e92efae38249 --- snd_main.c | 63 +++++++++++++---------------- snd_main.h | 6 +-- snd_mix.c | 113 +++++++++++++++++------------------------------------ snd_ogg.c | 6 +-- 4 files changed, 68 insertions(+), 120 deletions(-) diff --git a/snd_main.c b/snd_main.c index 919553b7..7cb7d55e 100644 --- a/snd_main.c +++ b/snd_main.c @@ -1043,41 +1043,42 @@ channel_t *SND_PickChannel(int entnum, int entchannel) // Check for replacement sound, or find the best one to replace first_to_die = -1; first_life_left = 0x7fffffff; - for (ch_idx=NUM_AMBIENTS ; ch_idx < NUM_AMBIENTS + MAX_DYNAMIC_CHANNELS ; ch_idx++) + + // entity channels try to replace the existing sound on the channel + if (entchannel != 0) { - ch = &channels[ch_idx]; - if (entchannel != 0) + for (ch_idx=NUM_AMBIENTS ; ch_idx < NUM_AMBIENTS + MAX_DYNAMIC_CHANNELS ; ch_idx++) { - // try to override an existing channel + ch = &channels[ch_idx]; if (ch->entnum == entnum && (ch->entchannel == entchannel || entchannel == -1) ) { // always override sound from same entity - first_to_die = ch_idx; - break; + S_StopChannel (ch_idx); + return &channels[ch_idx]; } } - else + } + + // there was no channel to override, so look for the first empty one + for (ch_idx=NUM_AMBIENTS ; ch_idx < NUM_AMBIENTS + MAX_DYNAMIC_CHANNELS ; ch_idx++) + { + ch = &channels[ch_idx]; + if (!ch->sfx) { - if (!ch->sfx) - { - // no sound on this channel - first_to_die = ch_idx; - break; - } + // no sound on this channel + first_to_die = ch_idx; + break; } - if (ch->sfx) - { - // don't let monster sounds override player sounds - if (ch->entnum == cl.viewentity && entnum != cl.viewentity) - continue; + // 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) || ch->sfx->loopstart >= 0) - continue; - } + // don't override looped sounds + if ((ch->flags & CHANNELFLAG_FORCELOOP) || ch->sfx->loopstart >= 0) + continue; + life_left = ch->sfx->total_length - ch->pos; - life_left = (int)(ch->end - snd_renderbuffer->endframe); if (life_left < first_life_left) { first_life_left = life_left; @@ -1088,8 +1089,6 @@ channel_t *SND_PickChannel(int entnum, int entchannel) if (first_to_die == -1) return NULL; - S_StopChannel (first_to_die); - return &channels[first_to_die]; } @@ -1164,9 +1163,8 @@ void S_PlaySfxOnChannel (sfx_t *sfx, channel_t *target_chan, unsigned int flags, VectorCopy (origin, target_chan->origin); target_chan->master_vol = (int)(fvol * 255); target_chan->sfx = sfx; - target_chan->end = snd_renderbuffer->endframe + sfx->total_length; - target_chan->lastptime = snd_renderbuffer->endframe; target_chan->flags = flags; + target_chan->pos = 0; // start of the sound // If it's a static sound if (isstatic) @@ -1187,7 +1185,6 @@ int S_StartSound (int entnum, int entchannel, sfx_t *sfx, vec3_t origin, float f { channel_t *target_chan, *check; int ch_idx; - int skip; if (snd_renderbuffer == NULL || sfx == NULL || nosound.integer) return -1; @@ -1218,13 +1215,8 @@ int S_StartSound (int entnum, int entchannel, sfx_t *sfx, vec3_t origin, float f continue; if (check->sfx == sfx && !check->pos) { - skip = (int)(0.1 * snd_renderbuffer->format.speed); - if (skip > (int)sfx->total_length) - skip = (int)sfx->total_length; - if (skip > 0) - skip = rand() % skip; - target_chan->pos += skip; - target_chan->end -= skip; + // use negative pos offset to delay this sound effect + target_chan->pos += (int)lhrandom(0, -0.1 * snd_renderbuffer->format.speed); break; } } @@ -1256,7 +1248,6 @@ void S_StopChannel (unsigned int channel_ind) ch->sfx = NULL; } - ch->end = 0; } diff --git a/snd_main.h b/snd_main.h index aba8086c..47a580a9 100644 --- a/snd_main.h +++ b/snd_main.h @@ -72,7 +72,7 @@ struct sfx_s unsigned int flags; // cf SFXFLAG_* defines int loopstart; // in sample frames. -1 if not looped - unsigned int total_length; // in sample frames + int total_length; // in sample frames const snd_fetcher_t *fetcher; void *fetcher_data; // Per-sfx data for the sound fetching functions }; @@ -86,9 +86,7 @@ typedef struct channel_s int master_vol; // 0-255 master volume sfx_t *sfx; // sfx number unsigned int flags; // cf CHANNELFLAG_* defines - unsigned int end; // end time in global paintsamples - unsigned int lastptime; // last time this channel was painted - unsigned int pos; // sample position in sfx + int pos; // sample position in sfx, negative values delay the start of the sound playback int entnum; // to allow overriding a specific sound int entchannel; vec3_t origin; // origin of sound effect diff --git a/snd_mix.c b/snd_mix.c index dc2a1474..43be3651 100644 --- a/snd_mix.c +++ b/snd_mix.c @@ -234,8 +234,20 @@ static qboolean SND_PaintChannel (channel_t *ch, unsigned int count) else snd_vol = (int)(volume.value * 256); + // calculate mixing volumes based on channel volumes and volume cvar + // also limit the volumes to values that won't clip for (i = 0;i < SND_LISTENERS;i++) + { vol[i] = ch->listener_volume[i] * snd_vol; + vol[i] = bound(0, vol[i], 65536); + } + + // if volumes are all zero, just return + for (i = 0;i < SND_LISTENERS;i++) + if (vol[i]) + break; + if (i == SND_LISTENERS) + return false; sb_offset = ch->pos; sb = ch->sfx->fetcher->getsb (ch, &sb_offset, count); @@ -243,6 +255,7 @@ static qboolean SND_PaintChannel (channel_t *ch, unsigned int count) { Con_DPrintf("SND_PaintChannel: ERROR: can't get sound buffer from sfx \"%s\"\n", ch->sfx->name); // , count); // or add this? FIXME + return false; } else { @@ -470,8 +483,6 @@ static qboolean SND_PaintChannel (channel_t *ch, unsigned int count) return false; // unsupported number of channels in sound } } - - ch->pos += count; return true; } @@ -495,105 +506,53 @@ void S_PaintChannels (snd_ringbuffer_t* rb, unsigned int starttime, unsigned int memset (paintbuffer, 0, (partialend - paintedtime) * sizeof (paintbuffer[0])); // paint in the channels. + // channels with zero volumes still advance in time but don't paint. ch = channels; for (i = 0; i < total_channels ; i++, ch++) { sfx_t *sfx; - unsigned int ltime, j; + unsigned int ltime; + int count; sfx = ch->sfx; if (sfx == NULL) continue; - for (j = 0;j < SND_LISTENERS;j++) - if (ch->listener_volume[j]) - break; - if (j == SND_LISTENERS) - continue; if (!S_LoadSound (sfx, true)) continue; - - // if the channel is paused if (ch->flags & CHANNELFLAG_PAUSED) - { - int pausedtime = partialend - paintedtime; - ch->lastptime += pausedtime; - ch->end += pausedtime; continue; - } - // if the sound hasn't been painted last time, update his position - if (ch->lastptime < paintedtime) + ltime = paintedtime; + if (ch->pos < 0) { - ch->pos += paintedtime - ch->lastptime; - - // If the sound should have ended by then - if ((unsigned int)ch->pos > sfx->total_length) - { - int loopstart; - - if (sfx->loopstart >= 0) - loopstart = bound(0, sfx->loopstart, (int)sfx->total_length - 1); - else - { - if (ch->flags & CHANNELFLAG_FORCELOOP) - loopstart = 0; - else - loopstart = -1; - } - - // If the sound is looped - if (loopstart >= 0) - ch->pos = (ch->pos - sfx->total_length) % (sfx->total_length - loopstart) + loopstart; - else - ch->pos = sfx->total_length; - ch->end = paintedtime + sfx->total_length - ch->pos; - } + count = -ch->pos; + count = min(count, (int)(partialend - ltime)); + ch->pos += count; + ltime += count; } - ltime = paintedtime; while (ltime < partialend) { - int count; - qboolean stop_paint; - - // paint up to end - if (ch->end < partialend) - count = ch->end - ltime; - else - count = partialend - ltime; - - if (count > 0) + // paint up to end of buffer or of input, whichever is lower + count = sfx->total_length - ch->pos; + count = bound(0, count, (int)(partialend - ltime)); + if (count) { - for (j = 0; j < SND_LISTENERS; j++) - ch->listener_volume[j] = bound(0, ch->listener_volume[j], 255); - - stop_paint = !SND_PaintChannel (ch, (unsigned int)count); - if (!stop_paint) - { - ltime += count; - ch->lastptime = ltime; - } + SND_PaintChannel (ch, (unsigned int)count); + ch->pos += count; + ltime += count; } - else - stop_paint = false; - if (ltime >= ch->end) + // if at end of sfx, loop or stop the channel + if (ch->pos >= sfx->total_length) { - // if at end of loop, restart - if ((sfx->loopstart >= 0 || (ch->flags & CHANNELFLAG_FORCELOOP)) && !stop_paint) - { + if (sfx->loopstart >= 0 || (ch->flags & CHANNELFLAG_FORCELOOP)) ch->pos = bound(0, sfx->loopstart, (int)sfx->total_length - 1); - ch->end = ltime + sfx->total_length - ch->pos; - } - // channel just stopped else - stop_paint = true; - } - - if (stop_paint) - { - S_StopChannel (ch - channels); - break; + { + S_StopChannel (ch - channels); + break; + } } } } diff --git a/snd_ogg.c b/snd_ogg.c index 8a268203..5b3e3c76 100644 --- a/snd_ogg.c +++ b/snd_ogg.c @@ -453,7 +453,7 @@ static const snd_buffer_t* OGG_FetchSound (channel_t* ch, unsigned int* start, u ch->fetcher_data = per_ch; } - + real_start = *start; sb = &per_ch->sb; @@ -481,8 +481,8 @@ static const snd_buffer_t* OGG_FetchSound (channel_t* ch, unsigned int* start, u unsigned int time_start; ogg_int64_t ogg_start; int err; - - if (real_start > sfx->total_length) + + if (real_start > (unsigned int)sfx->total_length) { Con_Printf ("OGG_FetchSound: asked for a start position after the end of the sfx! (%u > %u)\n", real_start, sfx->total_length); -- 2.39.2