A minor removal of a few pieces of dead code. Nothing major. This is
[xonotic/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 #endif
316 }
317
318
319 /*
320 ===============================================================================
321
322 CHANNEL MIXING
323
324 ===============================================================================
325 */
326
327 void SND_PaintChannelFrom8 (channel_t *ch, sfxcache_t *sc, int endtime);
328 void SND_PaintChannelFrom16 (channel_t *ch, sfxcache_t *sc, int endtime);
329
330 void S_PaintChannels(int endtime)
331 {
332         int     i;
333         int     end;
334         channel_t *ch;
335         sfxcache_t      *sc;
336         int             ltime, count;
337
338         while (paintedtime < endtime)
339         {
340                 // if paintbuffer is smaller than DMA buffer
341                 end = endtime;
342                 if (endtime - paintedtime > PAINTBUFFER_SIZE)
343                         end = paintedtime + PAINTBUFFER_SIZE;
344
345                 // clear the paint buffer
346                 memset(paintbuffer, 0, (end - paintedtime) * sizeof(portable_samplepair_t));
347
348                 // paint in the channels.
349                 ch = channels;
350                 for (i=0; i<total_channels ; i++, ch++)
351                 {
352                         if (!ch->sfx)
353                                 continue;
354                         if (!ch->leftvol && !ch->rightvol)
355                                 continue;
356                         sc = S_LoadSound (ch->sfx);
357                         if (!sc)
358                                 continue;
359
360                         ltime = paintedtime;
361
362                         while (ltime < end)
363                         {
364                                 // paint up to end
365                                 if (ch->end < end)
366                                         count = ch->end - ltime;
367                                 else
368                                         count = end - ltime;
369
370                                 if (count > 0)
371                                 {
372                                         if (sc->width == 1)
373                                                 SND_PaintChannelFrom8(ch, sc, count);
374                                         else
375                                                 SND_PaintChannelFrom16(ch, sc, count);
376
377                                         ltime += count;
378                                 }
379
380                                 // if at end of loop, restart
381                                 if (ltime >= ch->end)
382                                 {
383                                         if (sc->loopstart >= 0)
384                                         {
385                                                 ch->pos = sc->loopstart;
386                                                 ch->end = ltime + sc->length - ch->pos;
387                                         }
388                                         else
389                                         {
390                                                 // channel just stopped
391                                                 ch->sfx = NULL;
392                                                 break;
393                                         }
394                                 }
395                         }
396
397                 }
398
399                 // transfer out according to DMA format
400                 //S_CaptureAVISound(paintbuffer, end - paintedtime);
401                 S_TransferPaintBuffer(end);
402                 paintedtime = end;
403         }
404 }
405
406 void SND_InitScaletable (void)
407 {
408         int             i, j;
409
410         for (i=0 ; i<32 ; i++)
411                 for (j=0 ; j<256 ; j++)
412                         snd_scaletable[i][j] = ((signed char)j) * i * 8;
413 }
414
415
416 void SND_PaintChannelFrom8 (channel_t *ch, sfxcache_t *sc, int count)
417 {
418         int             *lscale, *rscale;
419         unsigned char *sfx;
420         int             i;
421
422         if (ch->leftvol > 255)
423                 ch->leftvol = 255;
424         if (ch->rightvol > 255)
425                 ch->rightvol = 255;
426
427         lscale = snd_scaletable[ch->leftvol >> 3];
428         rscale = snd_scaletable[ch->rightvol >> 3];
429         if (sc->stereo)
430         {
431                 // LordHavoc: stereo sound support, and optimizations
432                 sfx = (unsigned char *)sc->data + ch->pos * 2;
433
434                 for (i=0 ; i<count ; i++)
435                 {
436                         paintbuffer[i].left += lscale[*sfx++];
437                         paintbuffer[i].right += rscale[*sfx++];
438                 }
439                 
440         }
441         else
442         {
443                 sfx = (unsigned char *)sc->data + ch->pos;
444
445                 for (i=0 ; i<count ; i++)
446                 {
447                         paintbuffer[i].left += lscale[*sfx];
448                         paintbuffer[i].right += rscale[*sfx++];
449                 }
450
451         }
452         ch->pos += count;
453 }
454
455 void SND_PaintChannelFrom16 (channel_t *ch, sfxcache_t *sc, int count)
456 {
457         int leftvol, rightvol;
458         signed short *sfx;
459         int     i;
460
461         leftvol = ch->leftvol;
462         rightvol = ch->rightvol;
463         if (sc->stereo)
464         {
465                 // LordHavoc: stereo sound support, and optimizations
466                 sfx = (signed short *)sc->data + ch->pos * 2;
467
468                 for (i=0 ; i<count ; i++)
469                 {
470                         paintbuffer[i].left += (*sfx++ * leftvol) >> 8;
471                         paintbuffer[i].right += (*sfx++ * rightvol) >> 8;
472                 }
473         }
474         else
475         {
476                 sfx = (signed short *)sc->data + ch->pos;
477
478                 for (i=0 ; i<count ; i++)
479                 {
480                         paintbuffer[i].left += (*sfx * leftvol) >> 8;
481                         paintbuffer[i].right += (*sfx++ * rightvol) >> 8;
482                 }
483         }
484
485         ch->pos += count;
486 }
487