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