]> de.git.xonotic.org Git - xonotic/darkplaces.git/blob - snd_mix.c
ProLogic patch by Joris Nijnuis, with some fixes
[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 static portable_sampleframe_t paintbuffer[PAINTBUFFER_SIZE];
26 static portable_sampleframe_t paintbuffer_unswapped[PAINTBUFFER_SIZE];
27
28 extern speakerlayout_t snd_speakerlayout; // for querying the listeners
29
30 extern void SCR_CaptureVideo_SoundFrame(const portable_sampleframe_t *paintbuffer, size_t length);
31 static void S_CaptureAVISound(size_t length)
32 {
33         size_t i;
34         unsigned int j;
35
36         if (!cls.capturevideo.active)
37                 return;
38
39         // undo whatever swapping the channel layout (swapstereo, ALSA) did
40         for(j = 0; j < snd_speakerlayout.channels; ++j)
41         {
42                 unsigned int j0 = snd_speakerlayout.listeners[j].channel_unswapped;
43                 for(i = 0; i < length; ++i)
44                         paintbuffer_unswapped[i].sample[j0] = paintbuffer[i].sample[j];
45         }
46
47         SCR_CaptureVideo_SoundFrame(paintbuffer_unswapped, length);
48 }
49
50 static void S_ConvertPaintBuffer(const portable_sampleframe_t *painted_ptr, void *rb_ptr, int nbframes, int width, int channels)
51 {
52         int i, val;
53         if (width == 2)  // 16bit
54         {
55                 short *snd_out = (short*)rb_ptr;
56                 if (channels == 8)  // 7.1 surround
57                 {
58                         for (i = 0;i < nbframes;i++, painted_ptr++)
59                         {
60                                 *snd_out++ = bound(-32768, painted_ptr->sample[0], 32767);
61                                 *snd_out++ = bound(-32768, painted_ptr->sample[1], 32767);
62                                 *snd_out++ = bound(-32768, painted_ptr->sample[2], 32767);
63                                 *snd_out++ = bound(-32768, painted_ptr->sample[3], 32767);
64                                 *snd_out++ = bound(-32768, painted_ptr->sample[4], 32767);
65                                 *snd_out++ = bound(-32768, painted_ptr->sample[5], 32767);
66                                 *snd_out++ = bound(-32768, painted_ptr->sample[6], 32767);
67                                 *snd_out++ = bound(-32768, painted_ptr->sample[7], 32767);
68                         }
69                 }
70                 else if (channels == 6)  // 5.1 surround
71                 {
72                         for (i = 0; i < nbframes; i++, painted_ptr++)
73                         {
74                                 *snd_out++ = bound(-32768, painted_ptr->sample[0], 32767);
75                                 *snd_out++ = bound(-32768, painted_ptr->sample[1], 32767);
76                                 *snd_out++ = bound(-32768, painted_ptr->sample[2], 32767);
77                                 *snd_out++ = bound(-32768, painted_ptr->sample[3], 32767);
78                                 *snd_out++ = bound(-32768, painted_ptr->sample[4], 32767);
79                                 *snd_out++ = bound(-32768, painted_ptr->sample[5], 32767);
80                         }
81                 }
82                 else if (channels == 4)  // 4.0 surround
83                 {
84                         for (i = 0; i < nbframes; i++, painted_ptr++)
85                         {
86                                 *snd_out++ = bound(-32768, painted_ptr->sample[0], 32767);
87                                 *snd_out++ = bound(-32768, painted_ptr->sample[1], 32767);
88                                 *snd_out++ = bound(-32768, painted_ptr->sample[2], 32767);
89                                 *snd_out++ = bound(-32768, painted_ptr->sample[3], 32767);
90                         }
91                 }
92                 else if (channels == 2)  // 2.0 stereo
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                         }
99                 }
100                 else if (channels == 1)  // 1.0 mono
101                 {
102                         for (i = 0; i < nbframes; i++, painted_ptr++)
103                         {
104                                 val = (painted_ptr->sample[0] + painted_ptr->sample[1]) >> 1;
105                                 *snd_out++ = bound(-32768, val, 32767);
106                         }
107                 }
108
109                 // noise is really really annoying
110                 if (cls.timedemo)
111                         memset(rb_ptr, 0, nbframes * channels * width);
112         }
113         else  // 8bit
114         {
115                 unsigned char *snd_out = (unsigned char*)rb_ptr;
116                 if (channels == 8)  // 7.1 surround
117                 {
118                         for (i = 0; i < nbframes; i++, painted_ptr++)
119                         {
120                                 val = (painted_ptr->sample[0] >> 8) + 128; *snd_out++ = bound(0, val, 255);
121                                 val = (painted_ptr->sample[1] >> 8) + 128; *snd_out++ = bound(0, val, 255);
122                                 val = (painted_ptr->sample[2] >> 8) + 128; *snd_out++ = bound(0, val, 255);
123                                 val = (painted_ptr->sample[3] >> 8) + 128; *snd_out++ = bound(0, val, 255);
124                                 val = (painted_ptr->sample[4] >> 8) + 128; *snd_out++ = bound(0, val, 255);
125                                 val = (painted_ptr->sample[5] >> 8) + 128; *snd_out++ = bound(0, val, 255);
126                                 val = (painted_ptr->sample[6] >> 8) + 128; *snd_out++ = bound(0, val, 255);
127                                 val = (painted_ptr->sample[7] >> 8) + 128; *snd_out++ = bound(0, val, 255);
128                         }
129                 }
130                 else if (channels == 6)  // 5.1 surround
131                 {
132                         for (i = 0; i < nbframes; i++, painted_ptr++)
133                         {
134                                 val = (painted_ptr->sample[0] >> 8) + 128; *snd_out++ = bound(0, val, 255);
135                                 val = (painted_ptr->sample[1] >> 8) + 128; *snd_out++ = bound(0, val, 255);
136                                 val = (painted_ptr->sample[2] >> 8) + 128; *snd_out++ = bound(0, val, 255);
137                                 val = (painted_ptr->sample[3] >> 8) + 128; *snd_out++ = bound(0, val, 255);
138                                 val = (painted_ptr->sample[4] >> 8) + 128; *snd_out++ = bound(0, val, 255);
139                                 val = (painted_ptr->sample[5] >> 8) + 128; *snd_out++ = bound(0, val, 255);
140                         }
141                 }
142                 else if (channels == 4)  // 4.0 surround
143                 {
144                         for (i = 0; i < nbframes; i++, painted_ptr++)
145                         {
146                                 val = (painted_ptr->sample[0] >> 8) + 128; *snd_out++ = bound(0, val, 255);
147                                 val = (painted_ptr->sample[1] >> 8) + 128; *snd_out++ = bound(0, val, 255);
148                                 val = (painted_ptr->sample[2] >> 8) + 128; *snd_out++ = bound(0, val, 255);
149                                 val = (painted_ptr->sample[3] >> 8) + 128; *snd_out++ = bound(0, val, 255);
150                         }
151                 }
152                 else if (channels == 2)  // 2.0 stereo
153                 {
154                         for (i = 0; i < nbframes; i++, painted_ptr++)
155                         {
156                                 val = (painted_ptr->sample[0] >> 8) + 128; *snd_out++ = bound(0, val, 255);
157                                 val = (painted_ptr->sample[1] >> 8) + 128; *snd_out++ = bound(0, val, 255);
158                         }
159                 }
160                 else if (channels == 1)  // 1.0 mono
161                 {
162                         for (i = 0;i < nbframes;i++, painted_ptr++)
163                         {
164                                 val = ((painted_ptr->sample[0] + painted_ptr->sample[1]) >> 9) + 128;
165                                 *snd_out++ = bound(0, val, 255);
166                         }
167                 }
168
169                 // noise is really really annoying
170                 if (cls.timedemo)
171                         memset(rb_ptr, 128, nbframes * channels);
172         }
173 }
174
175
176 /*
177 ===============================================================================
178
179 CHANNEL MIXING
180
181 ===============================================================================
182 */
183
184 static qboolean SND_PaintChannel (channel_t *ch, portable_sampleframe_t *paint, unsigned int count)
185 {
186         int snd_vol, vol[SND_LISTENERS];
187         const snd_buffer_t *sb;
188         unsigned int i, sb_offset;
189
190         // If this channel manages its own volume
191         if (ch->flags & CHANNELFLAG_FULLVOLUME)
192                 snd_vol = (int)(mastervolume.value * 256);
193         else
194                 snd_vol = (int)(mastervolume.value * volume.value * 256);
195
196         // calculate mixing volumes based on channel volumes and volume cvar
197         // also limit the volumes to values that won't clip
198         for (i = 0;i < SND_LISTENERS;i++)
199         {
200                 vol[i] = ch->listener_volume[i] * snd_vol;
201                 vol[i] = bound(0, vol[i], 65536);
202         }
203
204         // if volumes are all zero, just return
205         for (i = 0;i < SND_LISTENERS;i++)
206                 if (vol[i])
207                         break;
208         if (i == SND_LISTENERS)
209                 return false;
210
211         sb_offset = ch->pos;
212         sb = ch->sfx->fetcher->getsb (ch->sfx->fetcher_data, &ch->fetcher_data, &sb_offset, count);
213         if (sb == NULL)
214         {
215                 Con_DPrintf("SND_PaintChannel: ERROR: can't get sound buffer from sfx \"%s\"\n",
216                                         ch->sfx->name); // , count); // or add this? FIXME
217                 return false;
218         }
219         else
220         {
221 #if SND_LISTENERS != 8
222 #               error the following code only supports up to 8 channels, update it
223 #endif
224                 if (sb->format.width == 1)
225                 {
226                         const signed char *samples = (signed char*)sb->samples + (ch->pos - sb_offset) * sb->format.channels;
227
228                         // Stereo sound support
229                         if (sb->format.channels == 2)
230                         {
231                                 if (vol[6] + vol[7] > 0)
232                                 {
233                                         for (i = 0;i < count;i++)
234                                         {
235                                                 paint[i].sample[0] += (samples[0] * vol[0]) >> 8;
236                                                 paint[i].sample[1] += (samples[1] * vol[1]) >> 8;
237                                                 paint[i].sample[2] += (samples[0] * vol[2]) >> 8;
238                                                 paint[i].sample[3] += (samples[1] * vol[3]) >> 8;
239                                                 paint[i].sample[4] += ((samples[0] + samples[1]) * vol[4]) >> 9;
240                                                 paint[i].sample[5] += ((samples[0] + samples[1]) * vol[5]) >> 9;
241                                                 paint[i].sample[6] += (samples[0] * vol[6]) >> 8;
242                                                 paint[i].sample[7] += (samples[1] * vol[7]) >> 8;
243                                                 samples += 2;
244                                         }
245                                 }
246                                 else if (vol[4] + vol[5] > 0)
247                                 {
248                                         for (i = 0;i < count;i++)
249                                         {
250                                                 paint[i].sample[0] += (samples[0] * vol[0]) >> 8;
251                                                 paint[i].sample[1] += (samples[1] * vol[1]) >> 8;
252                                                 paint[i].sample[2] += (samples[0] * vol[2]) >> 8;
253                                                 paint[i].sample[3] += (samples[1] * vol[3]) >> 8;
254                                                 paint[i].sample[4] += ((samples[0] + samples[1]) * vol[4]) >> 9;
255                                                 paint[i].sample[5] += ((samples[0] + samples[1]) * vol[5]) >> 9;
256                                                 samples += 2;
257                                         }
258                                 }
259                                 else if (vol[2] + vol[3] > 0)
260                                 {
261                                         for (i = 0;i < count;i++)
262                                         {
263                                                 paint[i].sample[0] += (samples[0] * vol[0]) >> 8;
264                                                 paint[i].sample[1] += (samples[1] * vol[1]) >> 8;
265                                                 paint[i].sample[2] += (samples[0] * vol[2]) >> 8;
266                                                 paint[i].sample[3] += (samples[1] * vol[3]) >> 8;
267                                                 samples += 2;
268                                         }
269                                 }
270                                 else if (vol[0] + vol[1] > 0)
271                                 {
272                                         for (i = 0;i < count;i++)
273                                         {
274                                                 paint[i].sample[0] += (samples[0] * vol[0]) >> 8;
275                                                 paint[i].sample[1] += (samples[1] * vol[1] * ch->prologic_invert) >> 8;
276                                                 samples += 2;
277                                         }
278                                 }
279                         }
280                         else if (sb->format.channels == 1)
281                         {
282                                 if (vol[6] + vol[7] > 0)
283                                 {
284                                         for (i = 0;i < count;i++)
285                                         {
286                                                 paint[i].sample[0] += (samples[0] * vol[0]) >> 8;
287                                                 paint[i].sample[1] += (samples[0] * vol[1]) >> 8;
288                                                 paint[i].sample[2] += (samples[0] * vol[2]) >> 8;
289                                                 paint[i].sample[3] += (samples[0] * vol[3]) >> 8;
290                                                 paint[i].sample[4] += (samples[0] * vol[4]) >> 8;
291                                                 paint[i].sample[5] += (samples[0] * vol[5]) >> 8;
292                                                 paint[i].sample[6] += (samples[0] * vol[6]) >> 8;
293                                                 paint[i].sample[7] += (samples[0] * vol[7]) >> 8;
294                                                 samples += 1;
295                                         }
296                                 }
297                                 else if (vol[4] + vol[5] > 0)
298                                 {
299                                         for (i = 0;i < count;i++)
300                                         {
301                                                 paint[i].sample[0] += (samples[0] * vol[0]) >> 8;
302                                                 paint[i].sample[1] += (samples[0] * vol[1]) >> 8;
303                                                 paint[i].sample[2] += (samples[0] * vol[2]) >> 8;
304                                                 paint[i].sample[3] += (samples[0] * vol[3]) >> 8;
305                                                 paint[i].sample[4] += (samples[0] * vol[4]) >> 8;
306                                                 paint[i].sample[5] += (samples[0] * vol[5]) >> 8;
307                                                 samples += 1;
308                                         }
309                                 }
310                                 else if (vol[2] + vol[3] > 0)
311                                 {
312                                         for (i = 0;i < count;i++)
313                                         {
314                                                 paint[i].sample[0] += (samples[0] * vol[0]) >> 8;
315                                                 paint[i].sample[1] += (samples[0] * vol[1]) >> 8;
316                                                 paint[i].sample[2] += (samples[0] * vol[2]) >> 8;
317                                                 paint[i].sample[3] += (samples[0] * vol[3]) >> 8;
318                                                 samples += 1;
319                                         }
320                                 }
321                                 else if (vol[0] + vol[1] > 0)
322                                 {
323                                         for (i = 0;i < count;i++)
324                                         {
325                                                 paint[i].sample[0] += (samples[0] * vol[0]) >> 8;
326                                                 paint[i].sample[1] += (samples[0] * vol[1] * ch->prologic_invert) >> 8;
327                                                 samples += 1;
328                                         }
329                                 }
330                         }
331                         else
332                                 return false; // unsupported number of channels in sound
333                 }
334                 else if (sb->format.width == 2)
335                 {
336                         const signed short *samples = (signed short*)sb->samples + (ch->pos - sb_offset) * sb->format.channels;
337
338                         // Stereo sound support
339                         if (sb->format.channels == 2)
340                         {
341                                 if (vol[6] + vol[7] > 0)
342                                 {
343                                         for (i = 0;i < count;i++)
344                                         {
345                                                 paint[i].sample[0] += (samples[0] * vol[0]) >> 16;
346                                                 paint[i].sample[1] += (samples[1] * vol[1]) >> 16;
347                                                 paint[i].sample[2] += (samples[0] * vol[2]) >> 16;
348                                                 paint[i].sample[3] += (samples[1] * vol[3]) >> 16;
349                                                 paint[i].sample[4] += ((samples[0] + samples[1]) * vol[4]) >> 17;
350                                                 paint[i].sample[5] += ((samples[0] + samples[1]) * vol[5]) >> 17;
351                                                 paint[i].sample[6] += (samples[0] * vol[6]) >> 16;
352                                                 paint[i].sample[7] += (samples[1] * vol[7]) >> 16;
353                                                 samples += 2;
354                                         }
355                                 }
356                                 else if (vol[4] + vol[5] > 0)
357                                 {
358                                         for (i = 0;i < count;i++)
359                                         {
360                                                 paint[i].sample[0] += (samples[0] * vol[0]) >> 16;
361                                                 paint[i].sample[1] += (samples[1] * vol[1]) >> 16;
362                                                 paint[i].sample[2] += (samples[0] * vol[2]) >> 16;
363                                                 paint[i].sample[3] += (samples[1] * vol[3]) >> 16;
364                                                 paint[i].sample[4] += ((samples[0] + samples[1]) * vol[4]) >> 17;
365                                                 paint[i].sample[5] += ((samples[0] + samples[1]) * vol[5]) >> 17;
366                                                 samples += 2;
367                                         }
368                                 }
369                                 else if (vol[2] + vol[3] > 0)
370                                 {
371                                         for (i = 0;i < count;i++)
372                                         {
373                                                 paint[i].sample[0] += (samples[0] * vol[0]) >> 16;
374                                                 paint[i].sample[1] += (samples[1] * vol[1]) >> 16;
375                                                 paint[i].sample[2] += (samples[0] * vol[2]) >> 16;
376                                                 paint[i].sample[3] += (samples[1] * vol[3]) >> 16;
377                                                 samples += 2;
378                                         }
379                                 }
380                                 else if (vol[0] + vol[1] > 0)
381                                 {
382                                         for (i = 0;i < count;i++)
383                                         {
384                                                 paint[i].sample[0] += (samples[0] * vol[0]) >> 16;
385                                                 paint[i].sample[1] += (samples[1] * vol[1] * ch->prologic_invert) >> 16;
386                                                 samples += 2;
387                                         }
388                                 }
389                         }
390                         else if (sb->format.channels == 1)
391                         {
392                                 if (vol[6] + vol[7] > 0)
393                                 {
394                                         for (i = 0;i < count;i++)
395                                         {
396                                                 paint[i].sample[0] += (samples[0] * vol[0]) >> 16;
397                                                 paint[i].sample[1] += (samples[0] * vol[1]) >> 16;
398                                                 paint[i].sample[2] += (samples[0] * vol[2]) >> 16;
399                                                 paint[i].sample[3] += (samples[0] * vol[3]) >> 16;
400                                                 paint[i].sample[4] += (samples[0] * vol[4]) >> 16;
401                                                 paint[i].sample[5] += (samples[0] * vol[5]) >> 16;
402                                                 paint[i].sample[6] += (samples[0] * vol[6]) >> 16;
403                                                 paint[i].sample[7] += (samples[0] * vol[7]) >> 16;
404                                                 samples += 1;
405                                         }
406                                 }
407                                 else if (vol[4] + vol[5] > 0)
408                                 {
409                                         for (i = 0;i < count;i++)
410                                         {
411                                                 paint[i].sample[0] += (samples[0] * vol[0]) >> 16;
412                                                 paint[i].sample[1] += (samples[0] * vol[1]) >> 16;
413                                                 paint[i].sample[2] += (samples[0] * vol[2]) >> 16;
414                                                 paint[i].sample[3] += (samples[0] * vol[3]) >> 16;
415                                                 paint[i].sample[4] += (samples[0] * vol[4]) >> 16;
416                                                 paint[i].sample[5] += (samples[0] * vol[5]) >> 16;
417                                                 samples += 1;
418                                         }
419                                 }
420                                 else if (vol[2] + vol[3] > 0)
421                                 {
422                                         for (i = 0;i < count;i++)
423                                         {
424                                                 paint[i].sample[0] += (samples[0] * vol[0]) >> 16;
425                                                 paint[i].sample[1] += (samples[0] * vol[1]) >> 16;
426                                                 paint[i].sample[2] += (samples[0] * vol[2]) >> 16;
427                                                 paint[i].sample[3] += (samples[0] * vol[3]) >> 16;
428                                                 samples += 1;
429                                         }
430                                 }
431                                 else if (vol[0] + vol[1] > 0)
432                                 {
433                                         for (i = 0;i < count;i++)
434                                         {
435                                                 paint[i].sample[0] += (samples[0] * vol[0]) >> 16;
436                                                 paint[i].sample[1] += (samples[0] * vol[1] * ch->prologic_invert) >> 16;
437                                                 samples += 1;
438                                         }
439                                 }
440                         }
441                         else
442                                 return false; // unsupported number of channels in sound
443                 }
444         }
445         return true;
446 }
447
448 void S_MixToBuffer(void *stream, unsigned int bufferframes)
449 {
450         unsigned int i;
451         channel_t *ch;
452         unsigned int frames;
453         unsigned char *outbytes = (unsigned char *) stream;
454
455         // mix as many times as needed to fill the requested buffer
456         while (bufferframes)
457         {
458                 // limit to the size of the paint buffer
459                 frames = min(bufferframes, PAINTBUFFER_SIZE);
460
461                 // clear the paint buffer
462                 memset (paintbuffer, 0, frames * sizeof (paintbuffer[0]));
463
464                 // paint in the channels.
465                 // channels with zero volumes still advance in time but don't paint.
466                 ch = channels;
467                 for (i = 0; i < total_channels ; i++, ch++)
468                 {
469                         sfx_t *sfx;
470                         int ltime;
471                         int count;
472
473                         sfx = ch->sfx;
474                         if (sfx == NULL)
475                                 continue;
476                         if (!S_LoadSound (sfx, true))
477                                 continue;
478                         if (ch->flags & CHANNELFLAG_PAUSED)
479                                 continue;
480
481                         ltime = 0;
482                         if (ch->pos < 0)
483                         {
484                                 count = -ch->pos;
485                                 count = min(count, (int)frames - ltime);
486                                 ch->pos += count;
487                                 ltime += count;
488                         }
489
490                         while (ltime < (int)frames)
491                         {
492                                 // paint up to end of buffer or of input, whichever is lower
493                                 count = sfx->total_length - ch->pos;
494                                 count = bound(0, count, (int)frames - ltime);
495                                 if (count)
496                                 {
497                                         SND_PaintChannel (ch, paintbuffer + ltime, count);
498                                         ch->pos += count;
499                                         ltime += count;
500                                 }
501
502                                 // if at end of sfx, loop or stop the channel
503                                 if (ch->pos >= (int)sfx->total_length)
504                                 {
505                                         if (sfx->loopstart < sfx->total_length)
506                                                 ch->pos = sfx->loopstart;
507                                         else if (ch->flags & CHANNELFLAG_FORCELOOP)
508                                                 ch->pos = 0;
509                                         else
510                                         {
511                                                 S_StopChannel (ch - channels, false);
512                                                 break;
513                                         }
514                                 }
515                         }
516                 }
517
518                 if (!snd_usethreadedmixing)
519                         S_CaptureAVISound(frames);
520
521                 S_ConvertPaintBuffer(paintbuffer, outbytes, frames, snd_renderbuffer->format.width, snd_renderbuffer->format.channels);
522
523                 // advance the output pointer
524                 outbytes += frames * snd_renderbuffer->format.width * snd_renderbuffer->format.channels;
525                 bufferframes -= frames;
526         }
527 }