]> icculus.org git repositories - divverent/darkplaces.git/blob - snd_mix.c
removed vm_cl_extensions (now uses vm_sv_extensions)
[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         for (i = 0;i < SND_LISTENERS;i++)
238                 vol[i] = ch->listener_volume[i] * snd_vol;
239
240         sb_offset = ch->pos;
241         sb = ch->sfx->fetcher->getsb (ch, &sb_offset, count);
242         if (sb == NULL)
243         {
244                 Con_DPrintf("SND_PaintChannel: ERROR: can't get sound buffer from sfx \"%s\"\n",
245                                         ch->sfx->name); // , count); // or add this? FIXME
246         }
247         else
248         {
249 #if SND_LISTENERS != 8
250 #               error the following code only supports up to 8 channels, update it
251 #endif
252                 if (sb->format.width == 1)
253                 {
254                         const signed char *samples = (signed char*)sb->samples + (ch->pos - sb_offset) * sb->format.channels;
255
256                         // Stereo sound support
257                         if (sb->format.channels == 2)
258                         {
259                                 if (vol[6] + vol[7] > 0)
260                                 {
261                                         for (i = 0;i < count;i++)
262                                         {
263                                                 paintbuffer[i].sample[0] += (samples[0] * vol[0]) >> 8;
264                                                 paintbuffer[i].sample[1] += (samples[1] * vol[1]) >> 8;
265                                                 paintbuffer[i].sample[2] += (samples[0] * vol[2]) >> 8;
266                                                 paintbuffer[i].sample[3] += (samples[1] * vol[3]) >> 8;
267                                                 paintbuffer[i].sample[4] += ((samples[0] + samples[1]) * vol[4]) >> 9;
268                                                 paintbuffer[i].sample[5] += ((samples[0] + samples[1]) * vol[5]) >> 9;
269                                                 paintbuffer[i].sample[6] += (samples[0] * vol[6]) >> 8;
270                                                 paintbuffer[i].sample[7] += (samples[1] * vol[7]) >> 8;
271                                                 samples += 2;
272                                         }
273                                 }
274                                 else if (vol[4] + vol[5] > 0)
275                                 {
276                                         for (i = 0;i < count;i++)
277                                         {
278                                                 paintbuffer[i].sample[0] += (samples[0] * vol[0]) >> 8;
279                                                 paintbuffer[i].sample[1] += (samples[1] * vol[1]) >> 8;
280                                                 paintbuffer[i].sample[2] += (samples[0] * vol[2]) >> 8;
281                                                 paintbuffer[i].sample[3] += (samples[1] * vol[3]) >> 8;
282                                                 paintbuffer[i].sample[4] += ((samples[0] + samples[1]) * vol[4]) >> 9;
283                                                 paintbuffer[i].sample[5] += ((samples[0] + samples[1]) * vol[5]) >> 9;
284                                                 samples += 2;
285                                         }
286                                 }
287                                 else if (vol[2] + vol[3] > 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                                                 samples += 2;
296                                         }
297                                 }
298                                 else if (vol[0] + vol[1] > 0)
299                                 {
300                                         for (i = 0;i < count;i++)
301                                         {
302                                                 paintbuffer[i].sample[0] += (samples[0] * vol[0]) >> 8;
303                                                 paintbuffer[i].sample[1] += (samples[1] * vol[1]) >> 8;
304                                                 samples += 2;
305                                         }
306                                 }
307                         }
308                         else if (sb->format.channels == 1)
309                         {
310                                 if (vol[6] + vol[7] > 0)
311                                 {
312                                         for (i = 0;i < count;i++)
313                                         {
314                                                 paintbuffer[i].sample[0] += (samples[0] * vol[0]) >> 8;
315                                                 paintbuffer[i].sample[1] += (samples[0] * vol[1]) >> 8;
316                                                 paintbuffer[i].sample[2] += (samples[0] * vol[2]) >> 8;
317                                                 paintbuffer[i].sample[3] += (samples[0] * vol[3]) >> 8;
318                                                 paintbuffer[i].sample[4] += (samples[0] * vol[4]) >> 8;
319                                                 paintbuffer[i].sample[5] += (samples[0] * vol[5]) >> 8;
320                                                 paintbuffer[i].sample[6] += (samples[0] * vol[6]) >> 8;
321                                                 paintbuffer[i].sample[7] += (samples[0] * vol[7]) >> 8;
322                                                 samples += 1;
323                                         }
324                                 }
325                                 else if (vol[4] + vol[5] > 0)
326                                 {
327                                         for (i = 0;i < count;i++)
328                                         {
329                                                 paintbuffer[i].sample[0] += (samples[0] * vol[0]) >> 8;
330                                                 paintbuffer[i].sample[1] += (samples[0] * vol[1]) >> 8;
331                                                 paintbuffer[i].sample[2] += (samples[0] * vol[2]) >> 8;
332                                                 paintbuffer[i].sample[3] += (samples[0] * vol[3]) >> 8;
333                                                 paintbuffer[i].sample[4] += (samples[0] * vol[4]) >> 8;
334                                                 paintbuffer[i].sample[5] += (samples[0] * vol[5]) >> 8;
335                                                 samples += 1;
336                                         }
337                                 }
338                                 else if (vol[2] + vol[3] > 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                                                 samples += 1;
347                                         }
348                                 }
349                                 else if (vol[0] + vol[1] > 0)
350                                 {
351                                         for (i = 0;i < count;i++)
352                                         {
353                                                 paintbuffer[i].sample[0] += (samples[0] * vol[0]) >> 8;
354                                                 paintbuffer[i].sample[1] += (samples[0] * vol[1]) >> 8;
355                                                 samples += 1;
356                                         }
357                                 }
358                         }
359                         else
360                                 return false; // unsupported number of channels in sound
361                 }
362                 else if (sb->format.width == 2)
363                 {
364                         const signed short *samples = (signed short*)sb->samples + (ch->pos - sb_offset) * sb->format.channels;
365
366                         // Stereo sound support
367                         if (sb->format.channels == 2)
368                         {
369                                 if (vol[6] + vol[7] > 0)
370                                 {
371                                         for (i = 0;i < count;i++)
372                                         {
373                                                 paintbuffer[i].sample[0] += (samples[0] * vol[0]) >> 16;
374                                                 paintbuffer[i].sample[1] += (samples[1] * vol[1]) >> 16;
375                                                 paintbuffer[i].sample[2] += (samples[0] * vol[2]) >> 16;
376                                                 paintbuffer[i].sample[3] += (samples[1] * vol[3]) >> 16;
377                                                 paintbuffer[i].sample[4] += ((samples[0] + samples[1]) * vol[4]) >> 17;
378                                                 paintbuffer[i].sample[5] += ((samples[0] + samples[1]) * vol[5]) >> 17;
379                                                 paintbuffer[i].sample[6] += (samples[0] * vol[6]) >> 16;
380                                                 paintbuffer[i].sample[7] += (samples[1] * vol[7]) >> 16;
381                                                 samples += 2;
382                                         }
383                                 }
384                                 else if (vol[4] + vol[5] > 0)
385                                 {
386                                         for (i = 0;i < count;i++)
387                                         {
388                                                 paintbuffer[i].sample[0] += (samples[0] * vol[0]) >> 16;
389                                                 paintbuffer[i].sample[1] += (samples[1] * vol[1]) >> 16;
390                                                 paintbuffer[i].sample[2] += (samples[0] * vol[2]) >> 16;
391                                                 paintbuffer[i].sample[3] += (samples[1] * vol[3]) >> 16;
392                                                 paintbuffer[i].sample[4] += ((samples[0] + samples[1]) * vol[4]) >> 17;
393                                                 paintbuffer[i].sample[5] += ((samples[0] + samples[1]) * vol[5]) >> 17;
394                                                 samples += 2;
395                                         }
396                                 }
397                                 else if (vol[2] + vol[3] > 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                                                 samples += 2;
406                                         }
407                                 }
408                                 else if (vol[0] + vol[1] > 0)
409                                 {
410                                         for (i = 0;i < count;i++)
411                                         {
412                                                 paintbuffer[i].sample[0] += (samples[0] * vol[0]) >> 16;
413                                                 paintbuffer[i].sample[1] += (samples[1] * vol[1]) >> 16;
414                                                 samples += 2;
415                                         }
416                                 }
417                         }
418                         else if (sb->format.channels == 1)
419                         {
420                                 if (vol[6] + vol[7] > 0)
421                                 {
422                                         for (i = 0;i < count;i++)
423                                         {
424                                                 paintbuffer[i].sample[0] += (samples[0] * vol[0]) >> 16;
425                                                 paintbuffer[i].sample[1] += (samples[0] * vol[1]) >> 16;
426                                                 paintbuffer[i].sample[2] += (samples[0] * vol[2]) >> 16;
427                                                 paintbuffer[i].sample[3] += (samples[0] * vol[3]) >> 16;
428                                                 paintbuffer[i].sample[4] += (samples[0] * vol[4]) >> 16;
429                                                 paintbuffer[i].sample[5] += (samples[0] * vol[5]) >> 16;
430                                                 paintbuffer[i].sample[6] += (samples[0] * vol[6]) >> 16;
431                                                 paintbuffer[i].sample[7] += (samples[0] * vol[7]) >> 16;
432                                                 samples += 1;
433                                         }
434                                 }
435                                 else if (vol[4] + vol[5] > 0)
436                                 {
437                                         for (i = 0;i < count;i++)
438                                         {
439                                                 paintbuffer[i].sample[0] += (samples[0] * vol[0]) >> 16;
440                                                 paintbuffer[i].sample[1] += (samples[0] * vol[1]) >> 16;
441                                                 paintbuffer[i].sample[2] += (samples[0] * vol[2]) >> 16;
442                                                 paintbuffer[i].sample[3] += (samples[0] * vol[3]) >> 16;
443                                                 paintbuffer[i].sample[4] += (samples[0] * vol[4]) >> 16;
444                                                 paintbuffer[i].sample[5] += (samples[0] * vol[5]) >> 16;
445                                                 samples += 1;
446                                         }
447                                 }
448                                 else if (vol[2] + vol[3] > 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                                                 samples += 1;
457                                         }
458                                 }
459                                 else if (vol[0] + vol[1] > 0)
460                                 {
461                                         for (i = 0;i < count;i++)
462                                         {
463                                                 paintbuffer[i].sample[0] += (samples[0] * vol[0]) >> 16;
464                                                 paintbuffer[i].sample[1] += (samples[0] * vol[1]) >> 16;
465                                                 samples += 1;
466                                         }
467                                 }
468                         }
469                         else
470                                 return false; // unsupported number of channels in sound
471                 }
472         }
473
474         ch->pos += count;
475         return true;
476 }
477
478 void S_PaintChannels (snd_ringbuffer_t* rb, unsigned int starttime, unsigned int endtime)
479 {
480         unsigned int paintedtime;
481
482         paintedtime = starttime;
483         while (paintedtime < endtime)
484         {
485                 unsigned int partialend, i, framecount;
486                 channel_t *ch;
487
488                 // if paintbuffer is too small
489                 if (endtime > paintedtime + PAINTBUFFER_SIZE)
490                         partialend = paintedtime + PAINTBUFFER_SIZE;
491                 else
492                         partialend = endtime;
493
494                 // clear the paint buffer
495                 memset (paintbuffer, 0, (partialend - paintedtime) * sizeof (paintbuffer[0]));
496
497                 // paint in the channels.
498                 ch = channels;
499                 for (i = 0; i < total_channels ; i++, ch++)
500                 {
501                         sfx_t *sfx;
502                         unsigned int ltime, j;
503
504                         sfx = ch->sfx;
505                         if (sfx == NULL)
506                                 continue;
507                         for (j = 0;j < SND_LISTENERS;j++)
508                                 if (ch->listener_volume[j])
509                                         break;
510                         if (j == SND_LISTENERS)
511                                 continue;
512                         if (!S_LoadSound (sfx, true))
513                                 continue;
514
515                         // if the channel is paused
516                         if (ch->flags & CHANNELFLAG_PAUSED)
517                         {
518                                 int pausedtime = partialend - paintedtime;
519                                 ch->lastptime += pausedtime;
520                                 ch->end += pausedtime;
521                                 continue;
522                         }
523
524                         // if the sound hasn't been painted last time, update his position
525                         if (ch->lastptime < paintedtime)
526                         {
527                                 ch->pos += paintedtime - ch->lastptime;
528
529                                 // If the sound should have ended by then
530                                 if ((unsigned int)ch->pos > sfx->total_length)
531                                 {
532                                         int loopstart;
533
534                                         if (sfx->loopstart >= 0)
535                                                 loopstart = bound(0, sfx->loopstart, (int)sfx->total_length - 1);
536                                         else
537                                         {
538                                                 if (ch->flags & CHANNELFLAG_FORCELOOP)
539                                                         loopstart = 0;
540                                                 else
541                                                         loopstart = -1;
542                                         }
543
544                                         // If the sound is looped
545                                         if (loopstart >= 0)
546                                                 ch->pos = (ch->pos - sfx->total_length) % (sfx->total_length - loopstart) + loopstart;
547                                         else
548                                                 ch->pos = sfx->total_length;
549                                         ch->end = paintedtime + sfx->total_length - ch->pos;
550                                 }
551                         }
552
553                         ltime = paintedtime;
554                         while (ltime < partialend)
555                         {
556                                 int count;
557                                 qboolean stop_paint;
558
559                                 // paint up to end
560                                 if (ch->end < partialend)
561                                         count = ch->end - ltime;
562                                 else
563                                         count = partialend - ltime;
564
565                                 if (count > 0)
566                                 {
567                                         for (j = 0; j < SND_LISTENERS; j++)
568                                                 ch->listener_volume[j] = bound(0, ch->listener_volume[j], 255);
569
570                                         stop_paint = !SND_PaintChannel (ch, (unsigned int)count);
571                                         if (!stop_paint)
572                                         {
573                                                 ltime += count;
574                                                 ch->lastptime = ltime;
575                                         }
576                                 }
577                                 else
578                                         stop_paint = false;
579
580                                 if (ltime >= ch->end)
581                                 {
582                                         // if at end of loop, restart
583                                         if ((sfx->loopstart >= 0 || (ch->flags & CHANNELFLAG_FORCELOOP)) && !stop_paint)
584                                         {
585                                                 ch->pos = bound(0, sfx->loopstart, (int)sfx->total_length - 1);
586                                                 ch->end = ltime + sfx->total_length - ch->pos;
587                                         }
588                                         // channel just stopped
589                                         else
590                                                 stop_paint = true;
591                                 }
592
593                                 if (stop_paint)
594                                 {
595                                         S_StopChannel (ch - channels);
596                                         break;
597                                 }
598                         }
599                 }
600
601                 S_CaptureAVISound (partialend - paintedtime);
602                 framecount = S_TransferPaintBuffer (rb, paintedtime, partialend);
603                 paintedtime += framecount;
604
605                 // If there was not enough free space in the sound buffer, stop here
606                 if (paintedtime != partialend)
607                 {
608                         Con_DPrintf(">> S_PaintChannels: Not enough free space in the sound buffer ( %u != %u)\n", paintedtime, partialend);
609                         break;
610                 }
611         }
612 }