vkQuake2 doxygen  1.0 dev
snd_mix.c
Go to the documentation of this file.
1 /*
2 Copyright (C) 1997-2001 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 "client.h"
23 #include "snd_loc.h"
24 
25 #define PAINTBUFFER_SIZE 2048
27 int snd_scaletable[32][256];
29 short *snd_out;
30 
31 void S_WriteLinearBlastStereo16 (void);
32 
33 #if !(defined __linux__ && defined __i386__)
34 #if !id386
35 
37 {
38  int i;
39  int val;
40 
41  for (i=0 ; i<snd_linear_count ; i+=2)
42  {
43  val = snd_p[i]>>8;
44  if (val > 0x7fff)
45  snd_out[i] = 0x7fff;
46  else if (val < (short)0x8000)
47  snd_out[i] = (short)0x8000;
48  else
49  snd_out[i] = val;
50 
51  val = snd_p[i+1]>>8;
52  if (val > 0x7fff)
53  snd_out[i+1] = 0x7fff;
54  else if (val < (short)0x8000)
55  snd_out[i+1] = (short)0x8000;
56  else
57  snd_out[i+1] = val;
58  }
59 }
60 #else
61 __declspec( naked ) void S_WriteLinearBlastStereo16 (void)
62 {
63  __asm {
64 
65  push edi
66  push ebx
67  mov ecx,ds:dword ptr[snd_linear_count]
68  mov ebx,ds:dword ptr[snd_p]
69  mov edi,ds:dword ptr[snd_out]
70 LWLBLoopTop:
71  mov eax,ds:dword ptr[-8+ebx+ecx*4]
72  sar eax,8
73  cmp eax,07FFFh
74  jg LClampHigh
75  cmp eax,0FFFF8000h
76  jnl LClampDone
77  mov eax,0FFFF8000h
78  jmp LClampDone
79 LClampHigh:
80  mov eax,07FFFh
81 LClampDone:
82  mov edx,ds:dword ptr[-4+ebx+ecx*4]
83  sar edx,8
84  cmp edx,07FFFh
85  jg LClampHigh2
86  cmp edx,0FFFF8000h
87  jnl LClampDone2
88  mov edx,0FFFF8000h
89  jmp LClampDone2
90 LClampHigh2:
91  mov edx,07FFFh
92 LClampDone2:
93  shl edx,16
94  and eax,0FFFFh
95  or edx,eax
96  mov ds:dword ptr[-4+edi+ecx*2],edx
97  sub ecx,2
98  jnz LWLBLoopTop
99  pop ebx
100  pop edi
101  ret
102  }
103 }
104 
105 #endif
106 #endif
107 
108 void S_TransferStereo16 (unsigned long *pbuf, int endtime)
109 {
110  int lpos;
111  int lpaintedtime;
112 
113  snd_p = (int *) paintbuffer;
114  lpaintedtime = paintedtime;
115 
116  while (lpaintedtime < endtime)
117  {
118  // handle recirculating buffer issues
119  lpos = lpaintedtime & ((dma.samples>>1)-1);
120 
121  snd_out = (short *) pbuf + (lpos<<1);
122 
123  snd_linear_count = (dma.samples>>1) - lpos;
124  if (lpaintedtime + snd_linear_count > endtime)
125  snd_linear_count = endtime - lpaintedtime;
126 
127  snd_linear_count <<= 1;
128 
129  // write a linear blast of samples
131 
133  lpaintedtime += (snd_linear_count>>1);
134  }
135 }
136 
137 /*
138 ===================
139 S_TransferPaintBuffer
140 
141 ===================
142 */
143 void S_TransferPaintBuffer(int endtime)
144 {
145  int out_idx;
146  int count;
147  int out_mask;
148  int *p;
149  int step;
150  int val;
151  unsigned long *pbuf;
152 
153  pbuf = (unsigned long *)dma.buffer;
154 
155  if (s_testsound->value)
156  {
157  int i;
158  int count;
159 
160  // write a fixed sine wave
161  count = (endtime - paintedtime);
162  for (i=0 ; i<count ; i++)
163  paintbuffer[i].left = paintbuffer[i].right = sin((paintedtime+i)*0.1)*20000*256;
164  }
165 
166 
167  if (dma.samplebits == 16 && dma.channels == 2)
168  { // optimized case
169  S_TransferStereo16 (pbuf, endtime);
170  }
171  else
172  { // general case
173  p = (int *) paintbuffer;
174  count = (endtime - paintedtime) * dma.channels;
175  out_mask = dma.samples - 1;
176  out_idx = paintedtime * dma.channels & out_mask;
177  step = 3 - dma.channels;
178 
179  if (dma.samplebits == 16)
180  {
181  short *out = (short *) pbuf;
182  while (count--)
183  {
184  val = *p >> 8;
185  p+= step;
186  if (val > 0x7fff)
187  val = 0x7fff;
188  else if (val < (short)0x8000)
189  val = (short)0x8000;
190  out[out_idx] = val;
191  out_idx = (out_idx + 1) & out_mask;
192  }
193  }
194  else if (dma.samplebits == 8)
195  {
196  unsigned char *out = (unsigned char *) pbuf;
197  while (count--)
198  {
199  val = *p >> 8;
200  p+= step;
201  if (val > 0x7fff)
202  val = 0x7fff;
203  else if (val < (short)0x8000)
204  val = (short)0x8000;
205  out[out_idx] = (val>>8) + 128;
206  out_idx = (out_idx + 1) & out_mask;
207  }
208  }
209  }
210 }
211 
212 
213 /*
214 ===============================================================================
215 
216 CHANNEL MIXING
217 
218 ===============================================================================
219 */
220 
221 void S_PaintChannelFrom8 (channel_t *ch, sfxcache_t *sc, int endtime, int offset);
222 void S_PaintChannelFrom16 (channel_t *ch, sfxcache_t *sc, int endtime, int offset);
223 
224 void S_PaintChannels(int endtime)
225 {
226  int i;
227  int end;
228  channel_t *ch;
229  sfxcache_t *sc;
230  int ltime, count;
231  playsound_t *ps;
232 
233  snd_vol = s_volume->value*256;
234 
235 //Com_Printf ("%i to %i\n", paintedtime, endtime);
236  while (paintedtime < endtime)
237  {
238  // if paintbuffer is smaller than DMA buffer
239  end = endtime;
240  if (endtime - paintedtime > PAINTBUFFER_SIZE)
242 
243  // start any playsounds
244  while (1)
245  {
246  ps = s_pendingplays.next;
247  if (ps == &s_pendingplays)
248  break; // no more pending sounds
249  if (ps->begin <= paintedtime)
250  {
251  S_IssuePlaysound (ps);
252  continue;
253  }
254 
255  if (ps->begin < end)
256  end = ps->begin; // stop here
257  break;
258  }
259 
260  // clear the paint buffer
261  if (s_rawend < paintedtime)
262  {
263 // Com_Printf ("clear\n");
264  memset(paintbuffer, 0, (end - paintedtime) * sizeof(portable_samplepair_t));
265  }
266  else
267  { // copy from the streaming sound source
268  int s;
269  int stop;
270 
271  stop = (end < s_rawend) ? end : s_rawend;
272 
273  for (i=paintedtime ; i<stop ; i++)
274  {
275  s = i&(MAX_RAW_SAMPLES-1);
277  }
278 // if (i != end)
279 // Com_Printf ("partial stream\n");
280 // else
281 // Com_Printf ("full stream\n");
282  for ( ; i<end ; i++)
283  {
286  }
287  }
288 
289 
290  // paint in the channels.
291  ch = channels;
292  for (i=0; i<MAX_CHANNELS ; i++, ch++)
293  {
294  ltime = paintedtime;
295 
296  while (ltime < end)
297  {
298  if (!ch->sfx || (!ch->leftvol && !ch->rightvol) )
299  break;
300 
301  // max painting is to the end of the buffer
302  count = end - ltime;
303 
304  // might be stopped by running out of data
305  if (ch->end - ltime < count)
306  count = ch->end - ltime;
307 
308  sc = S_LoadSound (ch->sfx);
309  if (!sc)
310  break;
311 
312  if (count > 0 && ch->sfx)
313  {
314  if (sc->width == 1)// FIXME; 8 bit asm is wrong now
315  S_PaintChannelFrom8(ch, sc, count, ltime - paintedtime);
316  else
317  S_PaintChannelFrom16(ch, sc, count, ltime - paintedtime);
318 
319  ltime += count;
320  }
321 
322  // if at end of loop, restart
323  if (ltime >= ch->end)
324  {
325  if (ch->autosound)
326  { // autolooping sounds always go back to start
327  ch->pos = 0;
328  ch->end = ltime + sc->length;
329  }
330  else if (sc->loopstart >= 0)
331  {
332  ch->pos = sc->loopstart;
333  ch->end = ltime + sc->length - ch->pos;
334  }
335  else
336  { // channel just stopped
337  ch->sfx = NULL;
338  }
339  }
340  }
341 
342  }
343 
344  // transfer out according to DMA format
346  paintedtime = end;
347  }
348 }
349 
350 void S_InitScaletable (void)
351 {
352  int i, j;
353  int scale;
354 
355  s_volume->modified = false;
356  for (i=0 ; i<32 ; i++)
357  {
358  scale = i * 8 * 256 * s_volume->value;
359  for (j=0 ; j<256 ; j++)
360  snd_scaletable[i][j] = ((signed char)j) * scale;
361  }
362 }
363 
364 
365 #if !(defined __linux__ && defined __i386__)
366 #if !id386
367 
368 void S_PaintChannelFrom8 (channel_t *ch, sfxcache_t *sc, int count, int offset)
369 {
370  int data;
371  int *lscale, *rscale;
372  unsigned char *sfx;
373  int i;
374  portable_samplepair_t *samp;
375 
376  if (ch->leftvol > 255)
377  ch->leftvol = 255;
378  if (ch->rightvol > 255)
379  ch->rightvol = 255;
380 
381  //ZOID-- >>11 has been changed to >>3, >>11 didn't make much sense
382  //as it would always be zero.
383  lscale = snd_scaletable[ ch->leftvol >> 3];
384  rscale = snd_scaletable[ ch->rightvol >> 3];
385  sfx = (signed char *)sc->data + ch->pos;
386 
387  samp = &paintbuffer[offset];
388 
389  for (i=0 ; i<count ; i++, samp++)
390  {
391  data = sfx[i];
392  samp->left += lscale[data];
393  samp->right += rscale[data];
394  }
395 
396  ch->pos += count;
397 }
398 
399 #else
400 
401 __declspec( naked ) void S_PaintChannelFrom8 (channel_t *ch, sfxcache_t *sc, int count, int offset)
402 {
403  __asm {
404  push esi
405  push edi
406  push ebx
407  push ebp
408  mov ebx,ds:dword ptr[4+16+esp]
409  mov esi,ds:dword ptr[8+16+esp]
410  mov eax,ds:dword ptr[4+ebx]
411  mov edx,ds:dword ptr[8+ebx]
412  cmp eax,255
413  jna LLeftSet
414  mov eax,255
415 LLeftSet:
416  cmp edx,255
417  jna LRightSet
418  mov edx,255
419 LRightSet:
420  and eax,0F8h
421  add esi,20
422  and edx,0F8h
423  mov edi,ds:dword ptr[16+ebx]
424  mov ecx,ds:dword ptr[12+16+esp]
425  add esi,edi
426  shl eax,7
427  add edi,ecx
428  shl edx,7
429  mov ds:dword ptr[16+ebx],edi
430  add eax,offset snd_scaletable
431  add edx,offset snd_scaletable
432  sub ebx,ebx
433  mov bl,ds:byte ptr[-1+esi+ecx*1]
434  test ecx,1
435  jz LMix8Loop
436  mov edi,ds:dword ptr[eax+ebx*4]
437  mov ebp,ds:dword ptr[edx+ebx*4]
438  add edi,ds:dword ptr[paintbuffer+0-8+ecx*8]
439  add ebp,ds:dword ptr[paintbuffer+4-8+ecx*8]
440  mov ds:dword ptr[paintbuffer+0-8+ecx*8],edi
441  mov ds:dword ptr[paintbuffer+4-8+ecx*8],ebp
442  mov bl,ds:byte ptr[-2+esi+ecx*1]
443  dec ecx
444  jz LDone
445 LMix8Loop:
446  mov edi,ds:dword ptr[eax+ebx*4]
447  mov ebp,ds:dword ptr[edx+ebx*4]
448  add edi,ds:dword ptr[paintbuffer+0-8+ecx*8]
449  add ebp,ds:dword ptr[paintbuffer+4-8+ecx*8]
450  mov bl,ds:byte ptr[-2+esi+ecx*1]
451  mov ds:dword ptr[paintbuffer+0-8+ecx*8],edi
452  mov ds:dword ptr[paintbuffer+4-8+ecx*8],ebp
453  mov edi,ds:dword ptr[eax+ebx*4]
454  mov ebp,ds:dword ptr[edx+ebx*4]
455  mov bl,ds:byte ptr[-3+esi+ecx*1]
456  add edi,ds:dword ptr[paintbuffer+0-8*2+ecx*8]
457  add ebp,ds:dword ptr[paintbuffer+4-8*2+ecx*8]
458  mov ds:dword ptr[paintbuffer+0-8*2+ecx*8],edi
459  mov ds:dword ptr[paintbuffer+4-8*2+ecx*8],ebp
460  sub ecx,2
461  jnz LMix8Loop
462 LDone:
463  pop ebp
464  pop ebx
465  pop edi
466  pop esi
467  ret
468  }
469 }
470 
471 #endif
472 #endif
473 
474 void S_PaintChannelFrom16 (channel_t *ch, sfxcache_t *sc, int count, int offset)
475 {
476  int data;
477  int left, right;
478  int leftvol, rightvol;
479  signed short *sfx;
480  int i;
481  portable_samplepair_t *samp;
482 
483  leftvol = ch->leftvol*snd_vol;
484  rightvol = ch->rightvol*snd_vol;
485  sfx = (signed short *)sc->data + ch->pos;
486 
487  samp = &paintbuffer[offset];
488  for (i=0 ; i<count ; i++, samp++)
489  {
490  data = sfx[i];
491  left = (data * leftvol)>>8;
492  right = (data * rightvol)>>8;
493  samp->left += left;
494  samp->right += right;
495  }
496 
497  ch->pos += count;
498 }
499 
MAX_CHANNELS
#define MAX_CHANNELS
Definition: snd_loc.h:126
s_testsound
cvar_t * s_testsound
Definition: snd_dma.c:75
channel_t::pos
int pos
Definition: snd_loc.h:81
S_PaintChannelFrom8
void S_PaintChannelFrom8(channel_t *ch, sfxcache_t *sc, int endtime, int offset)
Definition: snd_mix.c:368
sfxcache_t::length
int length
Definition: snd_loc.h:31
channel_t::sfx
sfx_t * sfx
Definition: snd_loc.h:77
PAINTBUFFER_SIZE
#define PAINTBUFFER_SIZE
Definition: snd_mix.c:25
playsound_s
Definition: snd_loc.h:50
channel_t::autosound
qboolean autosound
Definition: snd_loc.h:89
s_rawend
int s_rawend
Definition: snd_dma.c:83
cvar_s::modified
qboolean modified
Definition: q_shared.h:330
channel_t::rightvol
int rightvol
Definition: snd_loc.h:79
i
int i
Definition: q_shared.c:305
ebp
LEnter16_16 al cl movb ah addl ebp
Definition: block16.h:5
channel_t::leftvol
int leftvol
Definition: snd_loc.h:78
dma_t::samples
int samples
Definition: snd_loc.h:66
portable_samplepair_t::left
int left
Definition: snd_loc.h:25
s_volume
cvar_t * s_volume
Definition: snd_dma.c:74
snd_p
int * snd_p
Definition: snd_mix.c:28
j
GLint j
Definition: qgl_win.c:150
playsound_s::begin
unsigned begin
Definition: snd_loc.h:60
playsound_s::sfx
sfx_t * sfx
Definition: snd_loc.h:53
MAX_RAW_SAMPLES
#define MAX_RAW_SAMPLES
Definition: snd_loc.h:138
S_LoadSound
sfxcache_t * S_LoadSound(sfx_t *s)
Definition: snd_mem.c:99
dma_t::buffer
byte * buffer
Definition: snd_loc.h:71
dma_t::channels
int channels
Definition: snd_loc.h:65
playsound_s::next
struct playsound_s * next
Definition: snd_loc.h:52
paintedtime
int paintedtime
Definition: snd_dma.c:57
snd_scaletable
int snd_scaletable[32][256]
Definition: snd_mix.c:27
S_TransferPaintBuffer
void S_TransferPaintBuffer(int endtime)
Definition: snd_mix.c:143
S_TransferStereo16
void S_TransferStereo16(unsigned long *pbuf, int endtime)
Definition: snd_mix.c:108
cvar_s::value
float value
Definition: q_shared.h:331
NULL
#define NULL
Definition: q_shared.h:67
dma
dma_t dma
Definition: snd_dma.c:47
channel_t
Definition: snd_loc.h:75
S_IssuePlaysound
void S_IssuePlaysound(playsound_t *ps)
Definition: snd_dma.c:550
channels
channel_t channels[MAX_CHANNELS]
Definition: snd_dma.c:42
s_rawsamples
portable_samplepair_t s_rawsamples[MAX_RAW_SAMPLES]
Definition: snd_dma.c:84
s
static fixed16_t s
Definition: r_scan.c:30
snd_linear_count
int snd_linear_count
Definition: snd_mix.c:28
snd_vol
int snd_vol
Definition: snd_mix.c:28
S_InitScaletable
void S_InitScaletable(void)
Definition: snd_mix.c:350
paintbuffer
portable_samplepair_t paintbuffer[PAINTBUFFER_SIZE]
Definition: snd_mix.c:26
snd_loc.h
portable_samplepair_t::right
int right
Definition: snd_loc.h:26
portable_samplepair_t
Definition: snd_loc.h:23
s_pendingplays
playsound_t s_pendingplays
Definition: snd_dma.c:70
S_WriteLinearBlastStereo16
void S_WriteLinearBlastStereo16(void)
Definition: snd_mix.c:36
sfxcache_t
Definition: snd_loc.h:29
sfxcache_t::data
byte data[1]
Definition: snd_loc.h:36
sfxcache_t::width
int width
Definition: snd_loc.h:34
right
GLdouble right
Definition: qgl_win.c:159
dma_t::samplebits
int samplebits
Definition: snd_loc.h:69
S_PaintChannels
void S_PaintChannels(int endtime)
Definition: snd_mix.c:224
snd_out
short * snd_out
Definition: snd_mix.c:29
client.h
channel_t::end
int end
Definition: snd_loc.h:80
sfxcache_t::loopstart
int loopstart
Definition: snd_loc.h:32
count
GLint GLsizei count
Definition: qgl_win.c:128
S_PaintChannelFrom16
void S_PaintChannelFrom16(channel_t *ch, sfxcache_t *sc, int endtime, int offset)
Definition: snd_mix.c:474