2 Copyright (C) 1996-1997 Id Software, Inc.
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.
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.
13 See the GNU General Public License for more details.
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.
25 typedef struct portable_samplepair_s
27 int sample[SND_LISTENERS];
28 } portable_sampleframe_t;
30 // LordHavoc: was 512, expanded to 2048
31 #define PAINTBUFFER_SIZE 2048
32 portable_sampleframe_t paintbuffer[PAINTBUFFER_SIZE];
35 extern void SCR_CaptureVideo_SoundFrame(unsigned char *bufstereo16le, size_t length, int rate);
36 static void S_CaptureAVISound(size_t length)
39 unsigned char out[PAINTBUFFER_SIZE * 4];
40 unsigned char* out_ptr;
42 if (!cls.capturevideo_active)
45 // write the sound buffer as little endian 16bit interleaved stereo
46 for(i = 0, out_ptr = out; i < length; i++, out_ptr += 4)
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);
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);
60 SCR_CaptureVideo_SoundFrame(out, length, snd_renderbuffer->format.speed);
63 static unsigned int S_TransferPaintBuffer(snd_ringbuffer_t* rb, unsigned int starttime, unsigned int endtime)
65 unsigned int partialend;
68 if (!simsound && !SndSys_LockRenderBuffer())
71 partialend = starttime;
72 while (partialend < endtime) // handle recirculating buffer issues
74 unsigned int startoffset, maxframes, nbframes, i;
76 portable_sampleframe_t *painted_ptr;
79 startoffset = partialend % rb->maxframes;
80 maxframes = rb->maxframes - startoffset;
81 nbframes = endtime - partialend;
82 if (nbframes > maxframes)
85 rb_ptr = &rb->ring[startoffset * rb->format.width * rb->format.channels];
86 painted_ptr = &paintbuffer[partialend - starttime];
88 if (rb->format.width == 2) // 16bit
90 short *snd_out = (short*)rb_ptr;
91 if (rb->format.channels == 8) // 7.1 surround
93 for (i = 0;i < nbframes;i++, painted_ptr++)
95 *snd_out++ = bound(-32768, painted_ptr->sample[0], 32767);
96 *snd_out++ = bound(-32768, painted_ptr->sample[1], 32767);
97 *snd_out++ = bound(-32768, painted_ptr->sample[2], 32767);
98 *snd_out++ = bound(-32768, painted_ptr->sample[3], 32767);
99 *snd_out++ = bound(-32768, painted_ptr->sample[4], 32767);
100 *snd_out++ = bound(-32768, painted_ptr->sample[5], 32767);
101 *snd_out++ = bound(-32768, painted_ptr->sample[6], 32767);
102 *snd_out++ = bound(-32768, painted_ptr->sample[7], 32767);
105 else if (rb->format.channels == 6) // 5.1 surround
107 for (i = 0; i < nbframes; i++, painted_ptr++)
109 *snd_out++ = bound(-32768, painted_ptr->sample[0], 32767);
110 *snd_out++ = bound(-32768, painted_ptr->sample[1], 32767);
111 *snd_out++ = bound(-32768, painted_ptr->sample[2], 32767);
112 *snd_out++ = bound(-32768, painted_ptr->sample[3], 32767);
113 *snd_out++ = bound(-32768, painted_ptr->sample[4], 32767);
114 *snd_out++ = bound(-32768, painted_ptr->sample[5], 32767);
117 else if (rb->format.channels == 4) // 4.0 surround
119 for (i = 0; i < nbframes; i++, painted_ptr++)
121 *snd_out++ = bound(-32768, painted_ptr->sample[0], 32767);
122 *snd_out++ = bound(-32768, painted_ptr->sample[1], 32767);
123 *snd_out++ = bound(-32768, painted_ptr->sample[2], 32767);
124 *snd_out++ = bound(-32768, painted_ptr->sample[3], 32767);
127 else if (rb->format.channels == 2) // 2.0 stereo
129 for (i = 0; i < nbframes; i++, painted_ptr++)
131 *snd_out++ = bound(-32768, painted_ptr->sample[0], 32767);
132 *snd_out++ = bound(-32768, painted_ptr->sample[1], 32767);
135 else if (rb->format.channels == 1) // 1.0 mono
137 for (i = 0; i < nbframes; i++, painted_ptr++)
139 val = (painted_ptr->sample[0] + painted_ptr->sample[1]) >> 1;
140 *snd_out++ = bound(-32768, val, 32767);
146 unsigned char *snd_out = (unsigned char*)rb_ptr;
147 if (rb->format.channels == 8) // 7.1 surround
149 for (i = 0; i < nbframes; i++, painted_ptr++)
151 val = (painted_ptr->sample[0] >> 8) + 128; *snd_out++ = bound(0, val, 255);
152 val = (painted_ptr->sample[1] >> 8) + 128; *snd_out++ = bound(0, val, 255);
153 val = (painted_ptr->sample[2] >> 8) + 128; *snd_out++ = bound(0, val, 255);
154 val = (painted_ptr->sample[3] >> 8) + 128; *snd_out++ = bound(0, val, 255);
155 val = (painted_ptr->sample[4] >> 8) + 128; *snd_out++ = bound(0, val, 255);
156 val = (painted_ptr->sample[5] >> 8) + 128; *snd_out++ = bound(0, val, 255);
157 val = (painted_ptr->sample[6] >> 8) + 128; *snd_out++ = bound(0, val, 255);
158 val = (painted_ptr->sample[7] >> 8) + 128; *snd_out++ = bound(0, val, 255);
161 else if (rb->format.channels == 6) // 5.1 surround
163 for (i = 0; i < nbframes; i++, painted_ptr++)
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 val = (painted_ptr->sample[2] >> 8) + 128; *snd_out++ = bound(0, val, 255);
168 val = (painted_ptr->sample[3] >> 8) + 128; *snd_out++ = bound(0, val, 255);
169 val = (painted_ptr->sample[4] >> 8) + 128; *snd_out++ = bound(0, val, 255);
170 val = (painted_ptr->sample[5] >> 8) + 128; *snd_out++ = bound(0, val, 255);
173 else if (rb->format.channels == 4) // 4.0 surround
175 for (i = 0; i < nbframes; i++, painted_ptr++)
177 val = (painted_ptr->sample[0] >> 8) + 128; *snd_out++ = bound(0, val, 255);
178 val = (painted_ptr->sample[1] >> 8) + 128; *snd_out++ = bound(0, val, 255);
179 val = (painted_ptr->sample[2] >> 8) + 128; *snd_out++ = bound(0, val, 255);
180 val = (painted_ptr->sample[3] >> 8) + 128; *snd_out++ = bound(0, val, 255);
183 else if (rb->format.channels == 2) // 2.0 stereo
185 for (i = 0; i < nbframes; i++, painted_ptr++)
187 val = (painted_ptr->sample[0] >> 8) + 128; *snd_out++ = bound(0, val, 255);
188 val = (painted_ptr->sample[1] >> 8) + 128; *snd_out++ = bound(0, val, 255);
191 else if (rb->format.channels == 1) // 1.0 mono
193 for (i = 0;i < nbframes;i++, painted_ptr++)
195 val = ((painted_ptr->sample[0] + painted_ptr->sample[1]) >> 9) + 128;
196 *snd_out++ = bound(0, val, 255);
201 partialend += nbframes;
204 rb->endframe = endtime;
206 // Remove outdated samples from the ring buffer, if any
207 if (rb->startframe < soundtime)
208 rb->startframe = soundtime;
211 SndSys_UnlockRenderBuffer();
213 return endtime - starttime;
218 ===============================================================================
222 ===============================================================================
225 static qboolean SND_PaintChannel (channel_t *ch, unsigned int count)
227 int snd_vol, vol[SND_LISTENERS];
228 const snd_buffer_t *sb;
229 unsigned int i, sb_offset;
231 // If this channel manages its own volume
232 if (ch->flags & CHANNELFLAG_FULLVOLUME)
235 snd_vol = (int)(volume.value * 256);
237 for (i = 0;i < SND_LISTENERS;i++)
238 vol[i] = ch->listener_volume[i] * snd_vol;
241 sb = ch->sfx->fetcher->getsb (ch, &sb_offset, count);
244 Con_DPrintf("SND_PaintChannel: ERROR: can't get sound buffer from sfx \"%s\"\n",
245 ch->sfx->name, count);
249 #if SND_LISTENERS != 8
250 # error the following code only supports up to 8 channels, update it
252 if (sb->format.width == 1)
254 const signed char *samples = (signed char*)sb->samples + (ch->pos - sb_offset) * sb->format.channels;
256 // Stereo sound support
257 if (sb->format.channels == 2)
259 if (vol[6] + vol[7] > 0)
261 for (i = 0;i < count;i++)
263 paintbuffer[i].sample[0] += (samples[0] * vol[0]) >> 8;
264 paintbuffer[i].sample[1] += (samples[1] * vol[1]) >> 8;
265 paintbuffer[i].sample[2] += (samples[0] * vol[2]) >> 8;
266 paintbuffer[i].sample[3] += (samples[1] * vol[3]) >> 8;
267 paintbuffer[i].sample[4] += ((samples[0] + samples[1]) * vol[4]) >> 9;
268 paintbuffer[i].sample[5] += ((samples[0] + samples[1]) * vol[5]) >> 9;
269 paintbuffer[i].sample[6] += (samples[0] * vol[6]) >> 8;
270 paintbuffer[i].sample[7] += (samples[1] * vol[7]) >> 8;
274 else if (vol[4] + vol[5] > 0)
276 for (i = 0;i < count;i++)
278 paintbuffer[i].sample[0] += (samples[0] * vol[0]) >> 8;
279 paintbuffer[i].sample[1] += (samples[1] * vol[1]) >> 8;
280 paintbuffer[i].sample[2] += (samples[0] * vol[2]) >> 8;
281 paintbuffer[i].sample[3] += (samples[1] * vol[3]) >> 8;
282 paintbuffer[i].sample[4] += ((samples[0] + samples[1]) * vol[4]) >> 9;
283 paintbuffer[i].sample[5] += ((samples[0] + samples[1]) * vol[5]) >> 9;
287 else if (vol[2] + vol[3] > 0)
289 for (i = 0;i < count;i++)
291 paintbuffer[i].sample[0] += (samples[0] * vol[0]) >> 8;
292 paintbuffer[i].sample[1] += (samples[1] * vol[1]) >> 8;
293 paintbuffer[i].sample[2] += (samples[0] * vol[2]) >> 8;
294 paintbuffer[i].sample[3] += (samples[1] * vol[3]) >> 8;
298 else if (vol[0] + vol[1] > 0)
300 for (i = 0;i < count;i++)
302 paintbuffer[i].sample[0] += (samples[0] * vol[0]) >> 8;
303 paintbuffer[i].sample[1] += (samples[1] * vol[1]) >> 8;
308 else if (sb->format.channels == 1)
310 if (vol[6] + vol[7] > 0)
312 for (i = 0;i < count;i++)
314 paintbuffer[i].sample[0] += (samples[0] * vol[0]) >> 8;
315 paintbuffer[i].sample[1] += (samples[0] * vol[1]) >> 8;
316 paintbuffer[i].sample[2] += (samples[0] * vol[2]) >> 8;
317 paintbuffer[i].sample[3] += (samples[0] * vol[3]) >> 8;
318 paintbuffer[i].sample[4] += (samples[0] * vol[4]) >> 8;
319 paintbuffer[i].sample[5] += (samples[0] * vol[5]) >> 8;
320 paintbuffer[i].sample[6] += (samples[0] * vol[6]) >> 8;
321 paintbuffer[i].sample[7] += (samples[0] * vol[7]) >> 8;
325 else if (vol[4] + vol[5] > 0)
327 for (i = 0;i < count;i++)
329 paintbuffer[i].sample[0] += (samples[0] * vol[0]) >> 8;
330 paintbuffer[i].sample[1] += (samples[0] * vol[1]) >> 8;
331 paintbuffer[i].sample[2] += (samples[0] * vol[2]) >> 8;
332 paintbuffer[i].sample[3] += (samples[0] * vol[3]) >> 8;
333 paintbuffer[i].sample[4] += (samples[0] * vol[4]) >> 8;
334 paintbuffer[i].sample[5] += (samples[0] * vol[5]) >> 8;
338 else if (vol[2] + vol[3] > 0)
340 for (i = 0;i < count;i++)
342 paintbuffer[i].sample[0] += (samples[0] * vol[0]) >> 8;
343 paintbuffer[i].sample[1] += (samples[0] * vol[1]) >> 8;
344 paintbuffer[i].sample[2] += (samples[0] * vol[2]) >> 8;
345 paintbuffer[i].sample[3] += (samples[0] * vol[3]) >> 8;
349 else if (vol[0] + vol[1] > 0)
351 for (i = 0;i < count;i++)
353 paintbuffer[i].sample[0] += (samples[0] * vol[0]) >> 8;
354 paintbuffer[i].sample[1] += (samples[0] * vol[1]) >> 8;
360 return false; // unsupported number of channels in sound
362 else if (sb->format.width == 2)
364 const signed short *samples = (signed short*)sb->samples + (ch->pos - sb_offset) * sb->format.channels;
366 // Stereo sound support
367 if (sb->format.channels == 2)
369 if (vol[6] + vol[7] > 0)
371 for (i = 0;i < count;i++)
373 paintbuffer[i].sample[0] += (samples[0] * vol[0]) >> 16;
374 paintbuffer[i].sample[1] += (samples[1] * vol[1]) >> 16;
375 paintbuffer[i].sample[2] += (samples[0] * vol[2]) >> 16;
376 paintbuffer[i].sample[3] += (samples[1] * vol[3]) >> 16;
377 paintbuffer[i].sample[4] += ((samples[0] + samples[1]) * vol[4]) >> 17;
378 paintbuffer[i].sample[5] += ((samples[0] + samples[1]) * vol[5]) >> 17;
379 paintbuffer[i].sample[6] += (samples[0] * vol[6]) >> 16;
380 paintbuffer[i].sample[7] += (samples[1] * vol[7]) >> 16;
384 else if (vol[4] + vol[5] > 0)
386 for (i = 0;i < count;i++)
388 paintbuffer[i].sample[0] += (samples[0] * vol[0]) >> 16;
389 paintbuffer[i].sample[1] += (samples[1] * vol[1]) >> 16;
390 paintbuffer[i].sample[2] += (samples[0] * vol[2]) >> 16;
391 paintbuffer[i].sample[3] += (samples[1] * vol[3]) >> 16;
392 paintbuffer[i].sample[4] += ((samples[0] + samples[1]) * vol[4]) >> 17;
393 paintbuffer[i].sample[5] += ((samples[0] + samples[1]) * vol[5]) >> 17;
397 else if (vol[2] + vol[3] > 0)
399 for (i = 0;i < count;i++)
401 paintbuffer[i].sample[0] += (samples[0] * vol[0]) >> 16;
402 paintbuffer[i].sample[1] += (samples[1] * vol[1]) >> 16;
403 paintbuffer[i].sample[2] += (samples[0] * vol[2]) >> 16;
404 paintbuffer[i].sample[3] += (samples[1] * vol[3]) >> 16;
408 else if (vol[0] + vol[1] > 0)
410 for (i = 0;i < count;i++)
412 paintbuffer[i].sample[0] += (samples[0] * vol[0]) >> 16;
413 paintbuffer[i].sample[1] += (samples[1] * vol[1]) >> 16;
418 else if (sb->format.channels == 1)
420 if (vol[6] + vol[7] > 0)
422 for (i = 0;i < count;i++)
424 paintbuffer[i].sample[0] += (samples[0] * vol[0]) >> 16;
425 paintbuffer[i].sample[1] += (samples[0] * vol[1]) >> 16;
426 paintbuffer[i].sample[2] += (samples[0] * vol[2]) >> 16;
427 paintbuffer[i].sample[3] += (samples[0] * vol[3]) >> 16;
428 paintbuffer[i].sample[4] += (samples[0] * vol[4]) >> 16;
429 paintbuffer[i].sample[5] += (samples[0] * vol[5]) >> 16;
430 paintbuffer[i].sample[6] += (samples[0] * vol[6]) >> 16;
431 paintbuffer[i].sample[7] += (samples[0] * vol[7]) >> 16;
435 else if (vol[4] + vol[5] > 0)
437 for (i = 0;i < count;i++)
439 paintbuffer[i].sample[0] += (samples[0] * vol[0]) >> 16;
440 paintbuffer[i].sample[1] += (samples[0] * vol[1]) >> 16;
441 paintbuffer[i].sample[2] += (samples[0] * vol[2]) >> 16;
442 paintbuffer[i].sample[3] += (samples[0] * vol[3]) >> 16;
443 paintbuffer[i].sample[4] += (samples[0] * vol[4]) >> 16;
444 paintbuffer[i].sample[5] += (samples[0] * vol[5]) >> 16;
448 else if (vol[2] + vol[3] > 0)
450 for (i = 0;i < count;i++)
452 paintbuffer[i].sample[0] += (samples[0] * vol[0]) >> 16;
453 paintbuffer[i].sample[1] += (samples[0] * vol[1]) >> 16;
454 paintbuffer[i].sample[2] += (samples[0] * vol[2]) >> 16;
455 paintbuffer[i].sample[3] += (samples[0] * vol[3]) >> 16;
459 else if (vol[0] + vol[1] > 0)
461 for (i = 0;i < count;i++)
463 paintbuffer[i].sample[0] += (samples[0] * vol[0]) >> 16;
464 paintbuffer[i].sample[1] += (samples[0] * vol[1]) >> 16;
470 return false; // unsupported number of channels in sound
478 void S_PaintChannels (snd_ringbuffer_t* rb, unsigned int starttime, unsigned int endtime)
480 unsigned int paintedtime;
482 paintedtime = starttime;
483 while (paintedtime < endtime)
485 unsigned int partialend, i, framecount;
488 // if paintbuffer is too small
489 if (endtime > paintedtime + PAINTBUFFER_SIZE)
490 partialend = paintedtime + PAINTBUFFER_SIZE;
492 partialend = endtime;
494 // clear the paint buffer
495 memset (paintbuffer, 0, (partialend - paintedtime) * sizeof (paintbuffer[0]));
497 // paint in the channels.
499 for (i = 0; i < total_channels ; i++, ch++)
502 unsigned int ltime, j;
507 for (j = 0;j < SND_LISTENERS;j++)
508 if (ch->listener_volume[j])
510 if (j == SND_LISTENERS)
512 if (!S_LoadSound (sfx, true))
515 // if the channel is paused
516 if (ch->flags & CHANNELFLAG_PAUSED)
518 int pausedtime = partialend - paintedtime;
519 ch->lastptime += pausedtime;
520 ch->end += pausedtime;
524 // if the sound hasn't been painted last time, update his position
525 if (ch->lastptime < paintedtime)
527 ch->pos += paintedtime - ch->lastptime;
529 // If the sound should have ended by then
530 if ((unsigned int)ch->pos > sfx->total_length)
534 if (sfx->loopstart >= 0)
535 loopstart = bound(0, sfx->loopstart, (int)sfx->total_length - 1);
538 if (ch->flags & CHANNELFLAG_FORCELOOP)
544 // If the sound is looped
546 ch->pos = (ch->pos - sfx->total_length) % (sfx->total_length - loopstart) + loopstart;
548 ch->pos = sfx->total_length;
549 ch->end = paintedtime + sfx->total_length - ch->pos;
554 while (ltime < partialend)
560 if (ch->end < partialend)
561 count = ch->end - ltime;
563 count = partialend - ltime;
567 for (j = 0; j < SND_LISTENERS; j++)
568 ch->listener_volume[j] = bound(0, ch->listener_volume[j], 255);
570 stop_paint = !SND_PaintChannel (ch, (unsigned int)count);
574 ch->lastptime = ltime;
580 if (ltime >= ch->end)
582 // if at end of loop, restart
583 if ((sfx->loopstart >= 0 || (ch->flags & CHANNELFLAG_FORCELOOP)) && !stop_paint)
585 ch->pos = bound(0, sfx->loopstart, (int)sfx->total_length - 1);
586 ch->end = ltime + sfx->total_length - ch->pos;
588 // channel just stopped
595 S_StopChannel (ch - channels);
601 S_CaptureAVISound (partialend - paintedtime);
602 framecount = S_TransferPaintBuffer (rb, paintedtime, partialend);
603 paintedtime += framecount;
605 // If there was not enough free space in the sound buffer, stop here
606 if (paintedtime != partialend)
608 Con_DPrintf(">> S_PaintChannels: Not enough free space in the sound buffer ( %u != %u)\n", paintedtime, partialend);