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