]> icculus.org git repositories - divverent/darkplaces.git/blob - snd_mix.c
fixed spelling error (allready -> already)
[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 #define PAINTBUFFER_SIZE        512
31 portable_samplepair_t paintbuffer[PAINTBUFFER_SIZE];
32 int             snd_scaletable[32][256];
33 int     *snd_p, snd_linear_count, snd_vol;
34 short   *snd_out;
35
36 void Snd_WriteLinearBlastStereo16 (void);
37
38 extern cvar_t snd_swapstereo;
39 void Snd_WriteLinearBlastStereo16 (void)
40 {
41         int             i;
42         int             val;
43
44         if (snd_swapstereo.value)
45         {
46                 for (i=0 ; i<snd_linear_count ; i+=2)
47                 {
48                         val = (snd_p[i+1]*snd_vol)>>8;
49                         if (val > 0x7fff)
50                                 snd_out[i] = 0x7fff;
51                         else if (val < (short)0x8000)
52                                 snd_out[i] = (short)0x8000;
53                         else
54                                 snd_out[i] = val;
55
56                         val = (snd_p[i]*snd_vol)>>8;
57                         if (val > 0x7fff)
58                                 snd_out[i+1] = 0x7fff;
59                         else if (val < (short)0x8000)
60                                 snd_out[i+1] = (short)0x8000;
61                         else
62                                 snd_out[i+1] = val;
63                 }
64         }
65         else
66         {
67                 for (i=0 ; i<snd_linear_count ; i+=2)
68                 {
69                         val = (snd_p[i]*snd_vol)>>8;
70                         if (val > 0x7fff)
71                                 snd_out[i] = 0x7fff;
72                         else if (val < (short)0x8000)
73                                 snd_out[i] = (short)0x8000;
74                         else
75                                 snd_out[i] = val;
76
77                         val = (snd_p[i+1]*snd_vol)>>8;
78                         if (val > 0x7fff)
79                                 snd_out[i+1] = 0x7fff;
80                         else if (val < (short)0x8000)
81                                 snd_out[i+1] = (short)0x8000;
82                         else
83                                 snd_out[i+1] = val;
84                 }
85         }
86 }
87
88 void S_TransferStereo16 (int endtime)
89 {
90         int             lpos;
91         int             lpaintedtime;
92         DWORD   *pbuf;
93 #ifdef _WIN32
94         int             reps;
95         DWORD   dwSize,dwSize2;
96         DWORD   *pbuf2;
97         HRESULT hresult;
98 #endif
99         
100         snd_vol = volume.value*256;
101
102         snd_p = (int *) paintbuffer;
103         lpaintedtime = paintedtime;
104
105 #ifdef _WIN32
106         if (pDSBuf)
107         {
108                 reps = 0;
109
110                 while ((hresult = pDSBuf->lpVtbl->Lock(pDSBuf, 0, gSndBufSize, &pbuf, &dwSize, 
111                                                                            &pbuf2, &dwSize2, 0)) != DS_OK)
112                 {
113                         if (hresult != DSERR_BUFFERLOST)
114                         {
115                                 Con_Printf ("S_TransferStereo16: DS::Lock Sound Buffer Failed\n");
116                                 S_Shutdown ();
117                                 S_Startup ();
118                                 return;
119                         }
120
121                         if (++reps > 10000)
122                         {
123                                 Con_Printf ("S_TransferStereo16: DS: couldn't restore buffer\n");
124                                 S_Shutdown ();
125                                 S_Startup ();
126                                 return;
127                         }
128                 }
129         }
130         else
131 #endif
132         {
133                 pbuf = (DWORD *)shm->buffer;
134         }
135
136         while (lpaintedtime < endtime)
137         {
138         // handle recirculating buffer issues
139                 lpos = lpaintedtime & ((shm->samples>>1)-1);
140
141                 snd_out = (short *) pbuf + (lpos<<1);
142
143                 snd_linear_count = (shm->samples>>1) - lpos;
144                 if (lpaintedtime + snd_linear_count > endtime)
145                         snd_linear_count = endtime - lpaintedtime;
146
147                 snd_linear_count <<= 1;
148
149         // write a linear blast of samples
150                 Snd_WriteLinearBlastStereo16 ();
151
152                 snd_p += snd_linear_count;
153                 lpaintedtime += (snd_linear_count>>1);
154         }
155
156 #ifdef _WIN32
157         if (pDSBuf)
158                 pDSBuf->lpVtbl->Unlock(pDSBuf, pbuf, dwSize, NULL, 0);
159 #endif
160 }
161
162 void S_TransferPaintBuffer(int endtime)
163 {
164         int     out_idx;
165         int     count;
166         int     out_mask;
167         int     *p;
168         int     step;
169         int             val;
170         int             snd_vol;
171         DWORD   *pbuf;
172 #ifdef _WIN32
173         int             reps;
174         DWORD   dwSize,dwSize2;
175         DWORD   *pbuf2;
176         HRESULT hresult;
177 #endif
178
179         if (shm->samplebits == 16 && shm->channels == 2)
180         {
181                 S_TransferStereo16 (endtime);
182                 return;
183         }
184         
185         p = (int *) paintbuffer;
186         count = (endtime - paintedtime) * shm->channels;
187         out_mask = shm->samples - 1; 
188         out_idx = paintedtime * shm->channels & out_mask;
189         step = 3 - shm->channels;
190         snd_vol = volume.value*256;
191
192 #ifdef _WIN32
193         if (pDSBuf)
194         {
195                 reps = 0;
196
197                 while ((hresult = pDSBuf->lpVtbl->Lock(pDSBuf, 0, gSndBufSize, &pbuf, &dwSize, 
198                                                                            &pbuf2,&dwSize2, 0)) != DS_OK)
199                 {
200                         if (hresult != DSERR_BUFFERLOST)
201                         {
202                                 Con_Printf ("S_TransferPaintBuffer: DS::Lock Sound Buffer Failed\n");
203                                 S_Shutdown ();
204                                 S_Startup ();
205                                 return;
206                         }
207
208                         if (++reps > 10000)
209                         {
210                                 Con_Printf ("S_TransferPaintBuffer: DS: couldn't restore buffer\n");
211                                 S_Shutdown ();
212                                 S_Startup ();
213                                 return;
214                         }
215                 }
216         }
217         else
218 #endif
219         {
220                 pbuf = (DWORD *)shm->buffer;
221         }
222
223         if (shm->samplebits == 16)
224         {
225                 short *out = (short *) pbuf;
226                 while (count--)
227                 {
228                         val = (*p * snd_vol) >> 8;
229                         p+= step;
230                         if (val > 0x7fff)
231                                 val = 0x7fff;
232                         else if (val < (short)0x8000)
233                                 val = (short)0x8000;
234                         out[out_idx] = val;
235                         out_idx = (out_idx + 1) & out_mask;
236                 }
237         }
238         else if (shm->samplebits == 8)
239         {
240                 unsigned char *out = (unsigned char *) pbuf;
241                 while (count--)
242                 {
243                         val = (*p * snd_vol) >> 8;
244                         p+= step;
245                         if (val > 0x7fff)
246                                 val = 0x7fff;
247                         else if (val < (short)0x8000)
248                                 val = (short)0x8000;
249                         out[out_idx] = (val>>8) + 128;
250                         out_idx = (out_idx + 1) & out_mask;
251                 }
252         }
253
254 #ifdef _WIN32
255         if (pDSBuf) {
256                 DWORD dwNewpos, dwWrite;
257                 int il = paintedtime;
258                 int ir = endtime - paintedtime;
259                 
260                 ir += il;
261
262                 pDSBuf->lpVtbl->Unlock(pDSBuf, pbuf, dwSize, NULL, 0);
263
264                 pDSBuf->lpVtbl->GetCurrentPosition(pDSBuf, &dwNewpos, &dwWrite);
265
266 //              if ((dwNewpos >= il) && (dwNewpos <= ir))
267 //                      Con_Printf("%d-%d p %d c\n", il, ir, dwNewpos);
268         }
269 #endif
270 }
271
272
273 /*
274 ===============================================================================
275
276 CHANNEL MIXING
277
278 ===============================================================================
279 */
280
281 void SND_PaintChannelFrom8 (channel_t *ch, sfxcache_t *sc, int endtime);
282 void SND_PaintChannelFrom16 (channel_t *ch, sfxcache_t *sc, int endtime);
283
284 void S_PaintChannels(int endtime)
285 {
286         int     i;
287         int     end;
288         channel_t *ch;
289         sfxcache_t      *sc;
290         int             ltime, count;
291
292         while (paintedtime < endtime)
293         {
294         // if paintbuffer is smaller than DMA buffer
295                 end = endtime;
296                 if (endtime - paintedtime > PAINTBUFFER_SIZE)
297                         end = paintedtime + PAINTBUFFER_SIZE;
298
299         // clear the paint buffer
300                 memset(paintbuffer, 0, (end - paintedtime) * sizeof(portable_samplepair_t));
301
302         // paint in the channels.
303                 ch = channels;
304                 for (i=0; i<total_channels ; i++, ch++)
305                 {
306                         if (!ch->sfx)
307                                 continue;
308                         if (!ch->leftvol && !ch->rightvol)
309                                 continue;
310                         sc = S_LoadSound (ch->sfx);
311                         if (!sc)
312                                 continue;
313
314                         ltime = paintedtime;
315
316                         while (ltime < end)
317                         {       // paint up to end
318                                 if (ch->end < end)
319                                         count = ch->end - ltime;
320                                 else
321                                         count = end - ltime;
322
323                                 if (count > 0)
324                                 {       
325                                         if (sc->width == 1)
326                                                 SND_PaintChannelFrom8(ch, sc, count);
327                                         else
328                                                 SND_PaintChannelFrom16(ch, sc, count);
329         
330                                         ltime += count;
331                                 }
332
333                         // if at end of loop, restart
334                                 if (ltime >= ch->end)
335                                 {
336                                         if (sc->loopstart >= 0)
337                                         {
338                                                 ch->pos = sc->loopstart;
339                                                 ch->end = ltime + sc->length - ch->pos;
340                                         }
341                                         else                            
342                                         {       // channel just stopped
343                                                 ch->sfx = NULL;
344                                                 break;
345                                         }
346                                 }
347                         }
348                                                                                                                           
349                 }
350
351         // transfer out according to DMA format
352                 S_TransferPaintBuffer(end);
353                 paintedtime = end;
354         }
355 }
356
357 void SND_InitScaletable (void)
358 {
359         int             i, j;
360         
361         for (i=0 ; i<32 ; i++)
362                 for (j=0 ; j<256 ; j++)
363                         snd_scaletable[i][j] = ((signed char)j) * i * 8;
364 }
365
366
367 void SND_PaintChannelFrom8 (channel_t *ch, sfxcache_t *sc, int count)
368 {
369 //      int     data;
370         int             *lscale, *rscale;
371         unsigned char *sfx;
372         int             i;
373
374         if (ch->leftvol > 255)
375                 ch->leftvol = 255;
376         if (ch->rightvol > 255)
377                 ch->rightvol = 255;
378                 
379         lscale = snd_scaletable[ch->leftvol >> 3];
380         rscale = snd_scaletable[ch->rightvol >> 3];
381         if (sc->stereo) // LordHavoc: stereo sound support, and optimizations
382         {
383                 sfx = (unsigned char *)sc->data + ch->pos * 2;
384
385                 for (i=0 ; i<count ; i++)
386                 {
387                         paintbuffer[i].left += lscale[*sfx++];
388                         paintbuffer[i].right += rscale[*sfx++];
389                 }
390                 
391         }
392         else
393         {
394                 sfx = (unsigned char *)sc->data + ch->pos;
395
396                 for (i=0 ; i<count ; i++)
397                 {
398                         paintbuffer[i].left += lscale[*sfx];
399                         paintbuffer[i].right += rscale[*sfx++];
400                 }
401                 
402         }
403         ch->pos += count;
404 }
405
406 void SND_PaintChannelFrom16 (channel_t *ch, sfxcache_t *sc, int count)
407 {
408 //      int data;
409 //      int left, right;
410         int leftvol, rightvol;
411         signed short *sfx;
412         int     i;
413
414         leftvol = ch->leftvol;
415         rightvol = ch->rightvol;
416         if (sc->stereo) // LordHavoc: stereo sound support, and optimizations
417         {
418                 sfx = (signed short *)sc->data + ch->pos * 2;
419
420                 for (i=0 ; i<count ; i++)
421                 {
422                         paintbuffer[i].left += (short) ((int) (*sfx++ * leftvol) >> 8);
423                         paintbuffer[i].right += (short) ((int) (*sfx++ * rightvol) >> 8);
424                 }
425         }
426         else
427         {
428                 sfx = (signed short *)sc->data + ch->pos;
429
430                 for (i=0 ; i<count ; i++)
431                 {
432                         paintbuffer[i].left += (short) ((int) (*sfx * leftvol) >> 8);
433                         paintbuffer[i].right += (short) ((int) (*sfx++ * rightvol) >> 8);
434                 }
435         }
436
437         ch->pos += count;
438 }
439