]> de.git.xonotic.org Git - xonotic/darkplaces.git/blob - snd_mix.c
patch from div0 to make universal-binary builds of darkplaces possible on Mac OS X
[xonotic/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 // FIXME: this desyncs with the video too easily
36 extern void SCR_CaptureVideo_SoundFrame(unsigned char *bufstereo16le, size_t length, int rate);
37 static void S_CaptureAVISound(size_t length)
38 {
39         size_t i;
40         unsigned char out[PAINTBUFFER_SIZE * 4];
41         unsigned char* out_ptr;
42
43         if (!cls.capturevideo_active)
44                 return;
45
46         // write the sound buffer as little endian 16bit interleaved stereo
47         for(i = 0, out_ptr = out; i < length; i++, out_ptr += 4)
48         {
49                 int n0, n1;
50
51                 n0 = paintbuffer[i].sample[0];
52                 n0 = bound(-32768, n0, 32767);
53                 out_ptr[0] = (unsigned char)n0;
54                 out_ptr[1] = (unsigned char)(n0 >> 8);
55
56                 n1 = paintbuffer[i].sample[1];
57                 n1 = bound(-32768, n1, 32767);
58                 out_ptr[2] = (unsigned char)n1;
59                 out_ptr[3] = (unsigned char)(n1 >> 8);
60         }
61         SCR_CaptureVideo_SoundFrame(out, length, snd_renderbuffer->format.speed);
62 }
63
64 static unsigned int S_TransferPaintBuffer(snd_ringbuffer_t* rb, unsigned int starttime, unsigned int endtime)
65 {
66         unsigned int partialend;
67
68         // Lock submitbuffer
69         if (!simsound && !SndSys_LockRenderBuffer())
70                 return 0;
71         
72         partialend = starttime;
73         while (partialend < endtime)  // handle recirculating buffer issues
74         {
75                 unsigned int startoffset, maxframes, nbframes, i;
76                 void *rb_ptr;
77                 portable_sampleframe_t *painted_ptr;
78                 int val;
79
80                 startoffset = partialend % rb->maxframes;
81                 maxframes = rb->maxframes - startoffset;
82                 nbframes = endtime - partialend;
83                 if (nbframes > maxframes)
84                         nbframes = maxframes;
85
86                 rb_ptr = &rb->ring[startoffset * rb->format.width * rb->format.channels];
87                 painted_ptr = &paintbuffer[partialend - starttime];
88
89                 if (rb->format.width == 2)  // 16bit
90                 {
91                         short *snd_out = (short*)rb_ptr;
92                         if (rb->format.channels == 8)  // 7.1 surround
93                         {
94                                 for (i = 0;i < nbframes;i++, painted_ptr++)
95                                 {
96                                         *snd_out++ = bound(-32768, painted_ptr->sample[0], 32767);
97                                         *snd_out++ = bound(-32768, painted_ptr->sample[1], 32767);
98                                         *snd_out++ = bound(-32768, painted_ptr->sample[2], 32767);
99                                         *snd_out++ = bound(-32768, painted_ptr->sample[3], 32767);
100                                         *snd_out++ = bound(-32768, painted_ptr->sample[4], 32767);
101                                         *snd_out++ = bound(-32768, painted_ptr->sample[5], 32767);
102                                         *snd_out++ = bound(-32768, painted_ptr->sample[6], 32767);
103                                         *snd_out++ = bound(-32768, painted_ptr->sample[7], 32767);
104                                 }
105                         }
106                         else if (rb->format.channels == 6)  // 5.1 surround
107                         {
108                                 for (i = 0; i < nbframes; i++, painted_ptr++)
109                                 {
110                                         *snd_out++ = bound(-32768, painted_ptr->sample[0], 32767);
111                                         *snd_out++ = bound(-32768, painted_ptr->sample[1], 32767);
112                                         *snd_out++ = bound(-32768, painted_ptr->sample[2], 32767);
113                                         *snd_out++ = bound(-32768, painted_ptr->sample[3], 32767);
114                                         *snd_out++ = bound(-32768, painted_ptr->sample[4], 32767);
115                                         *snd_out++ = bound(-32768, painted_ptr->sample[5], 32767);
116                                 }
117                         }
118                         else if (rb->format.channels == 4)  // 4.0 surround
119                         {
120                                 for (i = 0; i < nbframes; i++, painted_ptr++)
121                                 {
122                                         *snd_out++ = bound(-32768, painted_ptr->sample[0], 32767);
123                                         *snd_out++ = bound(-32768, painted_ptr->sample[1], 32767);
124                                         *snd_out++ = bound(-32768, painted_ptr->sample[2], 32767);
125                                         *snd_out++ = bound(-32768, painted_ptr->sample[3], 32767);
126                                 }
127                         }
128                         else if (rb->format.channels == 2)  // 2.0 stereo
129                         {
130                                 for (i = 0; i < nbframes; i++, painted_ptr++)
131                                 {
132                                         *snd_out++ = bound(-32768, painted_ptr->sample[0], 32767);
133                                         *snd_out++ = bound(-32768, painted_ptr->sample[1], 32767);
134                                 }
135                         }
136                         else if (rb->format.channels == 1)  // 1.0 mono
137                         {
138                                 for (i = 0; i < nbframes; i++, painted_ptr++)
139                                 {
140                                         val = (painted_ptr->sample[0] + painted_ptr->sample[1]) >> 1;
141                                         *snd_out++ = bound(-32768, val, 32767);
142                                 }
143                         }
144                 }
145                 else  // 8bit
146                 {
147                         unsigned char *snd_out = (unsigned char*)rb_ptr;
148                         if (rb->format.channels == 8)  // 7.1 surround
149                         {
150                                 for (i = 0; i < nbframes; i++, painted_ptr++)
151                                 {
152                                         val = (painted_ptr->sample[0] >> 8) + 128; *snd_out++ = bound(0, val, 255);
153                                         val = (painted_ptr->sample[1] >> 8) + 128; *snd_out++ = bound(0, val, 255);
154                                         val = (painted_ptr->sample[2] >> 8) + 128; *snd_out++ = bound(0, val, 255);
155                                         val = (painted_ptr->sample[3] >> 8) + 128; *snd_out++ = bound(0, val, 255);
156                                         val = (painted_ptr->sample[4] >> 8) + 128; *snd_out++ = bound(0, val, 255);
157                                         val = (painted_ptr->sample[5] >> 8) + 128; *snd_out++ = bound(0, val, 255);
158                                         val = (painted_ptr->sample[6] >> 8) + 128; *snd_out++ = bound(0, val, 255);
159                                         val = (painted_ptr->sample[7] >> 8) + 128; *snd_out++ = bound(0, val, 255);
160                                 }
161                         }
162                         else if (rb->format.channels == 6)  // 5.1 surround
163                         {
164                                 for (i = 0; i < nbframes; i++, painted_ptr++)
165                                 {
166                                         val = (painted_ptr->sample[0] >> 8) + 128; *snd_out++ = bound(0, val, 255);
167                                         val = (painted_ptr->sample[1] >> 8) + 128; *snd_out++ = bound(0, val, 255);
168                                         val = (painted_ptr->sample[2] >> 8) + 128; *snd_out++ = bound(0, val, 255);
169                                         val = (painted_ptr->sample[3] >> 8) + 128; *snd_out++ = bound(0, val, 255);
170                                         val = (painted_ptr->sample[4] >> 8) + 128; *snd_out++ = bound(0, val, 255);
171                                         val = (painted_ptr->sample[5] >> 8) + 128; *snd_out++ = bound(0, val, 255);
172                                 }
173                         }
174                         else if (rb->format.channels == 4)  // 4.0 surround
175                         {
176                                 for (i = 0; i < nbframes; i++, painted_ptr++)
177                                 {
178                                         val = (painted_ptr->sample[0] >> 8) + 128; *snd_out++ = bound(0, val, 255);
179                                         val = (painted_ptr->sample[1] >> 8) + 128; *snd_out++ = bound(0, val, 255);
180                                         val = (painted_ptr->sample[2] >> 8) + 128; *snd_out++ = bound(0, val, 255);
181                                         val = (painted_ptr->sample[3] >> 8) + 128; *snd_out++ = bound(0, val, 255);
182                                 }
183                         }
184                         else if (rb->format.channels == 2)  // 2.0 stereo
185                         {
186                                 for (i = 0; i < nbframes; i++, painted_ptr++)
187                                 {
188                                         val = (painted_ptr->sample[0] >> 8) + 128; *snd_out++ = bound(0, val, 255);
189                                         val = (painted_ptr->sample[1] >> 8) + 128; *snd_out++ = bound(0, val, 255);
190                                 }
191                         }
192                         else if (rb->format.channels == 1)  // 1.0 mono
193                         {
194                                 for (i = 0;i < nbframes;i++, painted_ptr++)
195                                 {
196                                         val = ((painted_ptr->sample[0] + painted_ptr->sample[1]) >> 9) + 128;
197                                         *snd_out++ = bound(0, val, 255);
198                                 }
199                         }
200                 }
201
202                 partialend += nbframes;
203         }
204
205         rb->endframe = endtime;
206
207         // Remove outdated samples from the ring buffer, if any
208         if (rb->startframe < soundtime)
209                 rb->startframe = soundtime;
210
211         if (!simsound)
212                 SndSys_UnlockRenderBuffer();
213
214         return endtime - starttime;
215 }
216
217
218 /*
219 ===============================================================================
220
221 CHANNEL MIXING
222
223 ===============================================================================
224 */
225
226 static qboolean SND_PaintChannel (channel_t *ch, unsigned int count)
227 {
228         int snd_vol, vol[SND_LISTENERS];
229         const snd_buffer_t *sb;
230         unsigned int i, sb_offset;
231
232         // If this channel manages its own volume
233         if (ch->flags & CHANNELFLAG_FULLVOLUME)
234                 snd_vol = 256;
235         else
236                 snd_vol = (int)(volume.value * 256);
237
238         for (i = 0;i < SND_LISTENERS;i++)
239                 vol[i] = ch->listener_volume[i] * snd_vol;
240
241         sb_offset = ch->pos;
242         sb = ch->sfx->fetcher->getsb (ch, &sb_offset, count);
243         if (sb == NULL)
244         {
245                 Con_DPrintf("SND_PaintChannel: ERROR: can't get sound buffer from sfx \"%s\"\n",
246                                         ch->sfx->name, count);
247         }
248         else
249         {
250 #if SND_LISTENERS != 8
251 #               error the following code only supports up to 8 channels, update it
252 #endif
253                 if (sb->format.width == 1)
254                 {
255                         const signed char *samples = (signed char*)sb->samples + (ch->pos - sb_offset) * sb->format.channels;
256
257                         // Stereo sound support
258                         if (sb->format.channels == 2)
259                         {
260                                 if (vol[6] + vol[7] > 0)
261                                 {
262                                         for (i = 0;i < count;i++)
263                                         {
264                                                 paintbuffer[i].sample[0] += (samples[0] * vol[0]) >> 8;
265                                                 paintbuffer[i].sample[1] += (samples[1] * vol[1]) >> 8;
266                                                 paintbuffer[i].sample[2] += (samples[0] * vol[2]) >> 8;
267                                                 paintbuffer[i].sample[3] += (samples[1] * vol[3]) >> 8;
268                                                 paintbuffer[i].sample[4] += ((samples[0] + samples[1]) * vol[4]) >> 9;
269                                                 paintbuffer[i].sample[5] += ((samples[0] + samples[1]) * vol[5]) >> 9;
270                                                 paintbuffer[i].sample[6] += (samples[0] * vol[6]) >> 8;
271                                                 paintbuffer[i].sample[7] += (samples[1] * vol[7]) >> 8;
272                                                 samples += 2;
273                                         }
274                                 }
275                                 else if (vol[4] + vol[5] > 0)
276                                 {
277                                         for (i = 0;i < count;i++)
278                                         {
279                                                 paintbuffer[i].sample[0] += (samples[0] * vol[0]) >> 8;
280                                                 paintbuffer[i].sample[1] += (samples[1] * vol[1]) >> 8;
281                                                 paintbuffer[i].sample[2] += (samples[0] * vol[2]) >> 8;
282                                                 paintbuffer[i].sample[3] += (samples[1] * vol[3]) >> 8;
283                                                 paintbuffer[i].sample[4] += ((samples[0] + samples[1]) * vol[4]) >> 9;
284                                                 paintbuffer[i].sample[5] += ((samples[0] + samples[1]) * vol[5]) >> 9;
285                                                 samples += 2;
286                                         }
287                                 }
288                                 else if (vol[2] + vol[3] > 0)
289                                 {
290                                         for (i = 0;i < count;i++)
291                                         {
292                                                 paintbuffer[i].sample[0] += (samples[0] * vol[0]) >> 8;
293                                                 paintbuffer[i].sample[1] += (samples[1] * vol[1]) >> 8;
294                                                 paintbuffer[i].sample[2] += (samples[0] * vol[2]) >> 8;
295                                                 paintbuffer[i].sample[3] += (samples[1] * vol[3]) >> 8;
296                                                 samples += 2;
297                                         }
298                                 }
299                                 else if (vol[0] + vol[1] > 0)
300                                 {
301                                         for (i = 0;i < count;i++)
302                                         {
303                                                 paintbuffer[i].sample[0] += (samples[0] * vol[0]) >> 8;
304                                                 paintbuffer[i].sample[1] += (samples[1] * vol[1]) >> 8;
305                                                 samples += 2;
306                                         }
307                                 }
308                         }
309                         else if (sb->format.channels == 1)
310                         {
311                                 if (vol[6] + vol[7] > 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[0] * vol[1]) >> 8;
317                                                 paintbuffer[i].sample[2] += (samples[0] * vol[2]) >> 8;
318                                                 paintbuffer[i].sample[3] += (samples[0] * vol[3]) >> 8;
319                                                 paintbuffer[i].sample[4] += (samples[0] * vol[4]) >> 8;
320                                                 paintbuffer[i].sample[5] += (samples[0] * vol[5]) >> 8;
321                                                 paintbuffer[i].sample[6] += (samples[0] * vol[6]) >> 8;
322                                                 paintbuffer[i].sample[7] += (samples[0] * vol[7]) >> 8;
323                                                 samples += 1;
324                                         }
325                                 }
326                                 else if (vol[4] + vol[5] > 0)
327                                 {
328                                         for (i = 0;i < count;i++)
329                                         {
330                                                 paintbuffer[i].sample[0] += (samples[0] * vol[0]) >> 8;
331                                                 paintbuffer[i].sample[1] += (samples[0] * vol[1]) >> 8;
332                                                 paintbuffer[i].sample[2] += (samples[0] * vol[2]) >> 8;
333                                                 paintbuffer[i].sample[3] += (samples[0] * vol[3]) >> 8;
334                                                 paintbuffer[i].sample[4] += (samples[0] * vol[4]) >> 8;
335                                                 paintbuffer[i].sample[5] += (samples[0] * vol[5]) >> 8;
336                                                 samples += 1;
337                                         }
338                                 }
339                                 else if (vol[2] + vol[3] > 0)
340                                 {
341                                         for (i = 0;i < count;i++)
342                                         {
343                                                 paintbuffer[i].sample[0] += (samples[0] * vol[0]) >> 8;
344                                                 paintbuffer[i].sample[1] += (samples[0] * vol[1]) >> 8;
345                                                 paintbuffer[i].sample[2] += (samples[0] * vol[2]) >> 8;
346                                                 paintbuffer[i].sample[3] += (samples[0] * vol[3]) >> 8;
347                                                 samples += 1;
348                                         }
349                                 }
350                                 else if (vol[0] + vol[1] > 0)
351                                 {
352                                         for (i = 0;i < count;i++)
353                                         {
354                                                 paintbuffer[i].sample[0] += (samples[0] * vol[0]) >> 8;
355                                                 paintbuffer[i].sample[1] += (samples[0] * vol[1]) >> 8;
356                                                 samples += 1;
357                                         }
358                                 }
359                         }
360                         else
361                                 return false; // unsupported number of channels in sound
362                 }
363                 else if (sb->format.width == 2)
364                 {
365                         const signed short *samples = (signed short*)sb->samples + (ch->pos - sb_offset) * sb->format.channels;
366
367                         // Stereo sound support
368                         if (sb->format.channels == 2)
369                         {
370                                 if (vol[6] + vol[7] > 0)
371                                 {
372                                         for (i = 0;i < count;i++)
373                                         {
374                                                 paintbuffer[i].sample[0] += (samples[0] * vol[0]) >> 16;
375                                                 paintbuffer[i].sample[1] += (samples[1] * vol[1]) >> 16;
376                                                 paintbuffer[i].sample[2] += (samples[0] * vol[2]) >> 16;
377                                                 paintbuffer[i].sample[3] += (samples[1] * vol[3]) >> 16;
378                                                 paintbuffer[i].sample[4] += ((samples[0] + samples[1]) * vol[4]) >> 17;
379                                                 paintbuffer[i].sample[5] += ((samples[0] + samples[1]) * vol[5]) >> 17;
380                                                 paintbuffer[i].sample[6] += (samples[0] * vol[6]) >> 16;
381                                                 paintbuffer[i].sample[7] += (samples[1] * vol[7]) >> 16;
382                                                 samples += 2;
383                                         }
384                                 }
385                                 else if (vol[4] + vol[5] > 0)
386                                 {
387                                         for (i = 0;i < count;i++)
388                                         {
389                                                 paintbuffer[i].sample[0] += (samples[0] * vol[0]) >> 16;
390                                                 paintbuffer[i].sample[1] += (samples[1] * vol[1]) >> 16;
391                                                 paintbuffer[i].sample[2] += (samples[0] * vol[2]) >> 16;
392                                                 paintbuffer[i].sample[3] += (samples[1] * vol[3]) >> 16;
393                                                 paintbuffer[i].sample[4] += ((samples[0] + samples[1]) * vol[4]) >> 17;
394                                                 paintbuffer[i].sample[5] += ((samples[0] + samples[1]) * vol[5]) >> 17;
395                                                 samples += 2;
396                                         }
397                                 }
398                                 else if (vol[2] + vol[3] > 0)
399                                 {
400                                         for (i = 0;i < count;i++)
401                                         {
402                                                 paintbuffer[i].sample[0] += (samples[0] * vol[0]) >> 16;
403                                                 paintbuffer[i].sample[1] += (samples[1] * vol[1]) >> 16;
404                                                 paintbuffer[i].sample[2] += (samples[0] * vol[2]) >> 16;
405                                                 paintbuffer[i].sample[3] += (samples[1] * vol[3]) >> 16;
406                                                 samples += 2;
407                                         }
408                                 }
409                                 else if (vol[0] + vol[1] > 0)
410                                 {
411                                         for (i = 0;i < count;i++)
412                                         {
413                                                 paintbuffer[i].sample[0] += (samples[0] * vol[0]) >> 16;
414                                                 paintbuffer[i].sample[1] += (samples[1] * vol[1]) >> 16;
415                                                 samples += 2;
416                                         }
417                                 }
418                         }
419                         else if (sb->format.channels == 1)
420                         {
421                                 if (vol[6] + vol[7] > 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[0] * vol[1]) >> 16;
427                                                 paintbuffer[i].sample[2] += (samples[0] * vol[2]) >> 16;
428                                                 paintbuffer[i].sample[3] += (samples[0] * vol[3]) >> 16;
429                                                 paintbuffer[i].sample[4] += (samples[0] * vol[4]) >> 16;
430                                                 paintbuffer[i].sample[5] += (samples[0] * vol[5]) >> 16;
431                                                 paintbuffer[i].sample[6] += (samples[0] * vol[6]) >> 16;
432                                                 paintbuffer[i].sample[7] += (samples[0] * vol[7]) >> 16;
433                                                 samples += 1;
434                                         }
435                                 }
436                                 else if (vol[4] + vol[5] > 0)
437                                 {
438                                         for (i = 0;i < count;i++)
439                                         {
440                                                 paintbuffer[i].sample[0] += (samples[0] * vol[0]) >> 16;
441                                                 paintbuffer[i].sample[1] += (samples[0] * vol[1]) >> 16;
442                                                 paintbuffer[i].sample[2] += (samples[0] * vol[2]) >> 16;
443                                                 paintbuffer[i].sample[3] += (samples[0] * vol[3]) >> 16;
444                                                 paintbuffer[i].sample[4] += (samples[0] * vol[4]) >> 16;
445                                                 paintbuffer[i].sample[5] += (samples[0] * vol[5]) >> 16;
446                                                 samples += 1;
447                                         }
448                                 }
449                                 else if (vol[2] + vol[3] > 0)
450                                 {
451                                         for (i = 0;i < count;i++)
452                                         {
453                                                 paintbuffer[i].sample[0] += (samples[0] * vol[0]) >> 16;
454                                                 paintbuffer[i].sample[1] += (samples[0] * vol[1]) >> 16;
455                                                 paintbuffer[i].sample[2] += (samples[0] * vol[2]) >> 16;
456                                                 paintbuffer[i].sample[3] += (samples[0] * vol[3]) >> 16;
457                                                 samples += 1;
458                                         }
459                                 }
460                                 else if (vol[0] + vol[1] > 0)
461                                 {
462                                         for (i = 0;i < count;i++)
463                                         {
464                                                 paintbuffer[i].sample[0] += (samples[0] * vol[0]) >> 16;
465                                                 paintbuffer[i].sample[1] += (samples[0] * vol[1]) >> 16;
466                                                 samples += 1;
467                                         }
468                                 }
469                         }
470                         else
471                                 return false; // unsupported number of channels in sound
472                 }
473         }
474
475         ch->pos += count;
476         return true;
477 }
478
479 void S_PaintChannels (snd_ringbuffer_t* rb, unsigned int starttime, unsigned int endtime)
480 {
481         unsigned int paintedtime;
482
483         paintedtime = starttime;
484         while (paintedtime < endtime)
485         {
486                 unsigned int partialend, i, framecount;
487                 channel_t *ch;
488
489                 // if paintbuffer is too small
490                 if (endtime > paintedtime + PAINTBUFFER_SIZE)
491                         partialend = paintedtime + PAINTBUFFER_SIZE;
492                 else
493                         partialend = endtime;
494
495                 // clear the paint buffer
496                 memset (paintbuffer, 0, (partialend - paintedtime) * sizeof (paintbuffer[0]));
497
498                 // paint in the channels.
499                 ch = channels;
500                 for (i = 0; i < total_channels ; i++, ch++)
501                 {
502                         sfx_t *sfx;
503                         unsigned int ltime, j;
504
505                         sfx = ch->sfx;
506                         if (sfx == NULL)
507                                 continue;
508                         for (j = 0;j < SND_LISTENERS;j++)
509                                 if (ch->listener_volume[j])
510                                         break;
511                         if (j == SND_LISTENERS)
512                                 continue;
513                         if (!S_LoadSound (sfx, true))
514                                 continue;
515
516                         // if the channel is paused
517                         if (ch->flags & CHANNELFLAG_PAUSED)
518                         {
519                                 int pausedtime = partialend - paintedtime;
520                                 ch->lastptime += pausedtime;
521                                 ch->end += pausedtime;
522                                 continue;
523                         }
524
525                         // if the sound hasn't been painted last time, update his position
526                         if (ch->lastptime < paintedtime)
527                         {
528                                 ch->pos += paintedtime - ch->lastptime;
529
530                                 // If the sound should have ended by then
531                                 if ((unsigned int)ch->pos > sfx->total_length)
532                                 {
533                                         int loopstart;
534
535                                         if (sfx->loopstart >= 0)
536                                                 loopstart = bound(0, sfx->loopstart, (int)sfx->total_length - 1);
537                                         else
538                                         {
539                                                 if (ch->flags & CHANNELFLAG_FORCELOOP)
540                                                         loopstart = 0;
541                                                 else
542                                                         loopstart = -1;
543                                         }
544
545                                         // If the sound is looped
546                                         if (loopstart >= 0)
547                                                 ch->pos = (ch->pos - sfx->total_length) % (sfx->total_length - loopstart) + loopstart;
548                                         else
549                                                 ch->pos = sfx->total_length;
550                                         ch->end = paintedtime + sfx->total_length - ch->pos;
551                                 }
552                         }
553
554                         ltime = paintedtime;
555                         while (ltime < partialend)
556                         {
557                                 int count;
558                                 qboolean stop_paint;
559
560                                 // paint up to end
561                                 if (ch->end < partialend)
562                                         count = ch->end - ltime;
563                                 else
564                                         count = partialend - ltime;
565
566                                 if (count > 0)
567                                 {
568                                         for (j = 0; j < SND_LISTENERS; j++)
569                                                 ch->listener_volume[j] = bound(0, ch->listener_volume[j], 255);
570
571                                         stop_paint = !SND_PaintChannel (ch, (unsigned int)count);
572                                         if (!stop_paint)
573                                         {
574                                                 ltime += count;
575                                                 ch->lastptime = ltime;
576                                         }
577                                 }
578                                 else
579                                         stop_paint = false;
580
581                                 if (ltime >= ch->end)
582                                 {
583                                         // if at end of loop, restart
584                                         if ((sfx->loopstart >= 0 || (ch->flags & CHANNELFLAG_FORCELOOP)) && !stop_paint)
585                                         {
586                                                 ch->pos = bound(0, sfx->loopstart, (int)sfx->total_length - 1);
587                                                 ch->end = ltime + sfx->total_length - ch->pos;
588                                         }
589                                         // channel just stopped
590                                         else
591                                                 stop_paint = true;
592                                 }
593
594                                 if (stop_paint)
595                                 {
596                                         S_StopChannel (ch - channels);
597                                         break;
598                                 }
599                         }
600                 }
601
602                 S_CaptureAVISound (partialend - paintedtime);
603                 framecount = S_TransferPaintBuffer (rb, paintedtime, partialend);
604                 paintedtime += framecount;
605
606                 // If there was not enough free space in the sound buffer, stop here
607                 if (paintedtime != partialend)
608                 {
609                         Con_DPrintf(">> S_PaintChannels: Not enough free space in the sound buffer ( %u != %u)\n", paintedtime, partialend);
610                         break;
611                 }
612         }
613 }