]> icculus.org git repositories - divverent/darkplaces.git/blob - snd_mix.c
cleaned up and fixed collisions with brush models (example: you can now ramp jump...
[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 // snd_mix.c -- portable code to mix sounds for snd_dma.c
21
22 #include "quakedef.h"
23
24 #ifdef _WIN32
25 #include "winquake.h"
26 #else
27 #define DWORD   unsigned long
28 #endif
29
30 // LordHavoc: was 512, expanded to 2048
31 #define PAINTBUFFER_SIZE        2048
32 portable_samplepair_t paintbuffer[PAINTBUFFER_SIZE];
33 int             snd_scaletable[32][256];
34 int     *snd_p, snd_linear_count, snd_vol;
35 short   *snd_out;
36
37 /*
38 // LordHavoc: disabled this because it desyncs with the video too easily
39 extern cvar_t cl_avidemo;
40 static FILE *cl_avidemo_soundfile = NULL;
41 void S_CaptureAVISound(portable_samplepair_t *buf, int length)
42 {
43         int i, n;
44         qbyte out[PAINTBUFFER_SIZE * 4];
45         char filename[MAX_OSPATH];
46
47         if (cl_avidemo.value >= 0.1f)
48         {
49                 if (cl_avidemo_soundfile == NULL)
50                 {
51                         sprintf (filename, "%s/dpavi.wav", com_gamedir);
52                         cl_avidemo_soundfile = fopen(filename, "wb");
53                         memset(out, 0, 44);
54                         fwrite(out, 1, 44, cl_avidemo_soundfile);
55                         // header will be filled out when file is closed
56                 }
57                 fseek(cl_avidemo_soundfile, 0, SEEK_END);
58                 // write the sound buffer as little endian 16bit interleaved stereo
59                 for(i = 0;i < length;i++)
60                 {
61                         n = buf[i].left >> 2; // quiet enough to prevent clipping most of the time
62                         n = bound(-32768, n, 32767);
63                         out[i*4+0] = n & 0xFF;
64                         out[i*4+1] = (n >> 8) & 0xFF;
65                         n = buf[i].right >> 2; // quiet enough to prevent clipping most of the time
66                         n = bound(-32768, n, 32767);
67                         out[i*4+2] = n & 0xFF;
68                         out[i*4+3] = (n >> 8) & 0xFF;
69                 }
70                 if (fwrite(out, 4, length, cl_avidemo_soundfile) < length)
71                 {
72                         Cvar_SetValueQuick(&cl_avidemo, 0);
73                         Con_Printf("avi saving sound failed, out of disk space?  stopping avi demo capture.\n");
74                 }
75         }
76         else if (cl_avidemo_soundfile)
77         {
78                 // file has not been closed yet, close it
79                 fseek(cl_avidemo_soundfile, 0, SEEK_END);
80                 i = ftell(cl_avidemo_soundfile);
81
82                 //"RIFF", (int) unknown (chunk size), "WAVE",
83                 //"fmt ", (int) 16 (chunk size), (short) format 1 (uncompressed PCM), (short) 2 channels, (int) unknown rate, (int) unknown bytes per second, (short) 4 bytes per sample (channels * bytes per channel), (short) 16 bits per channel
84                 //"data", (int) unknown (chunk size)
85                 memcpy(out, "RIFF****WAVEfmt \x10\x00\x00\x00\x01\x00\x02\x00********\x04\x00\x10\x00data****", 44);
86                 // the length of the whole RIFF chunk
87                 n = i - 8;
88                 out[4] = (n) & 0xFF;
89                 out[5] = (n >> 8) & 0xFF;
90                 out[6] = (n >> 16) & 0xFF;
91                 out[7] = (n >> 24) & 0xFF;
92                 // rate
93                 n = shm->speed;
94                 out[24] = (n) & 0xFF;
95                 out[25] = (n >> 8) & 0xFF;
96                 out[26] = (n >> 16) & 0xFF;
97                 out[27] = (n >> 24) & 0xFF;
98                 // bytes per second (rate * channels * bytes per channel)
99                 n = shm->speed * 4;
100                 out[28] = (n) & 0xFF;
101                 out[29] = (n >> 8) & 0xFF;
102                 out[30] = (n >> 16) & 0xFF;
103                 out[31] = (n >> 24) & 0xFF;
104                 // the length of the data chunk
105                 n = i - 44;
106                 out[40] = (n) & 0xFF;
107                 out[41] = (n >> 8) & 0xFF;
108                 out[42] = (n >> 16) & 0xFF;
109                 out[43] = (n >> 24) & 0xFF;
110
111                 fseek(cl_avidemo_soundfile, 0, SEEK_SET);
112                 fwrite(out, 1, 44, cl_avidemo_soundfile);
113                 fclose(cl_avidemo_soundfile);
114                 cl_avidemo_soundfile = NULL;
115         }
116 }
117 */
118
119 void Snd_WriteLinearBlastStereo16 (void)
120 {
121         int             i;
122         int             val;
123
124         if (snd_swapstereo.value)
125         {
126                 for (i=0 ; i<snd_linear_count ; i+=2)
127                 {
128                         val = (snd_p[i+1]*snd_vol)>>8;
129                         snd_out[i  ] = bound(-32768, val, 32767);
130                         val = (snd_p[i  ]*snd_vol)>>8;
131                         snd_out[i+1] = bound(-32768, val, 32767);
132                 }
133         }
134         else
135         {
136                 for (i=0 ; i<snd_linear_count ; i+=2)
137                 {
138                         val = (snd_p[i]*snd_vol)>>8;
139                         snd_out[i] = bound(-32768, val, 32767);
140                         val = (snd_p[i+1]*snd_vol)>>8;
141                         snd_out[i+1] = bound(-32768, val, 32767);
142                 }
143         }
144 }
145
146 void S_TransferStereo16 (int endtime)
147 {
148         int             lpos;
149         int             lpaintedtime;
150         DWORD   *pbuf;
151 #ifdef _WIN32
152         int             reps;
153         DWORD   dwSize,dwSize2;
154         DWORD   *pbuf2;
155         HRESULT hresult;
156 #endif
157         
158         snd_vol = volume.value*256;
159
160         snd_p = (int *) paintbuffer;
161         lpaintedtime = paintedtime;
162
163 #ifdef _WIN32
164         if (pDSBuf)
165         {
166                 reps = 0;
167
168                 while ((hresult = pDSBuf->lpVtbl->Lock(pDSBuf, 0, gSndBufSize, &pbuf, &dwSize, &pbuf2, &dwSize2, 0)) != DS_OK)
169                 {
170                         if (hresult != DSERR_BUFFERLOST)
171                         {
172                                 Con_Printf ("S_TransferStereo16: DS::Lock Sound Buffer Failed\n");
173                                 S_Shutdown ();
174                                 S_Startup ();
175                                 return;
176                         }
177
178                         if (++reps > 10000)
179                         {
180                                 Con_Printf ("S_TransferStereo16: DS: couldn't restore buffer\n");
181                                 S_Shutdown ();
182                                 S_Startup ();
183                                 return;
184                         }
185                 }
186         }
187         else
188 #endif
189         {
190                 pbuf = (DWORD *)shm->buffer;
191         }
192
193         while (lpaintedtime < endtime)
194         {
195         // handle recirculating buffer issues
196                 lpos = lpaintedtime & ((shm->samples>>1)-1);
197
198                 snd_out = (short *) pbuf + (lpos<<1);
199
200                 snd_linear_count = (shm->samples>>1) - lpos;
201                 if (lpaintedtime + snd_linear_count > endtime)
202                         snd_linear_count = endtime - lpaintedtime;
203
204                 snd_linear_count <<= 1;
205
206         // write a linear blast of samples
207                 Snd_WriteLinearBlastStereo16 ();
208
209                 snd_p += snd_linear_count;
210                 lpaintedtime += (snd_linear_count>>1);
211         }
212
213 #ifdef _WIN32
214         if (pDSBuf)
215                 pDSBuf->lpVtbl->Unlock(pDSBuf, pbuf, dwSize, NULL, 0);
216 #endif
217 }
218
219 void S_TransferPaintBuffer(int endtime)
220 {
221         int     out_idx;
222         int     count;
223         int     out_mask;
224         int     *p;
225         int     step;
226         int             val;
227         int             snd_vol;
228         DWORD   *pbuf;
229 #ifdef _WIN32
230         int             reps;
231         DWORD   dwSize,dwSize2;
232         DWORD   *pbuf2;
233         HRESULT hresult;
234 #endif
235
236         if (shm->samplebits == 16 && shm->channels == 2)
237         {
238                 S_TransferStereo16 (endtime);
239                 return;
240         }
241
242         p = (int *) paintbuffer;
243         count = (endtime - paintedtime) * shm->channels;
244         out_mask = shm->samples - 1;
245         out_idx = paintedtime * shm->channels & out_mask;
246         step = 3 - shm->channels;
247         snd_vol = volume.value*256;
248
249 #ifdef _WIN32
250         if (pDSBuf)
251         {
252                 reps = 0;
253
254                 while ((hresult = pDSBuf->lpVtbl->Lock(pDSBuf, 0, gSndBufSize, &pbuf, &dwSize, &pbuf2,&dwSize2, 0)) != DS_OK)
255                 {
256                         if (hresult != DSERR_BUFFERLOST)
257                         {
258                                 Con_Printf ("S_TransferPaintBuffer: DS::Lock Sound Buffer Failed\n");
259                                 S_Shutdown ();
260                                 S_Startup ();
261                                 return;
262                         }
263
264                         if (++reps > 10000)
265                         {
266                                 Con_Printf ("S_TransferPaintBuffer: DS: couldn't restore buffer\n");
267                                 S_Shutdown ();
268                                 S_Startup ();
269                                 return;
270                         }
271                 }
272         }
273         else
274 #endif
275         {
276                 pbuf = (DWORD *)shm->buffer;
277         }
278
279         if (shm->samplebits == 16)
280         {
281                 short *out = (short *) pbuf;
282                 while (count--)
283                 {
284                         val = (*p * snd_vol) >> 8;
285                         out[out_idx] = bound(-32768, val, 32767);
286                         p+= step;
287                         out_idx = (out_idx + 1) & out_mask;
288                 }
289         }
290         else if (shm->samplebits == 8)
291         {
292                 unsigned char *out = (unsigned char *) pbuf;
293                 while (count--)
294                 {
295                         val = ((*p * snd_vol) >> 16) + 128;
296                         out[out_idx] = bound(0, val, 255);
297                         p+= step;
298                         out_idx = (out_idx + 1) & out_mask;
299                 }
300         }
301
302 #ifdef _WIN32
303         if (pDSBuf)
304         {
305                 DWORD dwNewpos, dwWrite;
306                 int il = paintedtime;
307                 int ir = endtime - paintedtime;
308
309                 ir += il;
310
311                 pDSBuf->lpVtbl->Unlock(pDSBuf, pbuf, dwSize, NULL, 0);
312
313                 pDSBuf->lpVtbl->GetCurrentPosition(pDSBuf, &dwNewpos, &dwWrite);
314
315 //              if ((dwNewpos >= il) && (dwNewpos <= ir))
316 //                      Con_Printf("%d-%d p %d c\n", il, ir, dwNewpos);
317         }
318 #endif
319 }
320
321
322 /*
323 ===============================================================================
324
325 CHANNEL MIXING
326
327 ===============================================================================
328 */
329
330 void SND_PaintChannelFrom8 (channel_t *ch, sfxcache_t *sc, int endtime);
331 void SND_PaintChannelFrom16 (channel_t *ch, sfxcache_t *sc, int endtime);
332
333 void S_PaintChannels(int endtime)
334 {
335         int     i;
336         int     end;
337         channel_t *ch;
338         sfxcache_t      *sc;
339         int             ltime, count;
340
341         while (paintedtime < endtime)
342         {
343                 // if paintbuffer is smaller than DMA buffer
344                 end = endtime;
345                 if (endtime - paintedtime > PAINTBUFFER_SIZE)
346                         end = paintedtime + PAINTBUFFER_SIZE;
347
348                 // clear the paint buffer
349                 memset(paintbuffer, 0, (end - paintedtime) * sizeof(portable_samplepair_t));
350
351                 // paint in the channels.
352                 ch = channels;
353                 for (i=0; i<total_channels ; i++, ch++)
354                 {
355                         if (!ch->sfx)
356                                 continue;
357                         if (!ch->leftvol && !ch->rightvol)
358                                 continue;
359                         sc = S_LoadSound (ch->sfx);
360                         if (!sc)
361                                 continue;
362
363                         ltime = paintedtime;
364
365                         while (ltime < end)
366                         {
367                                 // paint up to end
368                                 if (ch->end < end)
369                                         count = ch->end - ltime;
370                                 else
371                                         count = end - ltime;
372
373                                 if (count > 0)
374                                 {
375                                         if (sc->width == 1)
376                                                 SND_PaintChannelFrom8(ch, sc, count);
377                                         else
378                                                 SND_PaintChannelFrom16(ch, sc, count);
379
380                                         ltime += count;
381                                 }
382
383                                 // if at end of loop, restart
384                                 if (ltime >= ch->end)
385                                 {
386                                         if (sc->loopstart >= 0)
387                                         {
388                                                 ch->pos = sc->loopstart;
389                                                 ch->end = ltime + sc->length - ch->pos;
390                                         }
391                                         else
392                                         {
393                                                 // channel just stopped
394                                                 ch->sfx = NULL;
395                                                 break;
396                                         }
397                                 }
398                         }
399
400                 }
401
402                 // transfer out according to DMA format
403                 //S_CaptureAVISound(paintbuffer, end - paintedtime);
404                 S_TransferPaintBuffer(end);
405                 paintedtime = end;
406         }
407 }
408
409 void SND_InitScaletable (void)
410 {
411         int             i, j;
412
413         for (i=0 ; i<32 ; i++)
414                 for (j=0 ; j<256 ; j++)
415                         snd_scaletable[i][j] = ((signed char)j) * i * 8;
416 }
417
418
419 void SND_PaintChannelFrom8 (channel_t *ch, sfxcache_t *sc, int count)
420 {
421 //      int     data;
422         int             *lscale, *rscale;
423         unsigned char *sfx;
424         int             i;
425
426         if (ch->leftvol > 255)
427                 ch->leftvol = 255;
428         if (ch->rightvol > 255)
429                 ch->rightvol = 255;
430
431         lscale = snd_scaletable[ch->leftvol >> 3];
432         rscale = snd_scaletable[ch->rightvol >> 3];
433         if (sc->stereo)
434         {
435                 // LordHavoc: stereo sound support, and optimizations
436                 sfx = (unsigned char *)sc->data + ch->pos * 2;
437
438                 for (i=0 ; i<count ; i++)
439                 {
440                         paintbuffer[i].left += lscale[*sfx++];
441                         paintbuffer[i].right += rscale[*sfx++];
442                 }
443                 
444         }
445         else
446         {
447                 sfx = (unsigned char *)sc->data + ch->pos;
448
449                 for (i=0 ; i<count ; i++)
450                 {
451                         paintbuffer[i].left += lscale[*sfx];
452                         paintbuffer[i].right += rscale[*sfx++];
453                 }
454
455         }
456         ch->pos += count;
457 }
458
459 void SND_PaintChannelFrom16 (channel_t *ch, sfxcache_t *sc, int count)
460 {
461 //      int data;
462 //      int left, right;
463         int leftvol, rightvol;
464         signed short *sfx;
465         int     i;
466
467         leftvol = ch->leftvol;
468         rightvol = ch->rightvol;
469         if (sc->stereo)
470         {
471                 // LordHavoc: stereo sound support, and optimizations
472                 sfx = (signed short *)sc->data + ch->pos * 2;
473
474                 for (i=0 ; i<count ; i++)
475                 {
476                         paintbuffer[i].left += (*sfx++ * leftvol) >> 8;
477                         paintbuffer[i].right += (*sfx++ * rightvol) >> 8;
478                 }
479         }
480         else
481         {
482                 sfx = (signed short *)sc->data + ch->pos;
483
484                 for (i=0 ; i<count ; i++)
485                 {
486                         paintbuffer[i].left += (*sfx * leftvol) >> 8;
487                         paintbuffer[i].right += (*sfx++ * rightvol) >> 8;
488                 }
489         }
490
491         ch->pos += count;
492 }
493