removed channel_t->end and lastptime, now only pos governs playback
authorhavoc <havoc@d7cf8633-e32d-0410-b094-e92efae38249>
Mon, 14 May 2007 09:12:25 +0000 (09:12 +0000)
committerhavoc <havoc@d7cf8633-e32d-0410-b094-e92efae38249>
Mon, 14 May 2007 09:12:25 +0000 (09:12 +0000)
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
snd_main.h
snd_mix.c
snd_ogg.c

index 919553b..7cb7d55 100644 (file)
@@ -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;
 }
 
 
index aba8086..47a580a 100644 (file)
@@ -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
index dc2a147..43be365 100644 (file)
--- 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;
+                                       }
                                }
                        }
                }
index 8a26820..5b3e3c7 100644 (file)
--- 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);