]> git.xonotic.org Git - xonotic/darkplaces.git/blob - snd_mix.c
Underwater sound filter: fix warning and code style, add function docstring
[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 extern cvar_t snd_softclip;
25
26 static portable_sampleframe_t paintbuffer[PAINTBUFFER_SIZE];
27
28 extern speakerlayout_t snd_speakerlayout; // for querying the listeners
29
30 #ifdef CONFIG_VIDEO_CAPTURE
31 static portable_sampleframe_t paintbuffer_unswapped[PAINTBUFFER_SIZE];
32
33 static void S_CaptureAVISound(const portable_sampleframe_t *sampleframes, size_t length)
34 {
35         size_t i;
36         unsigned int j;
37
38         if (!cls.capturevideo.active)
39                 return;
40
41         // undo whatever swapping the channel layout (swapstereo, ALSA) did
42         for(j = 0; j < snd_speakerlayout.channels; ++j)
43         {
44                 unsigned int j0 = snd_speakerlayout.listeners[j].channel_unswapped;
45                 for(i = 0; i < length; ++i)
46                         paintbuffer_unswapped[i].sample[j0] = sampleframes[i].sample[j];
47         }
48
49         SCR_CaptureVideo_SoundFrame(paintbuffer_unswapped, length);
50 }
51 #endif
52
53 extern cvar_t snd_softclip;
54
55 static void S_SoftClipPaintBuffer(portable_sampleframe_t *painted_ptr, int nbframes, int width, int nchannels)
56 {
57         int i;
58
59         if((snd_softclip.integer == 1 && width <= 2) || snd_softclip.integer > 1)
60         {
61                 portable_sampleframe_t *p = painted_ptr;
62
63 #if 0
64 /* Soft clipping, the sound of a dream, thanks to Jon Wattes
65    post to Musicdsp.org */
66 #define SOFTCLIP(x) (x) = sin(bound(-M_PI/2, (x), M_PI/2)) * 0.25
67 #endif
68
69                 // let's do a simple limiter instead, seems to sound better
70                 static float maxvol = 0;
71                 maxvol = max(1.0f, maxvol * (1.0f - nbframes / (0.4f * snd_renderbuffer->format.speed)));
72 #define SOFTCLIP(x) if(fabs(x)>maxvol) maxvol=fabs(x); (x) /= maxvol;
73
74                 if (nchannels == 8)  // 7.1 surround
75                 {
76                         for (i = 0;i < nbframes;i++, p++)
77                         {
78                                 SOFTCLIP(p->sample[0]);
79                                 SOFTCLIP(p->sample[1]);
80                                 SOFTCLIP(p->sample[2]);
81                                 SOFTCLIP(p->sample[3]);
82                                 SOFTCLIP(p->sample[4]);
83                                 SOFTCLIP(p->sample[5]);
84                                 SOFTCLIP(p->sample[6]);
85                                 SOFTCLIP(p->sample[7]);
86                         }
87                 }
88                 else if (nchannels == 6)  // 5.1 surround
89                 {
90                         for (i = 0; i < nbframes; i++, p++)
91                         {
92                                 SOFTCLIP(p->sample[0]);
93                                 SOFTCLIP(p->sample[1]);
94                                 SOFTCLIP(p->sample[2]);
95                                 SOFTCLIP(p->sample[3]);
96                                 SOFTCLIP(p->sample[4]);
97                                 SOFTCLIP(p->sample[5]);
98                         }
99                 }
100                 else if (nchannels == 4)  // 4.0 surround
101                 {
102                         for (i = 0; i < nbframes; i++, p++)
103                         {
104                                 SOFTCLIP(p->sample[0]);
105                                 SOFTCLIP(p->sample[1]);
106                                 SOFTCLIP(p->sample[2]);
107                                 SOFTCLIP(p->sample[3]);
108                         }
109                 }
110                 else if (nchannels == 2)  // 2.0 stereo
111                 {
112                         for (i = 0; i < nbframes; i++, p++)
113                         {
114                                 SOFTCLIP(p->sample[0]);
115                                 SOFTCLIP(p->sample[1]);
116                         }
117                 }
118                 else if (nchannels == 1)  // 1.0 mono
119                 {
120                         for (i = 0; i < nbframes; i++, p++)
121                         {
122                                 SOFTCLIP(p->sample[0]);
123                         }
124                 }
125 #undef SOFTCLIP
126         }
127 }
128
129 static void S_ConvertPaintBuffer(portable_sampleframe_t *painted_ptr, void *rb_ptr, int nbframes, int width, int nchannels)
130 {
131         int i;
132         float val;
133         if (width == 4)  // 32bit float
134         {
135                 float *snd_out = (float*)rb_ptr;
136                 if (nchannels == 8)  // 7.1 surround
137                 {
138                         for (i = 0; i < nbframes; i++, painted_ptr++)
139                         {
140                                 *snd_out++ = painted_ptr->sample[0];
141                                 *snd_out++ = painted_ptr->sample[1];
142                                 *snd_out++ = painted_ptr->sample[2];
143                                 *snd_out++ = painted_ptr->sample[3];
144                                 *snd_out++ = painted_ptr->sample[4];
145                                 *snd_out++ = painted_ptr->sample[5];
146                                 *snd_out++ = painted_ptr->sample[6];
147                                 *snd_out++ = painted_ptr->sample[7];
148                         }
149                 }
150                 else if (nchannels == 6)  // 5.1 surround
151                 {
152                         for (i = 0; i < nbframes; i++, painted_ptr++)
153                         {
154                                 *snd_out++ = painted_ptr->sample[0];
155                                 *snd_out++ = painted_ptr->sample[1];
156                                 *snd_out++ = painted_ptr->sample[2];
157                                 *snd_out++ = painted_ptr->sample[3];
158                                 *snd_out++ = painted_ptr->sample[4];
159                                 *snd_out++ = painted_ptr->sample[5];
160                         }
161                 }
162                 else if (nchannels == 4)  // 4.0 surround
163                 {
164                         for (i = 0; i < nbframes; i++, painted_ptr++)
165                         {
166                                 *snd_out++ = painted_ptr->sample[0];
167                                 *snd_out++ = painted_ptr->sample[1];
168                                 *snd_out++ = painted_ptr->sample[2];
169                                 *snd_out++ = painted_ptr->sample[3];
170                         }
171                 }
172                 else if (nchannels == 2)  // 2.0 stereo
173                 {
174                         for (i = 0; i < nbframes; i++, painted_ptr++)
175                         {
176                                 *snd_out++ = painted_ptr->sample[0];
177                                 *snd_out++ = painted_ptr->sample[1];
178                         }
179                 }
180                 else if (nchannels == 1)  // 1.0 mono
181                 {
182                         for (i = 0; i < nbframes; i++, painted_ptr++)
183                         {
184                                 *snd_out++ = painted_ptr->sample[0];
185                         }
186                 }
187
188                 // noise is really really annoying
189                 if (cls.timedemo)
190                         memset(rb_ptr, 0, nbframes * nchannels * width);
191         }
192         else if (width == 2)  // 16bit
193         {
194                 short *snd_out = (short*)rb_ptr;
195                 if (nchannels == 8)  // 7.1 surround
196                 {
197                         for (i = 0;i < nbframes;i++, painted_ptr++)
198                         {
199                                 val = (int)(painted_ptr->sample[0] * 32768.0f);*snd_out++ = bound(-32768, val, 32767);
200                                 val = (int)(painted_ptr->sample[1] * 32768.0f);*snd_out++ = bound(-32768, val, 32767);
201                                 val = (int)(painted_ptr->sample[2] * 32768.0f);*snd_out++ = bound(-32768, val, 32767);
202                                 val = (int)(painted_ptr->sample[3] * 32768.0f);*snd_out++ = bound(-32768, val, 32767);
203                                 val = (int)(painted_ptr->sample[4] * 32768.0f);*snd_out++ = bound(-32768, val, 32767);
204                                 val = (int)(painted_ptr->sample[5] * 32768.0f);*snd_out++ = bound(-32768, val, 32767);
205                                 val = (int)(painted_ptr->sample[6] * 32768.0f);*snd_out++ = bound(-32768, val, 32767);
206                                 val = (int)(painted_ptr->sample[7] * 32768.0f);*snd_out++ = bound(-32768, val, 32767);
207                         }
208                 }
209                 else if (nchannels == 6)  // 5.1 surround
210                 {
211                         for (i = 0; i < nbframes; i++, painted_ptr++)
212                         {
213                                 val = (int)(painted_ptr->sample[0] * 32768.0f);*snd_out++ = bound(-32768, val, 32767);
214                                 val = (int)(painted_ptr->sample[1] * 32768.0f);*snd_out++ = bound(-32768, val, 32767);
215                                 val = (int)(painted_ptr->sample[2] * 32768.0f);*snd_out++ = bound(-32768, val, 32767);
216                                 val = (int)(painted_ptr->sample[3] * 32768.0f);*snd_out++ = bound(-32768, val, 32767);
217                                 val = (int)(painted_ptr->sample[4] * 32768.0f);*snd_out++ = bound(-32768, val, 32767);
218                                 val = (int)(painted_ptr->sample[5] * 32768.0f);*snd_out++ = bound(-32768, val, 32767);
219                         }
220                 }
221                 else if (nchannels == 4)  // 4.0 surround
222                 {
223                         for (i = 0; i < nbframes; i++, painted_ptr++)
224                         {
225                                 val = (int)(painted_ptr->sample[0] * 32768.0f);*snd_out++ = bound(-32768, val, 32767);
226                                 val = (int)(painted_ptr->sample[1] * 32768.0f);*snd_out++ = bound(-32768, val, 32767);
227                                 val = (int)(painted_ptr->sample[2] * 32768.0f);*snd_out++ = bound(-32768, val, 32767);
228                                 val = (int)(painted_ptr->sample[3] * 32768.0f);*snd_out++ = bound(-32768, val, 32767);
229                         }
230                 }
231                 else if (nchannels == 2)  // 2.0 stereo
232                 {
233                         for (i = 0; i < nbframes; i++, painted_ptr++)
234                         {
235                                 val = (int)(painted_ptr->sample[0] * 32768.0f);*snd_out++ = bound(-32768, val, 32767);
236                                 val = (int)(painted_ptr->sample[1] * 32768.0f);*snd_out++ = bound(-32768, val, 32767);
237                         }
238                 }
239                 else if (nchannels == 1)  // 1.0 mono
240                 {
241                         for (i = 0; i < nbframes; i++, painted_ptr++)
242                         {
243                                 val = (int)((painted_ptr->sample[0] + painted_ptr->sample[1]) * 16384.0f);*snd_out++ = bound(-32768, val, 32767);
244                         }
245                 }
246
247                 // noise is really really annoying
248                 if (cls.timedemo)
249                         memset(rb_ptr, 0, nbframes * nchannels * width);
250         }
251         else  // 8bit
252         {
253                 unsigned char *snd_out = (unsigned char*)rb_ptr;
254                 if (nchannels == 8)  // 7.1 surround
255                 {
256                         for (i = 0; i < nbframes; i++, painted_ptr++)
257                         {
258                                 val = (int)(painted_ptr->sample[0] * 128.0f) + 128; *snd_out++ = bound(0, val, 255);
259                                 val = (int)(painted_ptr->sample[1] * 128.0f) + 128; *snd_out++ = bound(0, val, 255);
260                                 val = (int)(painted_ptr->sample[2] * 128.0f) + 128; *snd_out++ = bound(0, val, 255);
261                                 val = (int)(painted_ptr->sample[3] * 128.0f) + 128; *snd_out++ = bound(0, val, 255);
262                                 val = (int)(painted_ptr->sample[4] * 128.0f) + 128; *snd_out++ = bound(0, val, 255);
263                                 val = (int)(painted_ptr->sample[5] * 128.0f) + 128; *snd_out++ = bound(0, val, 255);
264                                 val = (int)(painted_ptr->sample[6] * 128.0f) + 128; *snd_out++ = bound(0, val, 255);
265                                 val = (int)(painted_ptr->sample[7] * 128.0f) + 128; *snd_out++ = bound(0, val, 255);
266                         }
267                 }
268                 else if (nchannels == 6)  // 5.1 surround
269                 {
270                         for (i = 0; i < nbframes; i++, painted_ptr++)
271                         {
272                                 val = (int)(painted_ptr->sample[0] * 128.0f) + 128; *snd_out++ = bound(0, val, 255);
273                                 val = (int)(painted_ptr->sample[1] * 128.0f) + 128; *snd_out++ = bound(0, val, 255);
274                                 val = (int)(painted_ptr->sample[2] * 128.0f) + 128; *snd_out++ = bound(0, val, 255);
275                                 val = (int)(painted_ptr->sample[3] * 128.0f) + 128; *snd_out++ = bound(0, val, 255);
276                                 val = (int)(painted_ptr->sample[4] * 128.0f) + 128; *snd_out++ = bound(0, val, 255);
277                                 val = (int)(painted_ptr->sample[5] * 128.0f) + 128; *snd_out++ = bound(0, val, 255);
278                         }
279                 }
280                 else if (nchannels == 4)  // 4.0 surround
281                 {
282                         for (i = 0; i < nbframes; i++, painted_ptr++)
283                         {
284                                 val = (int)(painted_ptr->sample[0] * 128.0f) + 128; *snd_out++ = bound(0, val, 255);
285                                 val = (int)(painted_ptr->sample[1] * 128.0f) + 128; *snd_out++ = bound(0, val, 255);
286                                 val = (int)(painted_ptr->sample[2] * 128.0f) + 128; *snd_out++ = bound(0, val, 255);
287                                 val = (int)(painted_ptr->sample[3] * 128.0f) + 128; *snd_out++ = bound(0, val, 255);
288                         }
289                 }
290                 else if (nchannels == 2)  // 2.0 stereo
291                 {
292                         for (i = 0; i < nbframes; i++, painted_ptr++)
293                         {
294                                 val = (int)(painted_ptr->sample[0] * 128.0f) + 128; *snd_out++ = bound(0, val, 255);
295                                 val = (int)(painted_ptr->sample[1] * 128.0f) + 128; *snd_out++ = bound(0, val, 255);
296                         }
297                 }
298                 else if (nchannels == 1)  // 1.0 mono
299                 {
300                         for (i = 0;i < nbframes;i++, painted_ptr++)
301                         {
302                                 val = (int)((painted_ptr->sample[0] + painted_ptr->sample[1]) * 64.0f) + 128; *snd_out++ = bound(0, val, 255);
303                         }
304                 }
305
306                 // noise is really really annoying
307                 if (cls.timedemo)
308                         memset(rb_ptr, 128, nbframes * nchannels);
309         }
310 }
311
312
313
314 /*
315 ===============================================================================
316
317 UNDERWATER EFFECT
318
319 Muffles the intensity of sounds when the player is underwater
320
321 ===============================================================================
322 */
323
324 static struct
325 {
326         float   intensity;
327         float   alpha;
328         float   accum[SND_LISTENERS];
329 }
330 underwater = {0.f, 1.f, {0.f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f}};
331
332 void S_SetUnderwaterIntensity(void)
333 {
334         float host_frametime = cl.realframetime;
335         float target = cl.view_underwater ? 1.f : 0.f;
336
337         if (snd_waterfx.value < 0.f)
338                 target *= 0.f;
339         else if (snd_waterfx.value > 2.f)
340                 target *= 2.f;
341         else
342                 target *= snd_waterfx.value;
343
344         if (underwater.intensity < target)
345         {
346                 underwater.intensity += host_frametime * 4.f;
347                 underwater.intensity = min(underwater.intensity, target);
348         }
349         else if (underwater.intensity > target)
350         {
351                 underwater.intensity -= host_frametime * 4.f;
352                 underwater.intensity = max(underwater.intensity, target);
353         }
354
355         underwater.alpha = exp(-underwater.intensity * log(12.f));
356 }
357
358 static void S_UnderwaterFilter(int endtime)
359 {
360         int i;
361         int sl;
362
363         if (!underwater.intensity)
364         {
365                 if (endtime > 0)
366                         for (sl = 0; sl < SND_LISTENERS; sl++)
367                                 underwater.accum[sl] = paintbuffer[endtime-1].sample[sl];
368                 return;
369         }
370
371         for (i = 0; i < endtime; i++)
372                 for (sl = 0; sl < SND_LISTENERS; sl++)
373                 {
374                         underwater.accum[sl] += underwater.alpha * (paintbuffer[i].sample[sl] - underwater.accum[sl]);
375                         paintbuffer[i].sample[sl] = underwater.accum[sl];
376                 }
377 }
378
379
380
381 /*
382 ===============================================================================
383
384 CHANNEL MIXING
385
386 ===============================================================================
387 */
388
389 void S_MixToBuffer(void *stream, unsigned int bufferframes)
390 {
391         int channelindex;
392         channel_t *ch;
393         int totalmixframes;
394         unsigned char *outbytes = (unsigned char *) stream;
395         sfx_t *sfx;
396         portable_sampleframe_t *paint;
397         int wantframes;
398         int i;
399         int count;
400         int fetched;
401         int fetch;
402         int istartframe;
403         int iendframe;
404         int ilengthframes;
405         int totallength;
406         int loopstart;
407         int indexfrac;
408         int indexfracstep;
409 #define S_FETCHBUFFERSIZE 4096
410         float fetchsampleframes[S_FETCHBUFFERSIZE*2];
411         const float *fetchsampleframe;
412         float vol[SND_LISTENERS];
413         float lerp[2];
414         float sample[3];
415         double posd;
416         double speedd;
417         float maxvol;
418         qbool looping;
419         qbool silent;
420
421         // mix as many times as needed to fill the requested buffer
422         while (bufferframes)
423         {
424                 // limit to the size of the paint buffer
425                 totalmixframes = min(bufferframes, PAINTBUFFER_SIZE);
426
427                 // clear the paint buffer
428                 memset(paintbuffer, 0, totalmixframes * sizeof(paintbuffer[0]));
429
430                 // paint in the channels.
431                 // channels with zero volumes still advance in time but don't paint.
432                 ch = channels; // cppcheck complains here but it is wrong, channels is a channel_t[MAX_CHANNELS] and not an int
433                 for (channelindex = 0;channelindex < (int)total_channels;channelindex++, ch++)
434                 {
435                         sfx = ch->sfx;
436                         if (sfx == NULL)
437                                 continue;
438                         if (!S_LoadSound (sfx, true))
439                                 continue;
440                         if (ch->flags & CHANNELFLAG_PAUSED)
441                                 continue;
442                         if (!sfx->total_length)
443                                 continue;
444
445                         // copy the channel information to the stack for reference, otherwise the
446                         // values might change during a mix if the spatializer is updating them
447                         // (note: this still may get some old and some new values!)
448                         posd = ch->position;
449                         speedd = ch->mixspeed * sfx->format.speed / snd_renderbuffer->format.speed;
450                         for (i = 0;i < SND_LISTENERS;i++)
451                                 vol[i] = ch->volume[i];
452
453                         // check total volume level, because we can skip some code on silent sounds but other code must still run (position updates mainly)
454                         maxvol = 0;
455                         for (i = 0;i < SND_LISTENERS;i++)
456                                 if(vol[i] > maxvol)
457                                         maxvol = vol[i];
458                         switch(snd_renderbuffer->format.width)
459                         {
460                                 case 1: // 8bpp
461                                         silent = maxvol < (1.0f / (256.0f));
462                                         // so silent it has zero effect
463                                         break;
464                                 case 2: // 16bpp
465                                         silent = maxvol < (1.0f / (65536.0f));
466                                         // so silent it has zero effect
467                                         break;
468                                 default: // floating point
469                                         silent = maxvol < 1.0e-13f;
470                                         // 130 dB is difference between hearing
471                                         // threshold and a jackhammer from
472                                         // working distance.
473                                         // therefore, anyone who turns up
474                                         // volume so much they notice this
475                                         // cutoff, likely already has their
476                                         // ear-drums blown out anyway.
477                                         break;
478                         }
479
480                         // when doing prologic mixing, some channels invert one side
481                         if (ch->prologic_invert == -1)
482                                 vol[1] *= -1.0f;
483
484                         // get some sfx info in a consistent form
485                         totallength = sfx->total_length;
486                         loopstart = (int)sfx->loopstart < totallength ? (int)sfx->loopstart : ((ch->flags & CHANNELFLAG_FORCELOOP) ? 0 : totallength);
487                         looping = loopstart < totallength;
488
489                         // do the actual paint now (may skip work if silent)
490                         paint = paintbuffer;
491                         istartframe = 0;
492                         for (wantframes = totalmixframes;wantframes > 0;posd += count * speedd, wantframes -= count)
493                         {
494                                 // check if this is a delayed sound
495                                 if (posd < 0)
496                                 {
497                                         // for a delayed sound we have to eat into the delay first
498                                         count = (int)floor(-posd / speedd) + 1;
499                                         count = bound(1, count, wantframes);
500                                         // let the for loop iterator apply the skip
501                                         continue;
502                                 }
503
504                                 // compute a fetch size that won't overflow our buffer
505                                 count = wantframes;
506                                 for (;;)
507                                 {
508                                         istartframe = (int)floor(posd);
509                                         iendframe = (int)floor(posd + (count-1) * speedd);
510                                         ilengthframes = count > 1 ? (iendframe - istartframe + 2) : 2;
511                                         if (ilengthframes <= S_FETCHBUFFERSIZE)
512                                                 break;
513                                         // reduce count by 25% and try again
514                                         count -= count >> 2;
515                                 }
516
517                                 // zero whole fetch buffer for safety
518                                 // (floating point noise from uninitialized memory = HORRIBLE)
519                                 // otherwise we would only need to clear the excess
520                                 if (!silent)
521                                         memset(fetchsampleframes, 0, ilengthframes*sfx->format.channels*sizeof(fetchsampleframes[0]));
522
523                                 // if looping, do multiple fetches
524                                 fetched = 0;
525                                 for (;;)
526                                 {
527                                         fetch = min(ilengthframes - fetched, totallength - istartframe);
528                                         if (fetch > 0)
529                                         {
530                                                 if (!silent)
531                                                         sfx->fetcher->getsamplesfloat(ch, sfx, istartframe, fetch, fetchsampleframes + fetched*sfx->format.channels);
532                                                 istartframe += fetch;
533                                                 fetched += fetch;
534                                         }
535                                         if (istartframe == totallength && looping && fetched < ilengthframes)
536                                         {
537                                                 // loop and fetch some more
538                                                 posd += loopstart - totallength;
539                                                 istartframe = loopstart;
540                                         }
541                                         else
542                                         {
543                                                 break;
544                                         }
545                                 }
546
547                                 // set up our fixedpoint resampling variables (float to int conversions are expensive so do not do one per sampleframe)
548                                 fetchsampleframe = fetchsampleframes;
549                                 indexfrac = (int)floor((posd - floor(posd)) * 65536.0);
550                                 indexfracstep = (int)floor(speedd * 65536.0);
551                                 if (!silent)
552                                 {
553                                         if (sfx->format.channels == 2)
554                                         {
555                                                 // music is stereo
556 #if SND_LISTENERS != 8
557 #error the following code only supports up to 8 channels, update it
558 #endif
559                                                 if (snd_speakerlayout.channels > 2)
560                                                 {
561                                                         // surround mixing
562                                                         for (i = 0;i < count;i++, paint++)
563                                                         {
564                                                                 lerp[1] = indexfrac * (1.0f / 65536.0f);
565                                                                 lerp[0] = 1.0f - lerp[1];
566                                                                 sample[0] = fetchsampleframe[0] * lerp[0] + fetchsampleframe[2] * lerp[1];
567                                                                 sample[1] = fetchsampleframe[1] * lerp[0] + fetchsampleframe[3] * lerp[1];
568                                                                 sample[2] = (sample[0] + sample[1]) * 0.5f;
569                                                                 paint->sample[0] += sample[0] * vol[0];
570                                                                 paint->sample[1] += sample[1] * vol[1];
571                                                                 paint->sample[2] += sample[0] * vol[2];
572                                                                 paint->sample[3] += sample[1] * vol[3];
573                                                                 paint->sample[4] += sample[2] * vol[4];
574                                                                 paint->sample[5] += sample[2] * vol[5];
575                                                                 paint->sample[6] += sample[0] * vol[6];
576                                                                 paint->sample[7] += sample[1] * vol[7];
577                                                                 indexfrac += indexfracstep;
578                                                                 fetchsampleframe += 2 * (indexfrac >> 16);
579                                                                 indexfrac &= 0xFFFF;
580                                                         }
581                                                 }
582                                                 else
583                                                 {
584                                                         // stereo mixing
585                                                         for (i = 0;i < count;i++, paint++)
586                                                         {
587                                                                 lerp[1] = indexfrac * (1.0f / 65536.0f);
588                                                                 lerp[0] = 1.0f - lerp[1];
589                                                                 sample[0] = fetchsampleframe[0] * lerp[0] + fetchsampleframe[2] * lerp[1];
590                                                                 sample[1] = fetchsampleframe[1] * lerp[0] + fetchsampleframe[3] * lerp[1];
591                                                                 paint->sample[0] += sample[0] * vol[0];
592                                                                 paint->sample[1] += sample[1] * vol[1];
593                                                                 indexfrac += indexfracstep;
594                                                                 fetchsampleframe += 2 * (indexfrac >> 16);
595                                                                 indexfrac &= 0xFFFF;
596                                                         }
597                                                 }
598                                         }
599                                         else if (sfx->format.channels == 1)
600                                         {
601                                                 // most sounds are mono
602 #if SND_LISTENERS != 8
603 #error the following code only supports up to 8 channels, update it
604 #endif
605                                                 if (snd_speakerlayout.channels > 2)
606                                                 {
607                                                         // surround mixing
608                                                         for (i = 0;i < count;i++, paint++)
609                                                         {
610                                                                 lerp[1] = indexfrac * (1.0f / 65536.0f);
611                                                                 lerp[0] = 1.0f - lerp[1];
612                                                                 sample[0] = fetchsampleframe[0] * lerp[0] + fetchsampleframe[1] * lerp[1];
613                                                                 paint->sample[0] += sample[0] * vol[0];
614                                                                 paint->sample[1] += sample[0] * vol[1];
615                                                                 paint->sample[2] += sample[0] * vol[2];
616                                                                 paint->sample[3] += sample[0] * vol[3];
617                                                                 paint->sample[4] += sample[0] * vol[4];
618                                                                 paint->sample[5] += sample[0] * vol[5];
619                                                                 paint->sample[6] += sample[0] * vol[6];
620                                                                 paint->sample[7] += sample[0] * vol[7];
621                                                                 indexfrac += indexfracstep;
622                                                                 fetchsampleframe += (indexfrac >> 16);
623                                                                 indexfrac &= 0xFFFF;
624                                                         }
625                                                 }
626                                                 else
627                                                 {
628                                                         // stereo mixing
629                                                         for (i = 0;i < count;i++, paint++)
630                                                         {
631                                                                 lerp[1] = indexfrac * (1.0f / 65536.0f);
632                                                                 lerp[0] = 1.0f - lerp[1];
633                                                                 sample[0] = fetchsampleframe[0] * lerp[0] + fetchsampleframe[1] * lerp[1];
634                                                                 paint->sample[0] += sample[0] * vol[0];
635                                                                 paint->sample[1] += sample[0] * vol[1];
636                                                                 indexfrac += indexfracstep;
637                                                                 fetchsampleframe += (indexfrac >> 16);
638                                                                 indexfrac &= 0xFFFF;
639                                                         }
640                                                 }
641                                         }
642                                 }
643                         }
644                         ch->position = posd;
645                         if (!looping && istartframe == totallength)
646                                 S_StopChannel(ch - channels, false, false);
647                 }
648
649                 S_SoftClipPaintBuffer(paintbuffer, totalmixframes, snd_renderbuffer->format.width, snd_renderbuffer->format.channels);
650
651                 S_UnderwaterFilter(totalmixframes);
652
653
654 #ifdef CONFIG_VIDEO_CAPTURE
655                 if (!snd_usethreadedmixing)
656                         S_CaptureAVISound(paintbuffer, totalmixframes);
657 #endif
658
659                 S_ConvertPaintBuffer(paintbuffer, outbytes, totalmixframes, snd_renderbuffer->format.width, snd_renderbuffer->format.channels);
660
661                 // advance the output pointer
662                 outbytes += totalmixframes * snd_renderbuffer->format.width * snd_renderbuffer->format.channels;
663                 bufferframes -= totalmixframes;
664         }
665 }