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.
20 // snd_mix.c -- portable code to mix sounds
25 typedef struct portable_samplepair_s
29 } portable_samplepair_t;
31 // LordHavoc: was 512, expanded to 2048
32 #define PAINTBUFFER_SIZE 2048
33 portable_samplepair_t paintbuffer[PAINTBUFFER_SIZE];
35 // FIXME: this desyncs with the video too easily
36 extern qboolean cl_capturevideo_active;
37 extern void SCR_CaptureVideo_SoundFrame(unsigned char *bufstereo16le, size_t length, int rate);
38 void S_CaptureAVISound(portable_samplepair_t *buf, size_t length)
42 unsigned char out[PAINTBUFFER_SIZE * 4];
43 if (!cl_capturevideo_active)
45 // write the sound buffer as little endian 16bit interleaved stereo
46 for(i = 0;i < length;i++)
49 n = bound(-32768, n, 32767);
50 out[i*4+0] = n & 0xFF;
51 out[i*4+1] = (n >> 8) & 0xFF;
53 n = bound(-32768, n, 32767);
54 out[i*4+2] = n & 0xFF;
55 out[i*4+3] = (n >> 8) & 0xFF;
57 SCR_CaptureVideo_SoundFrame(out, length, shm->format.speed);
60 // TODO: rewrite this function
61 void S_TransferPaintBuffer(int endtime)
64 if ((pbuf = S_LockBuffer()))
71 snd_p = (int *) paintbuffer;
72 lpaintedtime = paintedtime;
73 if (shm->format.width == 2)
77 if (shm->format.channels == 2)
79 // 16bit 2 channels (stereo)
80 while (lpaintedtime < endtime)
82 // handle recirculating buffer issues
83 i = lpaintedtime & ((shm->samples >> 1) - 1);
84 snd_out = (short *) pbuf + (i << 1);
85 snd_linear_count = (shm->samples >> 1) - i;
86 if (snd_linear_count > endtime - lpaintedtime)
87 snd_linear_count = endtime - lpaintedtime;
88 snd_linear_count <<= 1;
89 if (snd_swapstereo.value)
91 for (i = 0;i < snd_linear_count;i += 2)
93 snd_out[i ] = bound(-32768, snd_p[i + 1], 32767);
94 snd_out[i + 1] = bound(-32768, snd_p[i ], 32767);
99 for (i = 0;i < snd_linear_count;i += 2)
101 snd_out[i ] = bound(-32768, snd_p[i ], 32767);
102 snd_out[i + 1] = bound(-32768, snd_p[i + 1], 32767);
105 snd_p += snd_linear_count;
106 lpaintedtime += (snd_linear_count >> 1);
111 // 16bit 1 channel (mono)
112 while (lpaintedtime < endtime)
114 // handle recirculating buffer issues
115 i = lpaintedtime & (shm->samples - 1);
116 snd_out = (short *) pbuf + i;
117 snd_linear_count = shm->samples - i;
118 if (snd_linear_count > endtime - lpaintedtime)
119 snd_linear_count = endtime - lpaintedtime;
120 for (i = 0;i < snd_linear_count;i++)
122 val = (snd_p[i * 2 + 0] + snd_p[i * 2 + 1]) >> 1;
123 snd_out[i] = bound(-32768, val, 32767);
125 snd_p += snd_linear_count << 1;
126 lpaintedtime += snd_linear_count;
133 unsigned char *snd_out;
134 if (shm->format.channels == 2)
136 // 8bit 2 channels (stereo)
137 while (lpaintedtime < endtime)
139 // handle recirculating buffer issues
140 i = lpaintedtime & ((shm->samples >> 1) - 1);
141 snd_out = (unsigned char *) pbuf + (i << 1);
142 snd_linear_count = (shm->samples >> 1) - i;
143 if (snd_linear_count > endtime - lpaintedtime)
144 snd_linear_count = endtime - lpaintedtime;
145 snd_linear_count <<= 1;
146 if (snd_swapstereo.value)
148 for (i = 0;i < snd_linear_count;i += 2)
150 val = (snd_p[i + 1] >> 8) + 128;
151 snd_out[i ] = bound(0, val, 255);
152 val = (snd_p[i ] >> 8) + 128;
153 snd_out[i + 1] = bound(0, val, 255);
158 for (i = 0;i < snd_linear_count;i += 2)
160 val = (snd_p[i ] >> 8) + 128;
161 snd_out[i ] = bound(0, val, 255);
162 val = (snd_p[i + 1] >> 8) + 128;
163 snd_out[i + 1] = bound(0, val, 255);
166 snd_p += snd_linear_count;
167 lpaintedtime += (snd_linear_count >> 1);
172 // 8bit 1 channel (mono)
173 while (lpaintedtime < endtime)
175 // handle recirculating buffer issues
176 i = lpaintedtime & (shm->samples - 1);
177 snd_out = (unsigned char *) pbuf + i;
178 snd_linear_count = shm->samples - i;
179 if (snd_linear_count > endtime - lpaintedtime)
180 snd_linear_count = endtime - lpaintedtime;
181 for (i = 0;i < snd_linear_count;i++)
183 val = ((snd_p[i * 2] + snd_p[i * 2 + 1]) >> 9) + 128;
184 snd_out[i ] = bound(0, val, 255);
186 snd_p += snd_linear_count << 1;
187 lpaintedtime += snd_linear_count;
198 ===============================================================================
202 ===============================================================================
205 qboolean SND_PaintChannelFrom8 (channel_t *ch, int endtime);
206 qboolean SND_PaintChannelFrom16 (channel_t *ch, int endtime);
208 void S_PaintChannels(int endtime)
216 while (paintedtime < endtime)
218 // if paintbuffer is smaller than DMA buffer
220 if (endtime - paintedtime > PAINTBUFFER_SIZE)
221 end = paintedtime + PAINTBUFFER_SIZE;
223 // clear the paint buffer
224 memset (&paintbuffer, 0, (end - paintedtime) * sizeof (paintbuffer[0]));
226 // paint in the channels.
228 for (i=0; i<total_channels ; i++, ch++)
233 if (!ch->leftvol && !ch->rightvol)
235 if (!S_LoadSound (sfx, true))
238 // if the channel is paused
239 if (ch->flags & CHANNELFLAG_PAUSED)
241 int pausedtime = end - paintedtime;
242 ch->lastptime += pausedtime;
243 ch->end += pausedtime;
247 // if the sound hasn't been painted last time, update his position
248 if (ch->lastptime < paintedtime)
250 ch->pos += paintedtime - ch->lastptime;
252 // If the sound should have ended by then
253 if ((unsigned int)ch->pos > sfx->total_length)
257 if (ch->flags & CHANNELFLAG_FORCELOOP)
261 if (sfx->loopstart >= 0)
262 loopstart = sfx->loopstart;
264 // If the sound is looped
266 ch->pos = (ch->pos - sfx->total_length) % (sfx->total_length - loopstart) + loopstart;
268 ch->pos = sfx->total_length;
269 ch->end = paintedtime + sfx->total_length - ch->pos;
280 count = (int)ch->end - ltime;
286 if (ch->leftvol > 255)
288 if (ch->rightvol > 255)
291 if (sfx->format.width == 1)
292 stop_paint = !SND_PaintChannelFrom8 (ch, count);
294 stop_paint = !SND_PaintChannelFrom16 (ch, count);
299 ch->lastptime = ltime;
305 if (ltime >= ch->end)
307 // if at end of loop, restart
308 if ((sfx->loopstart >= 0 || (ch->flags & CHANNELFLAG_FORCELOOP)) && !stop_paint)
310 ch->pos = bound(0, sfx->loopstart, (int)sfx->total_length - 1);
311 ch->end = ltime + sfx->total_length - ch->pos;
313 // channel just stopped
320 S_StopChannel (ch - channels);
326 // transfer out according to DMA format
327 S_CaptureAVISound (paintbuffer, end - paintedtime);
328 S_TransferPaintBuffer(end);
334 // TODO: Try to merge SND_PaintChannelFrom8 and SND_PaintChannelFrom16
335 qboolean SND_PaintChannelFrom8 (channel_t *ch, int count)
337 int snd_vol, leftvol, rightvol;
338 const signed char *sfx;
339 const sfxbuffer_t *sb;
342 // If this channel manages its own volume
343 if (ch->flags & CHANNELFLAG_FULLVOLUME)
346 snd_vol = volume.value * 256;
348 leftvol = ch->leftvol * snd_vol;
349 rightvol = ch->rightvol * snd_vol;
351 sb = ch->sfx->fetcher->getsb (ch, ch->pos, count);
355 // Stereo sound support
356 if (ch->sfx->format.channels == 2)
358 sfx = (signed char *)sb->data + (ch->pos - sb->offset) * 2;
359 for (i = 0;i < count;i++)
361 paintbuffer[i].left += (*sfx++ * leftvol) >> 8;
362 paintbuffer[i].right += (*sfx++ * rightvol) >> 8;
367 sfx = (signed char *)sb->data + ch->pos - sb->offset;
368 for (i = 0;i < count;i++)
370 paintbuffer[i].left += (*sfx * leftvol) >> 8;
371 paintbuffer[i].right += (*sfx++ * rightvol) >> 8;
378 qboolean SND_PaintChannelFrom16 (channel_t *ch, int count)
380 int snd_vol, leftvol, rightvol;
382 const sfxbuffer_t *sb;
385 // If this channel manages its own volume
386 if (ch->flags & CHANNELFLAG_FULLVOLUME)
389 snd_vol = volume.value * 256;
391 leftvol = ch->leftvol * snd_vol;
392 rightvol = ch->rightvol * snd_vol;
394 sb = ch->sfx->fetcher->getsb (ch, ch->pos, count);
398 // Stereo sound support
399 if (ch->sfx->format.channels == 2)
401 sfx = (signed short *)sb->data + (ch->pos - sb->offset) * 2;
403 for (i=0 ; i<count ; i++)
405 paintbuffer[i].left += (*sfx++ * leftvol) >> 16;
406 paintbuffer[i].right += (*sfx++ * rightvol) >> 16;
411 sfx = (signed short *)sb->data + ch->pos - sb->offset;
413 for (i=0 ; i<count ; i++)
415 paintbuffer[i].left += (*sfx * leftvol) >> 16;
416 paintbuffer[i].right += (*sfx++ * rightvol) >> 16;