remove prvm_boundscheck cvar (security hole) and force bounds check on unless DP...
[divverent/darkplaces.git] / snd_mix.c
1 /*
2 Copyright (C) 1996-1997 Id Software, Inc.
3
4 This program is free software; you can redistribute it and/or
5 modify it under the terms of the GNU General Public License
6 as published by the Free Software Foundation; either version 2
7 of the License, or (at your option) any later version.
8
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
12
13 See the GNU General Public License for more details.
14
15 You should have received a copy of the GNU General Public License
16 along with this program; if not, write to the Free Software
17 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
18
19 */
20
21 #include "quakedef.h"
22 #include "snd_main.h"
23
24
25 typedef struct portable_samplepair_s
26 {
27         int sample[SND_LISTENERS];
28 } portable_sampleframe_t;
29
30 // LordHavoc: was 512, expanded to 2048
31 #define PAINTBUFFER_SIZE 2048
32 portable_sampleframe_t paintbuffer[PAINTBUFFER_SIZE];
33
34
35 extern void SCR_CaptureVideo_SoundFrame(unsigned char *bufstereo16le, size_t length, int rate);
36 static void S_CaptureAVISound(size_t length)
37 {
38         size_t i;
39         unsigned char out[PAINTBUFFER_SIZE * 4];
40         unsigned char* out_ptr;
41
42         if (!cls.capturevideo.active)
43                 return;
44
45         // write the sound buffer as little endian 16bit interleaved stereo
46         for(i = 0, out_ptr = out; i < length; i++, out_ptr += 4)
47         {
48                 int n0, n1;
49
50                 n0 = paintbuffer[i].sample[0];
51                 n0 = bound(-32768, n0, 32767);
52                 out_ptr[0] = (unsigned char)n0;
53                 out_ptr[1] = (unsigned char)(n0 >> 8);
54
55                 n1 = paintbuffer[i].sample[1];
56                 n1 = bound(-32768, n1, 32767);
57                 out_ptr[2] = (unsigned char)n1;
58                 out_ptr[3] = (unsigned char)(n1 >> 8);
59         }
60         SCR_CaptureVideo_SoundFrame(out, length, snd_renderbuffer->format.speed);
61 }
62
63 static unsigned int S_TransferPaintBuffer(snd_ringbuffer_t* rb, unsigned int starttime, unsigned int endtime)
64 {
65         unsigned int partialend;
66
67         // Lock submitbuffer
68         if (!simsound && !SndSys_LockRenderBuffer())
69                 return 0;
70
71         partialend = starttime;
72         while (partialend < endtime)  // handle recirculating buffer issues
73         {
74                 unsigned int startoffset, maxframes, nbframes, i;
75                 void *rb_ptr;
76                 portable_sampleframe_t *painted_ptr;
77                 int val;
78
79                 startoffset = partialend % rb->maxframes;
80                 maxframes = rb->maxframes - startoffset;
81                 nbframes = endtime - partialend;
82                 if (nbframes > maxframes)
83                         nbframes = maxframes;
84
85                 rb_ptr = &rb->ring[startoffset * rb->format.width * rb->format.channels];
86                 painted_ptr = &paintbuffer[partialend - starttime];
87
88                 if (rb->format.width == 2)  // 16bit
89                 {
90                         short *snd_out = (short*)rb_ptr;
91                         if (rb->format.channels == 8)  // 7.1 surround
92                         {
93                                 for (i = 0;i < nbframes;i++, painted_ptr++)
94                                 {
95                                         *snd_out++ = bound(-32768, painted_ptr->sample[0], 32767);
96                                         *snd_out++ = bound(-32768, painted_ptr->sample[1], 32767);
97                                         *snd_out++ = bound(-32768, painted_ptr->sample[2], 32767);
98                                         *snd_out++ = bound(-32768, painted_ptr->sample[3], 32767);
99                                         *snd_out++ = bound(-32768, painted_ptr->sample[4], 32767);
100                                         *snd_out++ = bound(-32768, painted_ptr->sample[5], 32767);
101                                         *snd_out++ = bound(-32768, painted_ptr->sample[6], 32767);
102                                         *snd_out++ = bound(-32768, painted_ptr->sample[7], 32767);
103                                 }
104                         }
105                         else if (rb->format.channels == 6)  // 5.1 surround
106                         {
107                                 for (i = 0; i < nbframes; i++, painted_ptr++)
108                                 {
109                                         *snd_out++ = bound(-32768, painted_ptr->sample[0], 32767);
110                                         *snd_out++ = bound(-32768, painted_ptr->sample[1], 32767);
111                                         *snd_out++ = bound(-32768, painted_ptr->sample[2], 32767);
112                                         *snd_out++ = bound(-32768, painted_ptr->sample[3], 32767);
113                                         *snd_out++ = bound(-32768, painted_ptr->sample[4], 32767);
114                                         *snd_out++ = bound(-32768, painted_ptr->sample[5], 32767);
115                                 }
116                         }
117                         else if (rb->format.channels == 4)  // 4.0 surround
118                         {
119                                 for (i = 0; i < nbframes; i++, painted_ptr++)
120                                 {
121                                         *snd_out++ = bound(-32768, painted_ptr->sample[0], 32767);
122                                         *snd_out++ = bound(-32768, painted_ptr->sample[1], 32767);
123                                         *snd_out++ = bound(-32768, painted_ptr->sample[2], 32767);
124                                         *snd_out++ = bound(-32768, painted_ptr->sample[3], 32767);
125                                 }
126                         }
127                         else if (rb->format.channels == 2)  // 2.0 stereo
128                         {
129                                 for (i = 0; i < nbframes; i++, painted_ptr++)
130                                 {
131                                         *snd_out++ = bound(-32768, painted_ptr->sample[0], 32767);
132                                         *snd_out++ = bound(-32768, painted_ptr->sample[1], 32767);
133                                 }
134                         }
135                         else if (rb->format.channels == 1)  // 1.0 mono
136                         {
137                                 for (i = 0; i < nbframes; i++, painted_ptr++)
138                                 {
139                                         val = (painted_ptr->sample[0] + painted_ptr->sample[1]) >> 1;
140                                         *snd_out++ = bound(-32768, val, 32767);
141                                 }
142                         }
143                 }
144                 else  // 8bit
145                 {
146                         unsigned char *snd_out = (unsigned char*)rb_ptr;
147                         if (rb->format.channels == 8)  // 7.1 surround
148                         {
149                                 for (i = 0; i < nbframes; i++, painted_ptr++)
150                                 {
151                                         val = (painted_ptr->sample[0] >> 8) + 128; *snd_out++ = bound(0, val, 255);
152                                         val = (painted_ptr->sample[1] >> 8) + 128; *snd_out++ = bound(0, val, 255);
153                                         val = (painted_ptr->sample[2] >> 8) + 128; *snd_out++ = bound(0, val, 255);
154                                         val = (painted_ptr->sample[3] >> 8) + 128; *snd_out++ = bound(0, val, 255);
155                                         val = (painted_ptr->sample[4] >> 8) + 128; *snd_out++ = bound(0, val, 255);
156                                         val = (painted_ptr->sample[5] >> 8) + 128; *snd_out++ = bound(0, val, 255);
157                                         val = (painted_ptr->sample[6] >> 8) + 128; *snd_out++ = bound(0, val, 255);
158                                         val = (painted_ptr->sample[7] >> 8) + 128; *snd_out++ = bound(0, val, 255);
159                                 }
160                         }
161                         else if (rb->format.channels == 6)  // 5.1 surround
162                         {
163                                 for (i = 0; i < nbframes; i++, painted_ptr++)
164                                 {
165                                         val = (painted_ptr->sample[0] >> 8) + 128; *snd_out++ = bound(0, val, 255);
166                                         val = (painted_ptr->sample[1] >> 8) + 128; *snd_out++ = bound(0, val, 255);
167                                         val = (painted_ptr->sample[2] >> 8) + 128; *snd_out++ = bound(0, val, 255);
168                                         val = (painted_ptr->sample[3] >> 8) + 128; *snd_out++ = bound(0, val, 255);
169                                         val = (painted_ptr->sample[4] >> 8) + 128; *snd_out++ = bound(0, val, 255);
170                                         val = (painted_ptr->sample[5] >> 8) + 128; *snd_out++ = bound(0, val, 255);
171                                 }
172                         }
173                         else if (rb->format.channels == 4)  // 4.0 surround
174                         {
175                                 for (i = 0; i < nbframes; i++, painted_ptr++)
176                                 {
177                                         val = (painted_ptr->sample[0] >> 8) + 128; *snd_out++ = bound(0, val, 255);
178                                         val = (painted_ptr->sample[1] >> 8) + 128; *snd_out++ = bound(0, val, 255);
179                                         val = (painted_ptr->sample[2] >> 8) + 128; *snd_out++ = bound(0, val, 255);
180                                         val = (painted_ptr->sample[3] >> 8) + 128; *snd_out++ = bound(0, val, 255);
181                                 }
182                         }
183                         else if (rb->format.channels == 2)  // 2.0 stereo
184                         {
185                                 for (i = 0; i < nbframes; i++, painted_ptr++)
186                                 {
187                                         val = (painted_ptr->sample[0] >> 8) + 128; *snd_out++ = bound(0, val, 255);
188                                         val = (painted_ptr->sample[1] >> 8) + 128; *snd_out++ = bound(0, val, 255);
189                                 }
190                         }
191                         else if (rb->format.channels == 1)  // 1.0 mono
192                         {
193                                 for (i = 0;i < nbframes;i++, painted_ptr++)
194                                 {
195                                         val = ((painted_ptr->sample[0] + painted_ptr->sample[1]) >> 9) + 128;
196                                         *snd_out++ = bound(0, val, 255);
197                                 }
198                         }
199                 }
200
201                 partialend += nbframes;
202         }
203
204         rb->endframe = endtime;
205
206         // Remove outdated samples from the ring buffer, if any
207         if (rb->startframe < soundtime)
208                 rb->startframe = soundtime;
209
210         if (!simsound)
211                 SndSys_UnlockRenderBuffer();
212
213         return endtime - starttime;
214 }
215
216
217 /*
218 ===============================================================================
219
220 CHANNEL MIXING
221
222 ===============================================================================
223 */
224
225 static qboolean SND_PaintChannel (channel_t *ch, unsigned int count)
226 {
227         int snd_vol, vol[SND_LISTENERS];
228         const snd_buffer_t *sb;
229         unsigned int i, sb_offset;
230
231         // If this channel manages its own volume
232         if (ch->flags & CHANNELFLAG_FULLVOLUME)
233                 snd_vol = 256;
234         else
235                 snd_vol = (int)(volume.value * 256);
236
237         // calculate mixing volumes based on channel volumes and volume cvar
238         // also limit the volumes to values that won't clip
239         for (i = 0;i < SND_LISTENERS;i++)
240         {
241                 vol[i] = ch->listener_volume[i] * snd_vol;
242                 vol[i] = bound(0, vol[i], 65536);
243         }
244
245         // if volumes are all zero, just return
246         for (i = 0;i < SND_LISTENERS;i++)
247                 if (vol[i])
248                         break;
249         if (i == SND_LISTENERS)
250                 return false;
251
252         sb_offset = ch->pos;
253         sb = ch->sfx->fetcher->getsb (ch->sfx->fetcher_data, &ch->fetcher_data, &sb_offset, count);
254         if (sb == NULL)
255         {
256                 Con_DPrintf("SND_PaintChannel: ERROR: can't get sound buffer from sfx \"%s\"\n",
257                                         ch->sfx->name); // , count); // or add this? FIXME
258                 return false;
259         }
260         else
261         {
262 #if SND_LISTENERS != 8
263 #               error the following code only supports up to 8 channels, update it
264 #endif
265                 if (sb->format.width == 1)
266                 {
267                         const signed char *samples = (signed char*)sb->samples + (ch->pos - sb_offset) * sb->format.channels;
268
269                         // Stereo sound support
270                         if (sb->format.channels == 2)
271                         {
272                                 if (vol[6] + vol[7] > 0)
273                                 {
274                                         for (i = 0;i < count;i++)
275                                         {
276                                                 paintbuffer[i].sample[0] += (samples[0] * vol[0]) >> 8;
277                                                 paintbuffer[i].sample[1] += (samples[1] * vol[1]) >> 8;
278                                                 paintbuffer[i].sample[2] += (samples[0] * vol[2]) >> 8;
279                                                 paintbuffer[i].sample[3] += (samples[1] * vol[3]) >> 8;
280                                                 paintbuffer[i].sample[4] += ((samples[0] + samples[1]) * vol[4]) >> 9;
281                                                 paintbuffer[i].sample[5] += ((samples[0] + samples[1]) * vol[5]) >> 9;
282                                                 paintbuffer[i].sample[6] += (samples[0] * vol[6]) >> 8;
283                                                 paintbuffer[i].sample[7] += (samples[1] * vol[7]) >> 8;
284                                                 samples += 2;
285                                         }
286                                 }
287                                 else if (vol[4] + vol[5] > 0)
288                                 {
289                                         for (i = 0;i < count;i++)
290                                         {
291                                                 paintbuffer[i].sample[0] += (samples[0] * vol[0]) >> 8;
292                                                 paintbuffer[i].sample[1] += (samples[1] * vol[1]) >> 8;
293                                                 paintbuffer[i].sample[2] += (samples[0] * vol[2]) >> 8;
294                                                 paintbuffer[i].sample[3] += (samples[1] * vol[3]) >> 8;
295                                                 paintbuffer[i].sample[4] += ((samples[0] + samples[1]) * vol[4]) >> 9;
296                                                 paintbuffer[i].sample[5] += ((samples[0] + samples[1]) * vol[5]) >> 9;
297                                                 samples += 2;
298                                         }
299                                 }
300                                 else if (vol[2] + vol[3] > 0)
301                                 {
302                                         for (i = 0;i < count;i++)
303                                         {
304                                                 paintbuffer[i].sample[0] += (samples[0] * vol[0]) >> 8;
305                                                 paintbuffer[i].sample[1] += (samples[1] * vol[1]) >> 8;
306                                                 paintbuffer[i].sample[2] += (samples[0] * vol[2]) >> 8;
307                                                 paintbuffer[i].sample[3] += (samples[1] * vol[3]) >> 8;
308                                                 samples += 2;
309                                         }
310                                 }
311                                 else if (vol[0] + vol[1] > 0)
312                                 {
313                                         for (i = 0;i < count;i++)
314                                         {
315                                                 paintbuffer[i].sample[0] += (samples[0] * vol[0]) >> 8;
316                                                 paintbuffer[i].sample[1] += (samples[1] * vol[1]) >> 8;
317                                                 samples += 2;
318                                         }
319                                 }
320                         }
321                         else if (sb->format.channels == 1)
322                         {
323                                 if (vol[6] + vol[7] > 0)
324                                 {
325                                         for (i = 0;i < count;i++)
326                                         {
327                                                 paintbuffer[i].sample[0] += (samples[0] * vol[0]) >> 8;
328                                                 paintbuffer[i].sample[1] += (samples[0] * vol[1]) >> 8;
329                                                 paintbuffer[i].sample[2] += (samples[0] * vol[2]) >> 8;
330                                                 paintbuffer[i].sample[3] += (samples[0] * vol[3]) >> 8;
331                                                 paintbuffer[i].sample[4] += (samples[0] * vol[4]) >> 8;
332                                                 paintbuffer[i].sample[5] += (samples[0] * vol[5]) >> 8;
333                                                 paintbuffer[i].sample[6] += (samples[0] * vol[6]) >> 8;
334                                                 paintbuffer[i].sample[7] += (samples[0] * vol[7]) >> 8;
335                                                 samples += 1;
336                                         }
337                                 }
338                                 else if (vol[4] + vol[5] > 0)
339                                 {
340                                         for (i = 0;i < count;i++)
341                                         {
342                                                 paintbuffer[i].sample[0] += (samples[0] * vol[0]) >> 8;
343                                                 paintbuffer[i].sample[1] += (samples[0] * vol[1]) >> 8;
344                                                 paintbuffer[i].sample[2] += (samples[0] * vol[2]) >> 8;
345                                                 paintbuffer[i].sample[3] += (samples[0] * vol[3]) >> 8;
346                                                 paintbuffer[i].sample[4] += (samples[0] * vol[4]) >> 8;
347                                                 paintbuffer[i].sample[5] += (samples[0] * vol[5]) >> 8;
348                                                 samples += 1;
349                                         }
350                                 }
351                                 else if (vol[2] + vol[3] > 0)
352                                 {
353                                         for (i = 0;i < count;i++)
354                                         {
355                                                 paintbuffer[i].sample[0] += (samples[0] * vol[0]) >> 8;
356                                                 paintbuffer[i].sample[1] += (samples[0] * vol[1]) >> 8;
357                                                 paintbuffer[i].sample[2] += (samples[0] * vol[2]) >> 8;
358                                                 paintbuffer[i].sample[3] += (samples[0] * vol[3]) >> 8;
359                                                 samples += 1;
360                                         }
361                                 }
362                                 else if (vol[0] + vol[1] > 0)
363                                 {
364                                         for (i = 0;i < count;i++)
365                                         {
366                                                 paintbuffer[i].sample[0] += (samples[0] * vol[0]) >> 8;
367                                                 paintbuffer[i].sample[1] += (samples[0] * vol[1]) >> 8;
368                                                 samples += 1;
369                                         }
370                                 }
371                         }
372                         else
373                                 return false; // unsupported number of channels in sound
374                 }
375                 else if (sb->format.width == 2)
376                 {
377                         const signed short *samples = (signed short*)sb->samples + (ch->pos - sb_offset) * sb->format.channels;
378
379                         // Stereo sound support
380                         if (sb->format.channels == 2)
381                         {
382                                 if (vol[6] + vol[7] > 0)
383                                 {
384                                         for (i = 0;i < count;i++)
385                                         {
386                                                 paintbuffer[i].sample[0] += (samples[0] * vol[0]) >> 16;
387                                                 paintbuffer[i].sample[1] += (samples[1] * vol[1]) >> 16;
388                                                 paintbuffer[i].sample[2] += (samples[0] * vol[2]) >> 16;
389                                                 paintbuffer[i].sample[3] += (samples[1] * vol[3]) >> 16;
390                                                 paintbuffer[i].sample[4] += ((samples[0] + samples[1]) * vol[4]) >> 17;
391                                                 paintbuffer[i].sample[5] += ((samples[0] + samples[1]) * vol[5]) >> 17;
392                                                 paintbuffer[i].sample[6] += (samples[0] * vol[6]) >> 16;
393                                                 paintbuffer[i].sample[7] += (samples[1] * vol[7]) >> 16;
394                                                 samples += 2;
395                                         }
396                                 }
397                                 else if (vol[4] + vol[5] > 0)
398                                 {
399                                         for (i = 0;i < count;i++)
400                                         {
401                                                 paintbuffer[i].sample[0] += (samples[0] * vol[0]) >> 16;
402                                                 paintbuffer[i].sample[1] += (samples[1] * vol[1]) >> 16;
403                                                 paintbuffer[i].sample[2] += (samples[0] * vol[2]) >> 16;
404                                                 paintbuffer[i].sample[3] += (samples[1] * vol[3]) >> 16;
405                                                 paintbuffer[i].sample[4] += ((samples[0] + samples[1]) * vol[4]) >> 17;
406                                                 paintbuffer[i].sample[5] += ((samples[0] + samples[1]) * vol[5]) >> 17;
407                                                 samples += 2;
408                                         }
409                                 }
410                                 else if (vol[2] + vol[3] > 0)
411                                 {
412                                         for (i = 0;i < count;i++)
413                                         {
414                                                 paintbuffer[i].sample[0] += (samples[0] * vol[0]) >> 16;
415                                                 paintbuffer[i].sample[1] += (samples[1] * vol[1]) >> 16;
416                                                 paintbuffer[i].sample[2] += (samples[0] * vol[2]) >> 16;
417                                                 paintbuffer[i].sample[3] += (samples[1] * vol[3]) >> 16;
418                                                 samples += 2;
419                                         }
420                                 }
421                                 else if (vol[0] + vol[1] > 0)
422                                 {
423                                         for (i = 0;i < count;i++)
424                                         {
425                                                 paintbuffer[i].sample[0] += (samples[0] * vol[0]) >> 16;
426                                                 paintbuffer[i].sample[1] += (samples[1] * vol[1]) >> 16;
427                                                 samples += 2;
428                                         }
429                                 }
430                         }
431                         else if (sb->format.channels == 1)
432                         {
433                                 if (vol[6] + vol[7] > 0)
434                                 {
435                                         for (i = 0;i < count;i++)
436                                         {
437                                                 paintbuffer[i].sample[0] += (samples[0] * vol[0]) >> 16;
438                                                 paintbuffer[i].sample[1] += (samples[0] * vol[1]) >> 16;
439                                                 paintbuffer[i].sample[2] += (samples[0] * vol[2]) >> 16;
440                                                 paintbuffer[i].sample[3] += (samples[0] * vol[3]) >> 16;
441                                                 paintbuffer[i].sample[4] += (samples[0] * vol[4]) >> 16;
442                                                 paintbuffer[i].sample[5] += (samples[0] * vol[5]) >> 16;
443                                                 paintbuffer[i].sample[6] += (samples[0] * vol[6]) >> 16;
444                                                 paintbuffer[i].sample[7] += (samples[0] * vol[7]) >> 16;
445                                                 samples += 1;
446                                         }
447                                 }
448                                 else if (vol[4] + vol[5] > 0)
449                                 {
450                                         for (i = 0;i < count;i++)
451                                         {
452                                                 paintbuffer[i].sample[0] += (samples[0] * vol[0]) >> 16;
453                                                 paintbuffer[i].sample[1] += (samples[0] * vol[1]) >> 16;
454                                                 paintbuffer[i].sample[2] += (samples[0] * vol[2]) >> 16;
455                                                 paintbuffer[i].sample[3] += (samples[0] * vol[3]) >> 16;
456                                                 paintbuffer[i].sample[4] += (samples[0] * vol[4]) >> 16;
457                                                 paintbuffer[i].sample[5] += (samples[0] * vol[5]) >> 16;
458                                                 samples += 1;
459                                         }
460                                 }
461                                 else if (vol[2] + vol[3] > 0)
462                                 {
463                                         for (i = 0;i < count;i++)
464                                         {
465                                                 paintbuffer[i].sample[0] += (samples[0] * vol[0]) >> 16;
466                                                 paintbuffer[i].sample[1] += (samples[0] * vol[1]) >> 16;
467                                                 paintbuffer[i].sample[2] += (samples[0] * vol[2]) >> 16;
468                                                 paintbuffer[i].sample[3] += (samples[0] * vol[3]) >> 16;
469                                                 samples += 1;
470                                         }
471                                 }
472                                 else if (vol[0] + vol[1] > 0)
473                                 {
474                                         for (i = 0;i < count;i++)
475                                         {
476                                                 paintbuffer[i].sample[0] += (samples[0] * vol[0]) >> 16;
477                                                 paintbuffer[i].sample[1] += (samples[0] * vol[1]) >> 16;
478                                                 samples += 1;
479                                         }
480                                 }
481                         }
482                         else
483                                 return false; // unsupported number of channels in sound
484                 }
485         }
486         return true;
487 }
488
489 void S_PaintChannels (snd_ringbuffer_t* rb, unsigned int starttime, unsigned int endtime)
490 {
491         unsigned int paintedtime;
492
493         paintedtime = starttime;
494         while (paintedtime < endtime)
495         {
496                 unsigned int partialend, i, framecount;
497                 channel_t *ch;
498
499                 // if paintbuffer is too small
500                 if (endtime > paintedtime + PAINTBUFFER_SIZE)
501                         partialend = paintedtime + PAINTBUFFER_SIZE;
502                 else
503                         partialend = endtime;
504
505                 // clear the paint buffer
506                 memset (paintbuffer, 0, (partialend - paintedtime) * sizeof (paintbuffer[0]));
507
508                 // paint in the channels.
509                 // channels with zero volumes still advance in time but don't paint.
510                 ch = channels;
511                 for (i = 0; i < total_channels ; i++, ch++)
512                 {
513                         sfx_t *sfx;
514                         unsigned int ltime;
515                         unsigned int count;
516
517                         sfx = ch->sfx;
518                         if (sfx == NULL)
519                                 continue;
520                         if (!S_LoadSound (sfx, true))
521                                 continue;
522                         if (ch->flags & CHANNELFLAG_PAUSED)
523                                 continue;
524
525                         ltime = paintedtime;
526                         if (ch->pos < 0)
527                         {
528                                 count = -ch->pos;
529                                 count = min(count, partialend - ltime);
530                                 ch->pos += count;
531                                 ltime += count;
532                         }
533
534                         while (ltime < partialend)
535                         {
536                                 // paint up to end of buffer or of input, whichever is lower
537                                 count = sfx->total_length - ch->pos;
538                                 count = bound(0, count, partialend - ltime);
539                                 if (count)
540                                 {
541                                         SND_PaintChannel (ch, count);
542                                         ch->pos += count;
543                                         ltime += count;
544                                 }
545
546                                 // if at end of sfx, loop or stop the channel
547                                 if (ch->pos >= (int)sfx->total_length)
548                                 {
549                                         if (sfx->loopstart < sfx->total_length)
550                                                 ch->pos = sfx->loopstart;
551                                         else if (ch->flags & CHANNELFLAG_FORCELOOP)
552                                                 ch->pos = 0;
553                                         else
554                                         {
555                                                 S_StopChannel (ch - channels);
556                                                 break;
557                                         }
558                                 }
559                         }
560                 }
561
562                 S_CaptureAVISound (partialend - paintedtime);
563                 framecount = S_TransferPaintBuffer (rb, paintedtime, partialend);
564                 paintedtime += framecount;
565
566                 // If there was not enough free space in the sound buffer, stop here
567                 if (paintedtime != partialend)
568                 {
569                         Con_DPrintf(">> S_PaintChannels: Not enough free space in the sound buffer ( %u != %u)\n", paintedtime, partialend);
570                         break;
571                 }
572         }
573 }