- the Linux sound modules (ALSA and OSS) are now write-based, instead of
[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 // 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                                 if (snd_swapstereo.value)
95                                 {
96                                         for (i = 0; i < nbframes; i++, painted_ptr++)
97                                         {
98                                                 *snd_out++ = bound(-32768, painted_ptr->sample[1], 32767);
99                                                 *snd_out++ = bound(-32768, painted_ptr->sample[0], 32767);
100                                                 *snd_out++ = bound(-32768, painted_ptr->sample[3], 32767);
101                                                 *snd_out++ = bound(-32768, painted_ptr->sample[2], 32767);
102                                                 *snd_out++ = bound(-32768, painted_ptr->sample[4], 32767);
103                                                 *snd_out++ = bound(-32768, painted_ptr->sample[5], 32767);
104                                                 *snd_out++ = bound(-32768, painted_ptr->sample[6], 32767);
105                                                 *snd_out++ = bound(-32768, painted_ptr->sample[7], 32767);
106                                         }
107                                 }
108                                 else
109                                 {
110                                         for (i = 0;i < nbframes;i++, painted_ptr++)
111                                         {
112                                                 *snd_out++ = bound(-32768, painted_ptr->sample[0], 32767);
113                                                 *snd_out++ = bound(-32768, painted_ptr->sample[1], 32767);
114                                                 *snd_out++ = bound(-32768, painted_ptr->sample[2], 32767);
115                                                 *snd_out++ = bound(-32768, painted_ptr->sample[3], 32767);
116                                                 *snd_out++ = bound(-32768, painted_ptr->sample[4], 32767);
117                                                 *snd_out++ = bound(-32768, painted_ptr->sample[5], 32767);
118                                                 *snd_out++ = bound(-32768, painted_ptr->sample[6], 32767);
119                                                 *snd_out++ = bound(-32768, painted_ptr->sample[7], 32767);
120                                         }
121                                 }
122                         }
123                         else if (rb->format.channels == 6)  // 5.1 surround
124                         {
125                                 if (snd_swapstereo.value)
126                                 {
127                                         for (i = 0; i < nbframes; i++, painted_ptr++)
128                                         {
129                                                 *snd_out++ = bound(-32768, painted_ptr->sample[1], 32767);
130                                                 *snd_out++ = bound(-32768, painted_ptr->sample[0], 32767);
131                                                 *snd_out++ = bound(-32768, painted_ptr->sample[3], 32767);
132                                                 *snd_out++ = bound(-32768, painted_ptr->sample[2], 32767);
133                                                 *snd_out++ = bound(-32768, painted_ptr->sample[4], 32767);
134                                                 *snd_out++ = bound(-32768, painted_ptr->sample[5], 32767);
135                                         }
136                                 }
137                                 else
138                                 {
139                                         for (i = 0; i < nbframes; i++, painted_ptr++)
140                                         {
141                                                 *snd_out++ = bound(-32768, painted_ptr->sample[0], 32767);
142                                                 *snd_out++ = bound(-32768, painted_ptr->sample[1], 32767);
143                                                 *snd_out++ = bound(-32768, painted_ptr->sample[2], 32767);
144                                                 *snd_out++ = bound(-32768, painted_ptr->sample[3], 32767);
145                                                 *snd_out++ = bound(-32768, painted_ptr->sample[4], 32767);
146                                                 *snd_out++ = bound(-32768, painted_ptr->sample[5], 32767);
147                                         }
148                                 }
149                         }
150                         else if (rb->format.channels == 4)  // 4.0 surround
151                         {
152                                 if (snd_swapstereo.value)
153                                 {
154                                         for (i = 0; i < nbframes; i++, painted_ptr++)
155                                         {
156                                                 *snd_out++ = bound(-32768, painted_ptr->sample[1], 32767);
157                                                 *snd_out++ = bound(-32768, painted_ptr->sample[0], 32767);
158                                                 *snd_out++ = bound(-32768, painted_ptr->sample[3], 32767);
159                                                 *snd_out++ = bound(-32768, painted_ptr->sample[2], 32767);
160                                         }
161                                 }
162                                 else
163                                 {
164                                         for (i = 0; i < nbframes; i++, painted_ptr++)
165                                         {
166                                                 *snd_out++ = bound(-32768, painted_ptr->sample[0], 32767);
167                                                 *snd_out++ = bound(-32768, painted_ptr->sample[1], 32767);
168                                                 *snd_out++ = bound(-32768, painted_ptr->sample[2], 32767);
169                                                 *snd_out++ = bound(-32768, painted_ptr->sample[3], 32767);
170                                         }
171                                 }
172                         }
173                         else if (rb->format.channels == 2)  // 2.0 stereo
174                         {
175                                 if (snd_swapstereo.value)
176                                 {
177                                         for (i = 0; i < nbframes; i++, painted_ptr++)
178                                         {
179                                                 *snd_out++ = bound(-32768, painted_ptr->sample[1], 32767);
180                                                 *snd_out++ = bound(-32768, painted_ptr->sample[0], 32767);
181                                         }
182                                 }
183                                 else
184                                 {
185                                         for (i = 0; i < nbframes; i++, painted_ptr++)
186                                         {
187                                                 *snd_out++ = bound(-32768, painted_ptr->sample[0], 32767);
188                                                 *snd_out++ = bound(-32768, painted_ptr->sample[1], 32767);
189                                         }
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]) >> 1;
197                                         *snd_out++ = bound(-32768, val, 32767);
198                                 }
199                         }
200                 }
201                 else  // 8bit
202                 {
203                         unsigned char *snd_out = (unsigned char*)rb_ptr;
204                         if (rb->format.channels == 8)  // 7.1 surround
205                         {
206                                 if (snd_swapstereo.value)
207                                 {
208                                         for (i = 0; i < nbframes; i++, painted_ptr++)
209                                         {
210                                                 val = (painted_ptr->sample[1] >> 8) + 128; *snd_out++ = bound(0, val, 255);
211                                                 val = (painted_ptr->sample[0] >> 8) + 128; *snd_out++ = bound(0, val, 255);
212                                                 val = (painted_ptr->sample[3] >> 8) + 128; *snd_out++ = bound(0, val, 255);
213                                                 val = (painted_ptr->sample[2] >> 8) + 128; *snd_out++ = bound(0, val, 255);
214                                                 val = (painted_ptr->sample[4] >> 8) + 128; *snd_out++ = bound(0, val, 255);
215                                                 val = (painted_ptr->sample[5] >> 8) + 128; *snd_out++ = bound(0, val, 255);
216                                                 val = (painted_ptr->sample[6] >> 8) + 128; *snd_out++ = bound(0, val, 255);
217                                                 val = (painted_ptr->sample[7] >> 8) + 128; *snd_out++ = bound(0, val, 255);
218                                         }
219                                 }
220                                 else
221                                 {
222                                         for (i = 0; i < nbframes; i++, painted_ptr++)
223                                         {
224                                                 val = (painted_ptr->sample[0] >> 8) + 128; *snd_out++ = bound(0, val, 255);
225                                                 val = (painted_ptr->sample[1] >> 8) + 128; *snd_out++ = bound(0, val, 255);
226                                                 val = (painted_ptr->sample[2] >> 8) + 128; *snd_out++ = bound(0, val, 255);
227                                                 val = (painted_ptr->sample[3] >> 8) + 128; *snd_out++ = bound(0, val, 255);
228                                                 val = (painted_ptr->sample[4] >> 8) + 128; *snd_out++ = bound(0, val, 255);
229                                                 val = (painted_ptr->sample[5] >> 8) + 128; *snd_out++ = bound(0, val, 255);
230                                                 val = (painted_ptr->sample[6] >> 8) + 128; *snd_out++ = bound(0, val, 255);
231                                                 val = (painted_ptr->sample[7] >> 8) + 128; *snd_out++ = bound(0, val, 255);
232                                         }
233                                 }
234                         }
235                         else if (rb->format.channels == 6)  // 5.1 surround
236                         {
237                                 if (snd_swapstereo.value)
238                                 {
239                                         for (i = 0; i < nbframes; i++, painted_ptr++)
240                                         {
241                                                 val = (painted_ptr->sample[1] >> 8) + 128; *snd_out++ = bound(0, val, 255);
242                                                 val = (painted_ptr->sample[0] >> 8) + 128; *snd_out++ = bound(0, val, 255);
243                                                 val = (painted_ptr->sample[3] >> 8) + 128; *snd_out++ = bound(0, val, 255);
244                                                 val = (painted_ptr->sample[2] >> 8) + 128; *snd_out++ = bound(0, val, 255);
245                                                 val = (painted_ptr->sample[4] >> 8) + 128; *snd_out++ = bound(0, val, 255);
246                                                 val = (painted_ptr->sample[5] >> 8) + 128; *snd_out++ = bound(0, val, 255);
247                                         }
248                                 }
249                                 else
250                                 {
251                                         for (i = 0; i < nbframes; i++, painted_ptr++)
252                                         {
253                                                 val = (painted_ptr->sample[0] >> 8) + 128; *snd_out++ = bound(0, val, 255);
254                                                 val = (painted_ptr->sample[1] >> 8) + 128; *snd_out++ = bound(0, val, 255);
255                                                 val = (painted_ptr->sample[2] >> 8) + 128; *snd_out++ = bound(0, val, 255);
256                                                 val = (painted_ptr->sample[3] >> 8) + 128; *snd_out++ = bound(0, val, 255);
257                                                 val = (painted_ptr->sample[4] >> 8) + 128; *snd_out++ = bound(0, val, 255);
258                                                 val = (painted_ptr->sample[5] >> 8) + 128; *snd_out++ = bound(0, val, 255);
259                                         }
260                                 }
261                         }
262                         else if (rb->format.channels == 4)  // 4.0 surround
263                         {
264                                 if (snd_swapstereo.value)
265                                 {
266                                         for (i = 0; i < nbframes; i++, painted_ptr++)
267                                         {
268                                                 val = (painted_ptr->sample[1] >> 8) + 128; *snd_out++ = bound(0, val, 255);
269                                                 val = (painted_ptr->sample[0] >> 8) + 128; *snd_out++ = bound(0, val, 255);
270                                                 val = (painted_ptr->sample[3] >> 8) + 128; *snd_out++ = bound(0, val, 255);
271                                                 val = (painted_ptr->sample[2] >> 8) + 128; *snd_out++ = bound(0, val, 255);
272                                         }
273                                 }
274                                 else
275                                 {
276                                         for (i = 0; i < nbframes; i++, painted_ptr++)
277                                         {
278                                                 val = (painted_ptr->sample[0] >> 8) + 128; *snd_out++ = bound(0, val, 255);
279                                                 val = (painted_ptr->sample[1] >> 8) + 128; *snd_out++ = bound(0, val, 255);
280                                                 val = (painted_ptr->sample[2] >> 8) + 128; *snd_out++ = bound(0, val, 255);
281                                                 val = (painted_ptr->sample[3] >> 8) + 128; *snd_out++ = bound(0, val, 255);
282                                         }
283                                 }
284                         }
285                         else if (rb->format.channels == 2)  // 2.0 stereo
286                         {
287                                 if (snd_swapstereo.value)
288                                 {
289                                         for (i = 0; i < nbframes; i++, painted_ptr++)
290                                         {
291                                                 val = (painted_ptr->sample[1] >> 8) + 128; *snd_out++ = bound(0, val, 255);
292                                                 val = (painted_ptr->sample[0] >> 8) + 128; *snd_out++ = bound(0, val, 255);
293                                         }
294                                 }
295                                 else
296                                 {
297                                         for (i = 0; i < nbframes; i++, painted_ptr++)
298                                         {
299                                                 val = (painted_ptr->sample[0] >> 8) + 128; *snd_out++ = bound(0, val, 255);
300                                                 val = (painted_ptr->sample[1] >> 8) + 128; *snd_out++ = bound(0, val, 255);
301                                         }
302                                 }
303                         }
304                         else if (rb->format.channels == 1)  // 1.0 mono
305                         {
306                                 for (i = 0;i < nbframes;i++, painted_ptr++)
307                                 {
308                                         val = ((painted_ptr->sample[0] + painted_ptr->sample[1]) >> 9) + 128;
309                                         *snd_out++ = bound(0, val, 255);
310                                 }
311                         }
312                 }
313
314                 partialend += nbframes;
315         }
316
317         rb->endframe = endtime;
318
319         // Remove outdated samples from the ring buffer, if any
320         if (rb->startframe < soundtime)
321                 rb->startframe = soundtime;
322
323         if (!simsound)
324                 SndSys_UnlockRenderBuffer();
325
326         return endtime - starttime;
327 }
328
329
330 /*
331 ===============================================================================
332
333 CHANNEL MIXING
334
335 ===============================================================================
336 */
337
338 static qboolean SND_PaintChannel (channel_t *ch, unsigned int count)
339 {
340         int snd_vol, vol[SND_LISTENERS];
341         const snd_buffer_t *sb;
342         unsigned int i, sb_offset;
343
344         // If this channel manages its own volume
345         if (ch->flags & CHANNELFLAG_FULLVOLUME)
346                 snd_vol = 256;
347         else
348                 snd_vol = (int)(volume.value * 256);
349
350         for (i = 0;i < SND_LISTENERS;i++)
351                 vol[i] = ch->listener_volume[i] * snd_vol;
352
353         sb_offset = ch->pos;
354         sb = ch->sfx->fetcher->getsb (ch, &sb_offset, count);
355         if (sb == NULL)
356         {
357                 Con_DPrintf("SND_PaintChannel: ERROR: can't get sound buffer from sfx \"%s\"\n",
358                                         ch->sfx->name, count);
359         }
360         else
361         {
362 #if SND_LISTENERS != 8
363 #               error the following code only supports up to 8 channels, update it
364 #endif
365                 if (sb->format.width == 1)
366                 {
367                         const signed char *samples = (signed char*)sb->samples + (ch->pos - sb_offset) * sb->format.channels;
368
369                         // Stereo sound support
370                         if (sb->format.channels == 2)
371                         {
372                                 if (vol[6] + vol[7] > 0)
373                                 {
374                                         for (i = 0;i < count;i++)
375                                         {
376                                                 paintbuffer[i].sample[0] += (samples[0] * vol[0]) >> 8;
377                                                 paintbuffer[i].sample[1] += (samples[1] * vol[1]) >> 8;
378                                                 paintbuffer[i].sample[2] += (samples[0] * vol[2]) >> 8;
379                                                 paintbuffer[i].sample[3] += (samples[1] * vol[3]) >> 8;
380                                                 paintbuffer[i].sample[4] += ((samples[0] + samples[1]) * vol[4]) >> 9;
381                                                 paintbuffer[i].sample[5] += ((samples[0] + samples[1]) * vol[5]) >> 9;
382                                                 paintbuffer[i].sample[6] += (samples[0] * vol[6]) >> 8;
383                                                 paintbuffer[i].sample[7] += (samples[1] * vol[7]) >> 8;
384                                                 samples += 2;
385                                         }
386                                 }
387                                 else if (vol[4] + vol[5] > 0)
388                                 {
389                                         for (i = 0;i < count;i++)
390                                         {
391                                                 paintbuffer[i].sample[0] += (samples[0] * vol[0]) >> 8;
392                                                 paintbuffer[i].sample[1] += (samples[1] * vol[1]) >> 8;
393                                                 paintbuffer[i].sample[2] += (samples[0] * vol[2]) >> 8;
394                                                 paintbuffer[i].sample[3] += (samples[1] * vol[3]) >> 8;
395                                                 paintbuffer[i].sample[4] += ((samples[0] + samples[1]) * vol[4]) >> 9;
396                                                 paintbuffer[i].sample[5] += ((samples[0] + samples[1]) * vol[5]) >> 9;
397                                                 samples += 2;
398                                         }
399                                 }
400                                 else if (vol[2] + vol[3] > 0)
401                                 {
402                                         for (i = 0;i < count;i++)
403                                         {
404                                                 paintbuffer[i].sample[0] += (samples[0] * vol[0]) >> 8;
405                                                 paintbuffer[i].sample[1] += (samples[1] * vol[1]) >> 8;
406                                                 paintbuffer[i].sample[2] += (samples[0] * vol[2]) >> 8;
407                                                 paintbuffer[i].sample[3] += (samples[1] * vol[3]) >> 8;
408                                                 samples += 2;
409                                         }
410                                 }
411                                 else if (vol[0] + vol[1] > 0)
412                                 {
413                                         for (i = 0;i < count;i++)
414                                         {
415                                                 paintbuffer[i].sample[0] += (samples[0] * vol[0]) >> 8;
416                                                 paintbuffer[i].sample[1] += (samples[1] * vol[1]) >> 8;
417                                                 samples += 2;
418                                         }
419                                 }
420                         }
421                         else if (sb->format.channels == 1)
422                         {
423                                 if (vol[6] + vol[7] > 0)
424                                 {
425                                         for (i = 0;i < count;i++)
426                                         {
427                                                 paintbuffer[i].sample[0] += (samples[0] * vol[0]) >> 8;
428                                                 paintbuffer[i].sample[1] += (samples[0] * vol[1]) >> 8;
429                                                 paintbuffer[i].sample[2] += (samples[0] * vol[2]) >> 8;
430                                                 paintbuffer[i].sample[3] += (samples[0] * vol[3]) >> 8;
431                                                 paintbuffer[i].sample[4] += (samples[0] * vol[4]) >> 8;
432                                                 paintbuffer[i].sample[5] += (samples[0] * vol[5]) >> 8;
433                                                 paintbuffer[i].sample[6] += (samples[0] * vol[6]) >> 8;
434                                                 paintbuffer[i].sample[7] += (samples[0] * vol[7]) >> 8;
435                                                 samples += 1;
436                                         }
437                                 }
438                                 else if (vol[4] + vol[5] > 0)
439                                 {
440                                         for (i = 0;i < count;i++)
441                                         {
442                                                 paintbuffer[i].sample[0] += (samples[0] * vol[0]) >> 8;
443                                                 paintbuffer[i].sample[1] += (samples[0] * vol[1]) >> 8;
444                                                 paintbuffer[i].sample[2] += (samples[0] * vol[2]) >> 8;
445                                                 paintbuffer[i].sample[3] += (samples[0] * vol[3]) >> 8;
446                                                 paintbuffer[i].sample[4] += (samples[0] * vol[4]) >> 8;
447                                                 paintbuffer[i].sample[5] += (samples[0] * vol[5]) >> 8;
448                                                 samples += 1;
449                                         }
450                                 }
451                                 else if (vol[2] + vol[3] > 0)
452                                 {
453                                         for (i = 0;i < count;i++)
454                                         {
455                                                 paintbuffer[i].sample[0] += (samples[0] * vol[0]) >> 8;
456                                                 paintbuffer[i].sample[1] += (samples[0] * vol[1]) >> 8;
457                                                 paintbuffer[i].sample[2] += (samples[0] * vol[2]) >> 8;
458                                                 paintbuffer[i].sample[3] += (samples[0] * vol[3]) >> 8;
459                                                 samples += 1;
460                                         }
461                                 }
462                                 else if (vol[0] + vol[1] > 0)
463                                 {
464                                         for (i = 0;i < count;i++)
465                                         {
466                                                 paintbuffer[i].sample[0] += (samples[0] * vol[0]) >> 8;
467                                                 paintbuffer[i].sample[1] += (samples[0] * vol[1]) >> 8;
468                                                 samples += 1;
469                                         }
470                                 }
471                         }
472                         else
473                                 return false; // unsupported number of channels in sound
474                 }
475                 else if (sb->format.width == 2)
476                 {
477                         const signed short *samples = (signed short*)sb->samples + (ch->pos - sb_offset) * sb->format.channels;
478
479                         // Stereo sound support
480                         if (sb->format.channels == 2)
481                         {
482                                 if (vol[6] + vol[7] > 0)
483                                 {
484                                         for (i = 0;i < count;i++)
485                                         {
486                                                 paintbuffer[i].sample[0] += (samples[0] * vol[0]) >> 16;
487                                                 paintbuffer[i].sample[1] += (samples[1] * vol[1]) >> 16;
488                                                 paintbuffer[i].sample[2] += (samples[0] * vol[2]) >> 16;
489                                                 paintbuffer[i].sample[3] += (samples[1] * vol[3]) >> 16;
490                                                 paintbuffer[i].sample[4] += ((samples[0] + samples[1]) * vol[4]) >> 17;
491                                                 paintbuffer[i].sample[5] += ((samples[0] + samples[1]) * vol[5]) >> 17;
492                                                 paintbuffer[i].sample[6] += (samples[0] * vol[6]) >> 16;
493                                                 paintbuffer[i].sample[7] += (samples[1] * vol[7]) >> 16;
494                                                 samples += 2;
495                                         }
496                                 }
497                                 else if (vol[4] + vol[5] > 0)
498                                 {
499                                         for (i = 0;i < count;i++)
500                                         {
501                                                 paintbuffer[i].sample[0] += (samples[0] * vol[0]) >> 16;
502                                                 paintbuffer[i].sample[1] += (samples[1] * vol[1]) >> 16;
503                                                 paintbuffer[i].sample[2] += (samples[0] * vol[2]) >> 16;
504                                                 paintbuffer[i].sample[3] += (samples[1] * vol[3]) >> 16;
505                                                 paintbuffer[i].sample[4] += ((samples[0] + samples[1]) * vol[4]) >> 17;
506                                                 paintbuffer[i].sample[5] += ((samples[0] + samples[1]) * vol[5]) >> 17;
507                                                 samples += 2;
508                                         }
509                                 }
510                                 else if (vol[2] + vol[3] > 0)
511                                 {
512                                         for (i = 0;i < count;i++)
513                                         {
514                                                 paintbuffer[i].sample[0] += (samples[0] * vol[0]) >> 16;
515                                                 paintbuffer[i].sample[1] += (samples[1] * vol[1]) >> 16;
516                                                 paintbuffer[i].sample[2] += (samples[0] * vol[2]) >> 16;
517                                                 paintbuffer[i].sample[3] += (samples[1] * vol[3]) >> 16;
518                                                 samples += 2;
519                                         }
520                                 }
521                                 else if (vol[0] + vol[1] > 0)
522                                 {
523                                         for (i = 0;i < count;i++)
524                                         {
525                                                 paintbuffer[i].sample[0] += (samples[0] * vol[0]) >> 16;
526                                                 paintbuffer[i].sample[1] += (samples[1] * vol[1]) >> 16;
527                                                 samples += 2;
528                                         }
529                                 }
530                         }
531                         else if (sb->format.channels == 1)
532                         {
533                                 if (vol[6] + vol[7] > 0)
534                                 {
535                                         for (i = 0;i < count;i++)
536                                         {
537                                                 paintbuffer[i].sample[0] += (samples[0] * vol[0]) >> 16;
538                                                 paintbuffer[i].sample[1] += (samples[0] * vol[1]) >> 16;
539                                                 paintbuffer[i].sample[2] += (samples[0] * vol[2]) >> 16;
540                                                 paintbuffer[i].sample[3] += (samples[0] * vol[3]) >> 16;
541                                                 paintbuffer[i].sample[4] += (samples[0] * vol[4]) >> 16;
542                                                 paintbuffer[i].sample[5] += (samples[0] * vol[5]) >> 16;
543                                                 paintbuffer[i].sample[6] += (samples[0] * vol[6]) >> 16;
544                                                 paintbuffer[i].sample[7] += (samples[0] * vol[7]) >> 16;
545                                                 samples += 1;
546                                         }
547                                 }
548                                 else if (vol[4] + vol[5] > 0)
549                                 {
550                                         for (i = 0;i < count;i++)
551                                         {
552                                                 paintbuffer[i].sample[0] += (samples[0] * vol[0]) >> 16;
553                                                 paintbuffer[i].sample[1] += (samples[0] * vol[1]) >> 16;
554                                                 paintbuffer[i].sample[2] += (samples[0] * vol[2]) >> 16;
555                                                 paintbuffer[i].sample[3] += (samples[0] * vol[3]) >> 16;
556                                                 paintbuffer[i].sample[4] += (samples[0] * vol[4]) >> 16;
557                                                 paintbuffer[i].sample[5] += (samples[0] * vol[5]) >> 16;
558                                                 samples += 1;
559                                         }
560                                 }
561                                 else if (vol[2] + vol[3] > 0)
562                                 {
563                                         for (i = 0;i < count;i++)
564                                         {
565                                                 paintbuffer[i].sample[0] += (samples[0] * vol[0]) >> 16;
566                                                 paintbuffer[i].sample[1] += (samples[0] * vol[1]) >> 16;
567                                                 paintbuffer[i].sample[2] += (samples[0] * vol[2]) >> 16;
568                                                 paintbuffer[i].sample[3] += (samples[0] * vol[3]) >> 16;
569                                                 samples += 1;
570                                         }
571                                 }
572                                 else if (vol[0] + vol[1] > 0)
573                                 {
574                                         for (i = 0;i < count;i++)
575                                         {
576                                                 paintbuffer[i].sample[0] += (samples[0] * vol[0]) >> 16;
577                                                 paintbuffer[i].sample[1] += (samples[0] * vol[1]) >> 16;
578                                                 samples += 1;
579                                         }
580                                 }
581                         }
582                         else
583                                 return false; // unsupported number of channels in sound
584                 }
585         }
586
587         ch->pos += count;
588         return true;
589 }
590
591 void S_PaintChannels (snd_ringbuffer_t* rb, unsigned int starttime, unsigned int endtime)
592 {
593         unsigned int paintedtime;
594
595         paintedtime = starttime;
596         while (paintedtime < endtime)
597         {
598                 unsigned int partialend, i, framecount;
599                 channel_t *ch;
600
601                 // if paintbuffer is too small
602                 if (endtime > paintedtime + PAINTBUFFER_SIZE)
603                         partialend = paintedtime + PAINTBUFFER_SIZE;
604                 else
605                         partialend = endtime;
606
607                 // clear the paint buffer
608                 memset (paintbuffer, 0, (partialend - paintedtime) * sizeof (paintbuffer[0]));
609
610                 // paint in the channels.
611                 ch = channels;
612                 for (i = 0; i < total_channels ; i++, ch++)
613                 {
614                         sfx_t *sfx;
615                         unsigned int ltime, j;
616
617                         sfx = ch->sfx;
618                         if (sfx == NULL)
619                                 continue;
620                         for (j = 0;j < SND_LISTENERS;j++)
621                                 if (ch->listener_volume[j])
622                                         break;
623                         if (j == SND_LISTENERS)
624                                 continue;
625                         if (!S_LoadSound (sfx, true))
626                                 continue;
627
628                         // if the channel is paused
629                         if (ch->flags & CHANNELFLAG_PAUSED)
630                         {
631                                 int pausedtime = partialend - paintedtime;
632                                 ch->lastptime += pausedtime;
633                                 ch->end += pausedtime;
634                                 continue;
635                         }
636
637                         // if the sound hasn't been painted last time, update his position
638                         if (ch->lastptime < paintedtime)
639                         {
640                                 ch->pos += paintedtime - ch->lastptime;
641
642                                 // If the sound should have ended by then
643                                 if ((unsigned int)ch->pos > sfx->total_length)
644                                 {
645                                         int loopstart;
646
647                                         if (sfx->loopstart >= 0)
648                                                 loopstart = bound(0, sfx->loopstart, (int)sfx->total_length - 1);
649                                         else
650                                         {
651                                                 if (ch->flags & CHANNELFLAG_FORCELOOP)
652                                                         loopstart = 0;
653                                                 else
654                                                         loopstart = -1;
655                                         }
656
657                                         // If the sound is looped
658                                         if (loopstart >= 0)
659                                                 ch->pos = (ch->pos - sfx->total_length) % (sfx->total_length - loopstart) + loopstart;
660                                         else
661                                                 ch->pos = sfx->total_length;
662                                         ch->end = paintedtime + sfx->total_length - ch->pos;
663                                 }
664                         }
665
666                         ltime = paintedtime;
667                         while (ltime < partialend)
668                         {
669                                 int count;
670                                 qboolean stop_paint;
671
672                                 // paint up to end
673                                 if (ch->end < partialend)
674                                         count = ch->end - ltime;
675                                 else
676                                         count = partialend - ltime;
677
678                                 if (count > 0)
679                                 {
680                                         for (j = 0; j < SND_LISTENERS; j++)
681                                                 ch->listener_volume[j] = bound(0, ch->listener_volume[j], 255);
682
683                                         stop_paint = !SND_PaintChannel (ch, (unsigned int)count);
684                                         if (!stop_paint)
685                                         {
686                                                 ltime += count;
687                                                 ch->lastptime = ltime;
688                                         }
689                                 }
690                                 else
691                                         stop_paint = false;
692
693                                 if (ltime >= ch->end)
694                                 {
695                                         // if at end of loop, restart
696                                         if ((sfx->loopstart >= 0 || (ch->flags & CHANNELFLAG_FORCELOOP)) && !stop_paint)
697                                         {
698                                                 ch->pos = bound(0, sfx->loopstart, (int)sfx->total_length - 1);
699                                                 ch->end = ltime + sfx->total_length - ch->pos;
700                                         }
701                                         // channel just stopped
702                                         else
703                                                 stop_paint = true;
704                                 }
705
706                                 if (stop_paint)
707                                 {
708                                         S_StopChannel (ch - channels);
709                                         break;
710                                 }
711                         }
712                 }
713
714                 S_CaptureAVISound (partialend - paintedtime);
715                 framecount = S_TransferPaintBuffer (rb, paintedtime, partialend);
716                 paintedtime += framecount;
717
718                 // If there was not enough free space in the sound buffer, stop here
719                 if (paintedtime != partialend)
720                 {
721                         Con_DPrintf(">> S_PaintChannels: Not enough free space in the sound buffer ( %u != %u)\n", paintedtime, partialend);
722                         break;
723                 }
724         }
725 }