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