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 // FIXME: this desyncs with the video too easily
36 extern void SCR_CaptureVideo_SoundFrame(unsigned char *bufstereo16le, size_t length, int rate);
37 static void S_CaptureAVISound(size_t length)
40 unsigned char out[PAINTBUFFER_SIZE * 4];
41 unsigned char* out_ptr;
43 if (!cls.capturevideo_active)
46 // write the sound buffer as little endian 16bit interleaved stereo
47 for(i = 0, out_ptr = out; i < length; i++, out_ptr += 4)
51 n0 = paintbuffer[i].sample[0];
52 n0 = bound(-32768, n0, 32767);
53 out_ptr[0] = (unsigned char)n0;
54 out_ptr[1] = (unsigned char)(n0 >> 8);
56 n1 = paintbuffer[i].sample[1];
57 n1 = bound(-32768, n1, 32767);
58 out_ptr[2] = (unsigned char)n1;
59 out_ptr[3] = (unsigned char)(n1 >> 8);
61 SCR_CaptureVideo_SoundFrame(out, length, snd_renderbuffer->format.speed);
64 static unsigned int S_TransferPaintBuffer(snd_ringbuffer_t* rb, unsigned int starttime, unsigned int endtime)
66 unsigned int partialend;
69 if (!simsound && !SndSys_LockRenderBuffer())
72 partialend = starttime;
73 while (partialend < endtime) // handle recirculating buffer issues
75 unsigned int startoffset, maxframes, nbframes, i;
77 portable_sampleframe_t *painted_ptr;
80 startoffset = partialend % rb->maxframes;
81 maxframes = rb->maxframes - startoffset;
82 nbframes = endtime - partialend;
83 if (nbframes > maxframes)
86 rb_ptr = &rb->ring[startoffset * rb->format.width * rb->format.channels];
87 painted_ptr = &paintbuffer[partialend - starttime];
89 if (rb->format.width == 2) // 16bit
91 short *snd_out = (short*)rb_ptr;
92 if (rb->format.channels == 8) // 7.1 surround
94 for (i = 0;i < nbframes;i++, painted_ptr++)
96 *snd_out++ = bound(-32768, painted_ptr->sample[0], 32767);
97 *snd_out++ = bound(-32768, painted_ptr->sample[1], 32767);
98 *snd_out++ = bound(-32768, painted_ptr->sample[2], 32767);
99 *snd_out++ = bound(-32768, painted_ptr->sample[3], 32767);
100 *snd_out++ = bound(-32768, painted_ptr->sample[4], 32767);
101 *snd_out++ = bound(-32768, painted_ptr->sample[5], 32767);
102 *snd_out++ = bound(-32768, painted_ptr->sample[6], 32767);
103 *snd_out++ = bound(-32768, painted_ptr->sample[7], 32767);
106 else if (rb->format.channels == 6) // 5.1 surround
108 for (i = 0; i < nbframes; i++, painted_ptr++)
110 *snd_out++ = bound(-32768, painted_ptr->sample[0], 32767);
111 *snd_out++ = bound(-32768, painted_ptr->sample[1], 32767);
112 *snd_out++ = bound(-32768, painted_ptr->sample[2], 32767);
113 *snd_out++ = bound(-32768, painted_ptr->sample[3], 32767);
114 *snd_out++ = bound(-32768, painted_ptr->sample[4], 32767);
115 *snd_out++ = bound(-32768, painted_ptr->sample[5], 32767);
118 else if (rb->format.channels == 4) // 4.0 surround
120 for (i = 0; i < nbframes; i++, painted_ptr++)
122 *snd_out++ = bound(-32768, painted_ptr->sample[0], 32767);
123 *snd_out++ = bound(-32768, painted_ptr->sample[1], 32767);
124 *snd_out++ = bound(-32768, painted_ptr->sample[2], 32767);
125 *snd_out++ = bound(-32768, painted_ptr->sample[3], 32767);
128 else if (rb->format.channels == 2) // 2.0 stereo
130 for (i = 0; i < nbframes; i++, painted_ptr++)
132 *snd_out++ = bound(-32768, painted_ptr->sample[0], 32767);
133 *snd_out++ = bound(-32768, painted_ptr->sample[1], 32767);
136 else if (rb->format.channels == 1) // 1.0 mono
138 for (i = 0; i < nbframes; i++, painted_ptr++)
140 val = (painted_ptr->sample[0] + painted_ptr->sample[1]) >> 1;
141 *snd_out++ = bound(-32768, val, 32767);
147 unsigned char *snd_out = (unsigned char*)rb_ptr;
148 if (rb->format.channels == 8) // 7.1 surround
150 for (i = 0; i < nbframes; i++, painted_ptr++)
152 val = (painted_ptr->sample[0] >> 8) + 128; *snd_out++ = bound(0, val, 255);
153 val = (painted_ptr->sample[1] >> 8) + 128; *snd_out++ = bound(0, val, 255);
154 val = (painted_ptr->sample[2] >> 8) + 128; *snd_out++ = bound(0, val, 255);
155 val = (painted_ptr->sample[3] >> 8) + 128; *snd_out++ = bound(0, val, 255);
156 val = (painted_ptr->sample[4] >> 8) + 128; *snd_out++ = bound(0, val, 255);
157 val = (painted_ptr->sample[5] >> 8) + 128; *snd_out++ = bound(0, val, 255);
158 val = (painted_ptr->sample[6] >> 8) + 128; *snd_out++ = bound(0, val, 255);
159 val = (painted_ptr->sample[7] >> 8) + 128; *snd_out++ = bound(0, val, 255);
162 else if (rb->format.channels == 6) // 5.1 surround
164 for (i = 0; i < nbframes; i++, painted_ptr++)
166 val = (painted_ptr->sample[0] >> 8) + 128; *snd_out++ = bound(0, val, 255);
167 val = (painted_ptr->sample[1] >> 8) + 128; *snd_out++ = bound(0, val, 255);
168 val = (painted_ptr->sample[2] >> 8) + 128; *snd_out++ = bound(0, val, 255);
169 val = (painted_ptr->sample[3] >> 8) + 128; *snd_out++ = bound(0, val, 255);
170 val = (painted_ptr->sample[4] >> 8) + 128; *snd_out++ = bound(0, val, 255);
171 val = (painted_ptr->sample[5] >> 8) + 128; *snd_out++ = bound(0, val, 255);
174 else if (rb->format.channels == 4) // 4.0 surround
176 for (i = 0; i < nbframes; i++, painted_ptr++)
178 val = (painted_ptr->sample[0] >> 8) + 128; *snd_out++ = bound(0, val, 255);
179 val = (painted_ptr->sample[1] >> 8) + 128; *snd_out++ = bound(0, val, 255);
180 val = (painted_ptr->sample[2] >> 8) + 128; *snd_out++ = bound(0, val, 255);
181 val = (painted_ptr->sample[3] >> 8) + 128; *snd_out++ = bound(0, val, 255);
184 else if (rb->format.channels == 2) // 2.0 stereo
186 for (i = 0; i < nbframes; i++, painted_ptr++)
188 val = (painted_ptr->sample[0] >> 8) + 128; *snd_out++ = bound(0, val, 255);
189 val = (painted_ptr->sample[1] >> 8) + 128; *snd_out++ = bound(0, val, 255);
192 else if (rb->format.channels == 1) // 1.0 mono
194 for (i = 0;i < nbframes;i++, painted_ptr++)
196 val = ((painted_ptr->sample[0] + painted_ptr->sample[1]) >> 9) + 128;
197 *snd_out++ = bound(0, val, 255);
202 partialend += nbframes;
205 rb->endframe = endtime;
207 // Remove outdated samples from the ring buffer, if any
208 if (rb->startframe < soundtime)
209 rb->startframe = soundtime;
212 SndSys_UnlockRenderBuffer();
214 return endtime - starttime;
219 ===============================================================================
223 ===============================================================================
226 static qboolean SND_PaintChannel (channel_t *ch, unsigned int count)
228 int snd_vol, vol[SND_LISTENERS];
229 const snd_buffer_t *sb;
230 unsigned int i, sb_offset;
232 // If this channel manages its own volume
233 if (ch->flags & CHANNELFLAG_FULLVOLUME)
236 snd_vol = (int)(volume.value * 256);
238 for (i = 0;i < SND_LISTENERS;i++)
239 vol[i] = ch->listener_volume[i] * snd_vol;
242 sb = ch->sfx->fetcher->getsb (ch, &sb_offset, count);
245 Con_DPrintf("SND_PaintChannel: ERROR: can't get sound buffer from sfx \"%s\"\n",
246 ch->sfx->name, count);
250 #if SND_LISTENERS != 8
251 # error the following code only supports up to 8 channels, update it
253 if (sb->format.width == 1)
255 const signed char *samples = (signed char*)sb->samples + (ch->pos - sb_offset) * sb->format.channels;
257 // Stereo sound support
258 if (sb->format.channels == 2)
260 if (vol[6] + vol[7] > 0)
262 for (i = 0;i < count;i++)
264 paintbuffer[i].sample[0] += (samples[0] * vol[0]) >> 8;
265 paintbuffer[i].sample[1] += (samples[1] * vol[1]) >> 8;
266 paintbuffer[i].sample[2] += (samples[0] * vol[2]) >> 8;
267 paintbuffer[i].sample[3] += (samples[1] * vol[3]) >> 8;
268 paintbuffer[i].sample[4] += ((samples[0] + samples[1]) * vol[4]) >> 9;
269 paintbuffer[i].sample[5] += ((samples[0] + samples[1]) * vol[5]) >> 9;
270 paintbuffer[i].sample[6] += (samples[0] * vol[6]) >> 8;
271 paintbuffer[i].sample[7] += (samples[1] * vol[7]) >> 8;
275 else if (vol[4] + vol[5] > 0)
277 for (i = 0;i < count;i++)
279 paintbuffer[i].sample[0] += (samples[0] * vol[0]) >> 8;
280 paintbuffer[i].sample[1] += (samples[1] * vol[1]) >> 8;
281 paintbuffer[i].sample[2] += (samples[0] * vol[2]) >> 8;
282 paintbuffer[i].sample[3] += (samples[1] * vol[3]) >> 8;
283 paintbuffer[i].sample[4] += ((samples[0] + samples[1]) * vol[4]) >> 9;
284 paintbuffer[i].sample[5] += ((samples[0] + samples[1]) * vol[5]) >> 9;
288 else if (vol[2] + vol[3] > 0)
290 for (i = 0;i < count;i++)
292 paintbuffer[i].sample[0] += (samples[0] * vol[0]) >> 8;
293 paintbuffer[i].sample[1] += (samples[1] * vol[1]) >> 8;
294 paintbuffer[i].sample[2] += (samples[0] * vol[2]) >> 8;
295 paintbuffer[i].sample[3] += (samples[1] * vol[3]) >> 8;
299 else if (vol[0] + vol[1] > 0)
301 for (i = 0;i < count;i++)
303 paintbuffer[i].sample[0] += (samples[0] * vol[0]) >> 8;
304 paintbuffer[i].sample[1] += (samples[1] * vol[1]) >> 8;
309 else if (sb->format.channels == 1)
311 if (vol[6] + vol[7] > 0)
313 for (i = 0;i < count;i++)
315 paintbuffer[i].sample[0] += (samples[0] * vol[0]) >> 8;
316 paintbuffer[i].sample[1] += (samples[0] * vol[1]) >> 8;
317 paintbuffer[i].sample[2] += (samples[0] * vol[2]) >> 8;
318 paintbuffer[i].sample[3] += (samples[0] * vol[3]) >> 8;
319 paintbuffer[i].sample[4] += (samples[0] * vol[4]) >> 8;
320 paintbuffer[i].sample[5] += (samples[0] * vol[5]) >> 8;
321 paintbuffer[i].sample[6] += (samples[0] * vol[6]) >> 8;
322 paintbuffer[i].sample[7] += (samples[0] * vol[7]) >> 8;
326 else if (vol[4] + vol[5] > 0)
328 for (i = 0;i < count;i++)
330 paintbuffer[i].sample[0] += (samples[0] * vol[0]) >> 8;
331 paintbuffer[i].sample[1] += (samples[0] * vol[1]) >> 8;
332 paintbuffer[i].sample[2] += (samples[0] * vol[2]) >> 8;
333 paintbuffer[i].sample[3] += (samples[0] * vol[3]) >> 8;
334 paintbuffer[i].sample[4] += (samples[0] * vol[4]) >> 8;
335 paintbuffer[i].sample[5] += (samples[0] * vol[5]) >> 8;
339 else if (vol[2] + vol[3] > 0)
341 for (i = 0;i < count;i++)
343 paintbuffer[i].sample[0] += (samples[0] * vol[0]) >> 8;
344 paintbuffer[i].sample[1] += (samples[0] * vol[1]) >> 8;
345 paintbuffer[i].sample[2] += (samples[0] * vol[2]) >> 8;
346 paintbuffer[i].sample[3] += (samples[0] * vol[3]) >> 8;
350 else if (vol[0] + vol[1] > 0)
352 for (i = 0;i < count;i++)
354 paintbuffer[i].sample[0] += (samples[0] * vol[0]) >> 8;
355 paintbuffer[i].sample[1] += (samples[0] * vol[1]) >> 8;
361 return false; // unsupported number of channels in sound
363 else if (sb->format.width == 2)
365 const signed short *samples = (signed short*)sb->samples + (ch->pos - sb_offset) * sb->format.channels;
367 // Stereo sound support
368 if (sb->format.channels == 2)
370 if (vol[6] + vol[7] > 0)
372 for (i = 0;i < count;i++)
374 paintbuffer[i].sample[0] += (samples[0] * vol[0]) >> 16;
375 paintbuffer[i].sample[1] += (samples[1] * vol[1]) >> 16;
376 paintbuffer[i].sample[2] += (samples[0] * vol[2]) >> 16;
377 paintbuffer[i].sample[3] += (samples[1] * vol[3]) >> 16;
378 paintbuffer[i].sample[4] += ((samples[0] + samples[1]) * vol[4]) >> 17;
379 paintbuffer[i].sample[5] += ((samples[0] + samples[1]) * vol[5]) >> 17;
380 paintbuffer[i].sample[6] += (samples[0] * vol[6]) >> 16;
381 paintbuffer[i].sample[7] += (samples[1] * vol[7]) >> 16;
385 else if (vol[4] + vol[5] > 0)
387 for (i = 0;i < count;i++)
389 paintbuffer[i].sample[0] += (samples[0] * vol[0]) >> 16;
390 paintbuffer[i].sample[1] += (samples[1] * vol[1]) >> 16;
391 paintbuffer[i].sample[2] += (samples[0] * vol[2]) >> 16;
392 paintbuffer[i].sample[3] += (samples[1] * vol[3]) >> 16;
393 paintbuffer[i].sample[4] += ((samples[0] + samples[1]) * vol[4]) >> 17;
394 paintbuffer[i].sample[5] += ((samples[0] + samples[1]) * vol[5]) >> 17;
398 else if (vol[2] + vol[3] > 0)
400 for (i = 0;i < count;i++)
402 paintbuffer[i].sample[0] += (samples[0] * vol[0]) >> 16;
403 paintbuffer[i].sample[1] += (samples[1] * vol[1]) >> 16;
404 paintbuffer[i].sample[2] += (samples[0] * vol[2]) >> 16;
405 paintbuffer[i].sample[3] += (samples[1] * vol[3]) >> 16;
409 else if (vol[0] + vol[1] > 0)
411 for (i = 0;i < count;i++)
413 paintbuffer[i].sample[0] += (samples[0] * vol[0]) >> 16;
414 paintbuffer[i].sample[1] += (samples[1] * vol[1]) >> 16;
419 else if (sb->format.channels == 1)
421 if (vol[6] + vol[7] > 0)
423 for (i = 0;i < count;i++)
425 paintbuffer[i].sample[0] += (samples[0] * vol[0]) >> 16;
426 paintbuffer[i].sample[1] += (samples[0] * vol[1]) >> 16;
427 paintbuffer[i].sample[2] += (samples[0] * vol[2]) >> 16;
428 paintbuffer[i].sample[3] += (samples[0] * vol[3]) >> 16;
429 paintbuffer[i].sample[4] += (samples[0] * vol[4]) >> 16;
430 paintbuffer[i].sample[5] += (samples[0] * vol[5]) >> 16;
431 paintbuffer[i].sample[6] += (samples[0] * vol[6]) >> 16;
432 paintbuffer[i].sample[7] += (samples[0] * vol[7]) >> 16;
436 else if (vol[4] + vol[5] > 0)
438 for (i = 0;i < count;i++)
440 paintbuffer[i].sample[0] += (samples[0] * vol[0]) >> 16;
441 paintbuffer[i].sample[1] += (samples[0] * vol[1]) >> 16;
442 paintbuffer[i].sample[2] += (samples[0] * vol[2]) >> 16;
443 paintbuffer[i].sample[3] += (samples[0] * vol[3]) >> 16;
444 paintbuffer[i].sample[4] += (samples[0] * vol[4]) >> 16;
445 paintbuffer[i].sample[5] += (samples[0] * vol[5]) >> 16;
449 else if (vol[2] + vol[3] > 0)
451 for (i = 0;i < count;i++)
453 paintbuffer[i].sample[0] += (samples[0] * vol[0]) >> 16;
454 paintbuffer[i].sample[1] += (samples[0] * vol[1]) >> 16;
455 paintbuffer[i].sample[2] += (samples[0] * vol[2]) >> 16;
456 paintbuffer[i].sample[3] += (samples[0] * vol[3]) >> 16;
460 else if (vol[0] + vol[1] > 0)
462 for (i = 0;i < count;i++)
464 paintbuffer[i].sample[0] += (samples[0] * vol[0]) >> 16;
465 paintbuffer[i].sample[1] += (samples[0] * vol[1]) >> 16;
471 return false; // unsupported number of channels in sound
479 void S_PaintChannels (snd_ringbuffer_t* rb, unsigned int starttime, unsigned int endtime)
481 unsigned int paintedtime;
483 paintedtime = starttime;
484 while (paintedtime < endtime)
486 unsigned int partialend, i, framecount;
489 // if paintbuffer is too small
490 if (endtime > paintedtime + PAINTBUFFER_SIZE)
491 partialend = paintedtime + PAINTBUFFER_SIZE;
493 partialend = endtime;
495 // clear the paint buffer
496 memset (paintbuffer, 0, (partialend - paintedtime) * sizeof (paintbuffer[0]));
498 // paint in the channels.
500 for (i = 0; i < total_channels ; i++, ch++)
503 unsigned int ltime, j;
508 for (j = 0;j < SND_LISTENERS;j++)
509 if (ch->listener_volume[j])
511 if (j == SND_LISTENERS)
513 if (!S_LoadSound (sfx, true))
516 // if the channel is paused
517 if (ch->flags & CHANNELFLAG_PAUSED)
519 int pausedtime = partialend - paintedtime;
520 ch->lastptime += pausedtime;
521 ch->end += pausedtime;
525 // if the sound hasn't been painted last time, update his position
526 if (ch->lastptime < paintedtime)
528 ch->pos += paintedtime - ch->lastptime;
530 // If the sound should have ended by then
531 if ((unsigned int)ch->pos > sfx->total_length)
535 if (sfx->loopstart >= 0)
536 loopstart = bound(0, sfx->loopstart, (int)sfx->total_length - 1);
539 if (ch->flags & CHANNELFLAG_FORCELOOP)
545 // If the sound is looped
547 ch->pos = (ch->pos - sfx->total_length) % (sfx->total_length - loopstart) + loopstart;
549 ch->pos = sfx->total_length;
550 ch->end = paintedtime + sfx->total_length - ch->pos;
555 while (ltime < partialend)
561 if (ch->end < partialend)
562 count = ch->end - ltime;
564 count = partialend - ltime;
568 for (j = 0; j < SND_LISTENERS; j++)
569 ch->listener_volume[j] = bound(0, ch->listener_volume[j], 255);
571 stop_paint = !SND_PaintChannel (ch, (unsigned int)count);
575 ch->lastptime = ltime;
581 if (ltime >= ch->end)
583 // if at end of loop, restart
584 if ((sfx->loopstart >= 0 || (ch->flags & CHANNELFLAG_FORCELOOP)) && !stop_paint)
586 ch->pos = bound(0, sfx->loopstart, (int)sfx->total_length - 1);
587 ch->end = ltime + sfx->total_length - ch->pos;
589 // channel just stopped
596 S_StopChannel (ch - channels);
602 S_CaptureAVISound (partialend - paintedtime);
603 framecount = S_TransferPaintBuffer (rb, paintedtime, partialend);
604 paintedtime += framecount;
606 // If there was not enough free space in the sound buffer, stop here
607 if (paintedtime != partialend)
609 Con_DPrintf(">> S_PaintChannels: Not enough free space in the sound buffer ( %u != %u)\n", paintedtime, partialend);