1 /*
2 ===========================================================================
3 Copyright (C) 1999-2005 Id Software, Inc.
4
5 This file is part of Quake III Arena source code.
6
7 Quake III Arena source code is free software; you can redistribute it
8 and/or modify it under the terms of the GNU General Public License as
9 published by the Free Software Foundation; either version 2 of the License,
10 or (at your option) any later version.
11
12 Quake III Arena source code is distributed in the hope that it will be
13 useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 GNU General Public License for more details.
16
17 You should have received a copy of the GNU General Public License
18 along with Quake III Arena source code; if not, write to the Free Software
19 Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
20 ===========================================================================
21 */
22 // snd_mix.c -- portable code to mix sounds for snd_dma.c
23
24 #include "client.h"
25 #include "snd_local.h"
26 #if idppc_altivec && !defined(MACOS_X)
27 #include <altivec.h>
28 #endif
29
30 static portable_samplepair_t paintbuffer[PAINTBUFFER_SIZE];
31 static int snd_vol;
32
33 int* snd_p;
34 int snd_linear_count;
35 short* snd_out;
36
37 #if !id386 // if configured not to use asm
38
S_WriteLinearBlastStereo16(void)39 void S_WriteLinearBlastStereo16 (void)
40 {
41 int i;
42 int val;
43
44 for (i=0 ; i<snd_linear_count ; i+=2)
45 {
46 val = snd_p[i]>>8;
47 if (val > 0x7fff)
48 snd_out[i] = 0x7fff;
49 else if (val < -32768)
50 snd_out[i] = -32768;
51 else
52 snd_out[i] = val;
53
54 val = snd_p[i+1]>>8;
55 if (val > 0x7fff)
56 snd_out[i+1] = 0x7fff;
57 else if (val < -32768)
58 snd_out[i+1] = -32768;
59 else
60 snd_out[i+1] = val;
61 }
62 }
63 #elif defined(__GNUC__)
64 // uses snd_mixa.s
65 void S_WriteLinearBlastStereo16 (void);
66 #else
67
S_WriteLinearBlastStereo16(void)68 __declspec( naked ) void S_WriteLinearBlastStereo16 (void)
69 {
70 __asm {
71
72 push edi
73 push ebx
74 mov ecx,ds:dword ptr[snd_linear_count]
75 mov ebx,ds:dword ptr[snd_p]
76 mov edi,ds:dword ptr[snd_out]
77 LWLBLoopTop:
78 mov eax,ds:dword ptr[-8+ebx+ecx*4]
79 sar eax,8
80 cmp eax,07FFFh
81 jg LClampHigh
82 cmp eax,0FFFF8000h
83 jnl LClampDone
84 mov eax,0FFFF8000h
85 jmp LClampDone
86 LClampHigh:
87 mov eax,07FFFh
88 LClampDone:
89 mov edx,ds:dword ptr[-4+ebx+ecx*4]
90 sar edx,8
91 cmp edx,07FFFh
92 jg LClampHigh2
93 cmp edx,0FFFF8000h
94 jnl LClampDone2
95 mov edx,0FFFF8000h
96 jmp LClampDone2
97 LClampHigh2:
98 mov edx,07FFFh
99 LClampDone2:
100 shl edx,16
101 and eax,0FFFFh
102 or edx,eax
103 mov ds:dword ptr[-4+edi+ecx*2],edx
104 sub ecx,2
105 jnz LWLBLoopTop
106 pop ebx
107 pop edi
108 ret
109 }
110 }
111
112 #endif
113
S_TransferStereo16(unsigned long * pbuf,int endtime)114 void S_TransferStereo16 (unsigned long *pbuf, int endtime)
115 {
116 int lpos;
117 int ls_paintedtime;
118
119 snd_p = (int *) paintbuffer;
120 ls_paintedtime = s_paintedtime;
121
122 while (ls_paintedtime < endtime)
123 {
124 // handle recirculating buffer issues
125 lpos = ls_paintedtime & ((dma.samples>>1)-1);
126
127 snd_out = (short *) pbuf + (lpos<<1);
128
129 snd_linear_count = (dma.samples>>1) - lpos;
130 if (ls_paintedtime + snd_linear_count > endtime)
131 snd_linear_count = endtime - ls_paintedtime;
132
133 snd_linear_count <<= 1;
134
135 // write a linear blast of samples
136 S_WriteLinearBlastStereo16 ();
137
138 snd_p += snd_linear_count;
139 ls_paintedtime += (snd_linear_count>>1);
140
141 if( CL_VideoRecording( ) )
142 CL_WriteAVIAudioFrame( (byte *)snd_out, snd_linear_count << 1 );
143 }
144 }
145
146 /*
147 ===================
148 S_TransferPaintBuffer
149
150 ===================
151 */
S_TransferPaintBuffer(int endtime)152 void S_TransferPaintBuffer(int endtime)
153 {
154 int out_idx;
155 int count;
156 int out_mask;
157 int *p;
158 int step;
159 int val;
160 unsigned long *pbuf;
161
162 pbuf = (unsigned long *)dma.buffer;
163
164
165 if ( s_testsound->integer ) {
166 int i;
167 int count;
168
169 // write a fixed sine wave
170 count = (endtime - s_paintedtime);
171 for (i=0 ; i<count ; i++)
172 paintbuffer[i].left = paintbuffer[i].right = sin((s_paintedtime+i)*0.1)*20000*256;
173 }
174
175
176 if (dma.samplebits == 16 && dma.channels == 2)
177 { // optimized case
178 S_TransferStereo16 (pbuf, endtime);
179 }
180 else
181 { // general case
182 p = (int *) paintbuffer;
183 count = (endtime - s_paintedtime) * dma.channels;
184 out_mask = dma.samples - 1;
185 out_idx = s_paintedtime * dma.channels & out_mask;
186 step = 3 - dma.channels;
187
188 if (dma.samplebits == 16)
189 {
190 short *out = (short *) pbuf;
191 while (count--)
192 {
193 val = *p >> 8;
194 p+= step;
195 if (val > 0x7fff)
196 val = 0x7fff;
197 else if (val < -32768)
198 val = -32768;
199 out[out_idx] = val;
200 out_idx = (out_idx + 1) & out_mask;
201 }
202 }
203 else if (dma.samplebits == 8)
204 {
205 unsigned char *out = (unsigned char *) pbuf;
206 while (count--)
207 {
208 val = *p >> 8;
209 p+= step;
210 if (val > 0x7fff)
211 val = 0x7fff;
212 else if (val < -32768)
213 val = -32768;
214 out[out_idx] = (val>>8) + 128;
215 out_idx = (out_idx + 1) & out_mask;
216 }
217 }
218 }
219 }
220
221
222 /*
223 ===============================================================================
224
225 CHANNEL MIXING
226
227 ===============================================================================
228 */
229
230 #if idppc_altivec
S_PaintChannelFrom16_altivec(channel_t * ch,const sfx_t * sc,int count,int sampleOffset,int bufferOffset)231 static void S_PaintChannelFrom16_altivec( channel_t *ch, const sfx_t *sc, int count, int sampleOffset, int bufferOffset ) {
232 int data, aoff, boff;
233 int leftvol, rightvol;
234 int i, j;
235 portable_samplepair_t *samp;
236 sndBuffer *chunk;
237 short *samples;
238 float ooff, fdata, fdiv, fleftvol, frightvol;
239
240 samp = &paintbuffer[ bufferOffset ];
241
242 if (ch->doppler) {
243 sampleOffset = sampleOffset*ch->oldDopplerScale;
244 }
245
246 chunk = sc->soundData;
247 while (sampleOffset>=SND_CHUNK_SIZE) {
248 chunk = chunk->next;
249 sampleOffset -= SND_CHUNK_SIZE;
250 if (!chunk) {
251 chunk = sc->soundData;
252 }
253 }
254
255 if (!ch->doppler || ch->dopplerScale==1.0f) {
256 vector signed short volume_vec;
257 vector unsigned int volume_shift;
258 int vectorCount, samplesLeft, chunkSamplesLeft;
259 leftvol = ch->leftvol*snd_vol;
260 rightvol = ch->rightvol*snd_vol;
261 samples = chunk->sndChunk;
262 ((short *)&volume_vec)[0] = leftvol;
263 ((short *)&volume_vec)[1] = leftvol;
264 ((short *)&volume_vec)[4] = leftvol;
265 ((short *)&volume_vec)[5] = leftvol;
266 ((short *)&volume_vec)[2] = rightvol;
267 ((short *)&volume_vec)[3] = rightvol;
268 ((short *)&volume_vec)[6] = rightvol;
269 ((short *)&volume_vec)[7] = rightvol;
270 volume_shift = vec_splat_u32(8);
271 i = 0;
272
273 while(i < count) {
274 /* Try to align destination to 16-byte boundary */
275 while(i < count && (((unsigned long)&samp[i] & 0x1f) || ((count-i) < 8) || ((SND_CHUNK_SIZE - sampleOffset) < 8))) {
276 data = samples[sampleOffset++];
277 samp[i].left += (data * leftvol)>>8;
278 samp[i].right += (data * rightvol)>>8;
279
280 if (sampleOffset == SND_CHUNK_SIZE) {
281 chunk = chunk->next;
282 samples = chunk->sndChunk;
283 sampleOffset = 0;
284 }
285 i++;
286 }
287 /* Destination is now aligned. Process as many 8-sample
288 chunks as we can before we run out of room from the current
289 sound chunk. We do 8 per loop to avoid extra source data reads. */
290 samplesLeft = count - i;
291 chunkSamplesLeft = SND_CHUNK_SIZE - sampleOffset;
292 if(samplesLeft > chunkSamplesLeft)
293 samplesLeft = chunkSamplesLeft;
294
295 vectorCount = samplesLeft / 8;
296
297 if(vectorCount)
298 {
299 vector unsigned char tmp;
300 vector short s0, s1, sampleData0, sampleData1;
301 vector signed int merge0, merge1;
302 vector signed int d0, d1, d2, d3;
303 vector unsigned char samplePermute0 =
304 VECCONST_UINT8(0, 1, 4, 5, 0, 1, 4, 5, 2, 3, 6, 7, 2, 3, 6, 7);
305 vector unsigned char samplePermute1 =
306 VECCONST_UINT8(8, 9, 12, 13, 8, 9, 12, 13, 10, 11, 14, 15, 10, 11, 14, 15);
307 vector unsigned char loadPermute0, loadPermute1;
308
309 // Rather than permute the vectors after we load them to do the sample
310 // replication and rearrangement, we permute the alignment vector so
311 // we do everything in one step below and avoid data shuffling.
312 tmp = vec_lvsl(0,&samples[sampleOffset]);
313 loadPermute0 = vec_perm(tmp,tmp,samplePermute0);
314 loadPermute1 = vec_perm(tmp,tmp,samplePermute1);
315
316 s0 = *(vector short *)&samples[sampleOffset];
317 while(vectorCount)
318 {
319 /* Load up source (16-bit) sample data */
320 s1 = *(vector short *)&samples[sampleOffset+7];
321
322 /* Load up destination sample data */
323 d0 = *(vector signed int *)&samp[i];
324 d1 = *(vector signed int *)&samp[i+2];
325 d2 = *(vector signed int *)&samp[i+4];
326 d3 = *(vector signed int *)&samp[i+6];
327
328 sampleData0 = vec_perm(s0,s1,loadPermute0);
329 sampleData1 = vec_perm(s0,s1,loadPermute1);
330
331 merge0 = vec_mule(sampleData0,volume_vec);
332 merge0 = vec_sra(merge0,volume_shift); /* Shift down to proper range */
333
334 merge1 = vec_mulo(sampleData0,volume_vec);
335 merge1 = vec_sra(merge1,volume_shift);
336
337 d0 = vec_add(merge0,d0);
338 d1 = vec_add(merge1,d1);
339
340 merge0 = vec_mule(sampleData1,volume_vec);
341 merge0 = vec_sra(merge0,volume_shift); /* Shift down to proper range */
342
343 merge1 = vec_mulo(sampleData1,volume_vec);
344 merge1 = vec_sra(merge1,volume_shift);
345
346 d2 = vec_add(merge0,d2);
347 d3 = vec_add(merge1,d3);
348
349 /* Store destination sample data */
350 *(vector signed int *)&samp[i] = d0;
351 *(vector signed int *)&samp[i+2] = d1;
352 *(vector signed int *)&samp[i+4] = d2;
353 *(vector signed int *)&samp[i+6] = d3;
354
355 i += 8;
356 vectorCount--;
357 s0 = s1;
358 sampleOffset += 8;
359 }
360 if (sampleOffset == SND_CHUNK_SIZE) {
361 chunk = chunk->next;
362 samples = chunk->sndChunk;
363 sampleOffset = 0;
364 }
365 }
366 }
367 } else {
368 fleftvol = ch->leftvol*snd_vol;
369 frightvol = ch->rightvol*snd_vol;
370
371 ooff = sampleOffset;
372 samples = chunk->sndChunk;
373
374 for ( i=0 ; i<count ; i++ ) {
375
376 aoff = ooff;
377 ooff = ooff + ch->dopplerScale;
378 boff = ooff;
379 fdata = 0;
380 for (j=aoff; j<boff; j++) {
381 if (j == SND_CHUNK_SIZE) {
382 chunk = chunk->next;
383 if (!chunk) {
384 chunk = sc->soundData;
385 }
386 samples = chunk->sndChunk;
387 ooff -= SND_CHUNK_SIZE;
388 }
389 fdata += samples[j&(SND_CHUNK_SIZE-1)];
390 }
391 fdiv = 256 * (boff-aoff);
392 samp[i].left += (fdata * fleftvol)/fdiv;
393 samp[i].right += (fdata * frightvol)/fdiv;
394 }
395 }
396 }
397 #endif
398
S_PaintChannelFrom16_scalar(channel_t * ch,const sfx_t * sc,int count,int sampleOffset,int bufferOffset)399 static void S_PaintChannelFrom16_scalar( channel_t *ch, const sfx_t *sc, int count, int sampleOffset, int bufferOffset ) {
400 int data, aoff, boff;
401 int leftvol, rightvol;
402 int i, j;
403 portable_samplepair_t *samp;
404 sndBuffer *chunk;
405 short *samples;
406 float ooff, fdata, fdiv, fleftvol, frightvol;
407
408 samp = &paintbuffer[ bufferOffset ];
409
410 if (ch->doppler) {
411 sampleOffset = sampleOffset*ch->oldDopplerScale;
412 }
413
414 chunk = sc->soundData;
415 while (sampleOffset>=SND_CHUNK_SIZE) {
416 chunk = chunk->next;
417 sampleOffset -= SND_CHUNK_SIZE;
418 if (!chunk) {
419 chunk = sc->soundData;
420 }
421 }
422
423 if (!ch->doppler || ch->dopplerScale==1.0f) {
424 leftvol = ch->leftvol*snd_vol;
425 rightvol = ch->rightvol*snd_vol;
426 samples = chunk->sndChunk;
427 for ( i=0 ; i<count ; i++ ) {
428 data = samples[sampleOffset++];
429 samp[i].left += (data * leftvol)>>8;
430 samp[i].right += (data * rightvol)>>8;
431
432 if (sampleOffset == SND_CHUNK_SIZE) {
433 chunk = chunk->next;
434 samples = chunk->sndChunk;
435 sampleOffset = 0;
436 }
437 }
438 } else {
439 fleftvol = ch->leftvol*snd_vol;
440 frightvol = ch->rightvol*snd_vol;
441
442 ooff = sampleOffset;
443 samples = chunk->sndChunk;
444
445
446
447
448 for ( i=0 ; i<count ; i++ ) {
449
450 aoff = ooff;
451 ooff = ooff + ch->dopplerScale;
452 boff = ooff;
453 fdata = 0;
454 for (j=aoff; j<boff; j++) {
455 if (j == SND_CHUNK_SIZE) {
456 chunk = chunk->next;
457 if (!chunk) {
458 chunk = sc->soundData;
459 }
460 samples = chunk->sndChunk;
461 ooff -= SND_CHUNK_SIZE;
462 }
463 fdata += samples[j&(SND_CHUNK_SIZE-1)];
464 }
465 fdiv = 256 * (boff-aoff);
466 samp[i].left += (fdata * fleftvol)/fdiv;
467 samp[i].right += (fdata * frightvol)/fdiv;
468 }
469 }
470 }
471
S_PaintChannelFrom16(channel_t * ch,const sfx_t * sc,int count,int sampleOffset,int bufferOffset)472 static void S_PaintChannelFrom16( channel_t *ch, const sfx_t *sc, int count, int sampleOffset, int bufferOffset ) {
473 #if idppc_altivec
474 if (com_altivec->integer) {
475 // must be in a seperate function or G3 systems will crash.
476 S_PaintChannelFrom16_altivec( ch, sc, count, sampleOffset, bufferOffset );
477 return;
478 }
479 #endif
480 S_PaintChannelFrom16_scalar( ch, sc, count, sampleOffset, bufferOffset );
481 }
482
S_PaintChannelFromWavelet(channel_t * ch,sfx_t * sc,int count,int sampleOffset,int bufferOffset)483 void S_PaintChannelFromWavelet( channel_t *ch, sfx_t *sc, int count, int sampleOffset, int bufferOffset ) {
484 int data;
485 int leftvol, rightvol;
486 int i;
487 portable_samplepair_t *samp;
488 sndBuffer *chunk;
489 short *samples;
490
491 leftvol = ch->leftvol*snd_vol;
492 rightvol = ch->rightvol*snd_vol;
493
494 i = 0;
495 samp = &paintbuffer[ bufferOffset ];
496 chunk = sc->soundData;
497 while (sampleOffset>=(SND_CHUNK_SIZE_FLOAT*4)) {
498 chunk = chunk->next;
499 sampleOffset -= (SND_CHUNK_SIZE_FLOAT*4);
500 i++;
501 }
502
503 if (i!=sfxScratchIndex || sfxScratchPointer != sc) {
504 S_AdpcmGetSamples( chunk, sfxScratchBuffer );
505 sfxScratchIndex = i;
506 sfxScratchPointer = sc;
507 }
508
509 samples = sfxScratchBuffer;
510
511 for ( i=0 ; i<count ; i++ ) {
512 data = samples[sampleOffset++];
513 samp[i].left += (data * leftvol)>>8;
514 samp[i].right += (data * rightvol)>>8;
515
516 if (sampleOffset == SND_CHUNK_SIZE*2) {
517 chunk = chunk->next;
518 decodeWavelet(chunk, sfxScratchBuffer);
519 sfxScratchIndex++;
520 sampleOffset = 0;
521 }
522 }
523 }
524
S_PaintChannelFromADPCM(channel_t * ch,sfx_t * sc,int count,int sampleOffset,int bufferOffset)525 void S_PaintChannelFromADPCM( channel_t *ch, sfx_t *sc, int count, int sampleOffset, int bufferOffset ) {
526 int data;
527 int leftvol, rightvol;
528 int i;
529 portable_samplepair_t *samp;
530 sndBuffer *chunk;
531 short *samples;
532
533 leftvol = ch->leftvol*snd_vol;
534 rightvol = ch->rightvol*snd_vol;
535
536 i = 0;
537 samp = &paintbuffer[ bufferOffset ];
538 chunk = sc->soundData;
539
540 if (ch->doppler) {
541 sampleOffset = sampleOffset*ch->oldDopplerScale;
542 }
543
544 while (sampleOffset>=(SND_CHUNK_SIZE*4)) {
545 chunk = chunk->next;
546 sampleOffset -= (SND_CHUNK_SIZE*4);
547 i++;
548 }
549
550 if (i!=sfxScratchIndex || sfxScratchPointer != sc) {
551 S_AdpcmGetSamples( chunk, sfxScratchBuffer );
552 sfxScratchIndex = i;
553 sfxScratchPointer = sc;
554 }
555
556 samples = sfxScratchBuffer;
557
558 for ( i=0 ; i<count ; i++ ) {
559 data = samples[sampleOffset++];
560 samp[i].left += (data * leftvol)>>8;
561 samp[i].right += (data * rightvol)>>8;
562
563 if (sampleOffset == SND_CHUNK_SIZE*4) {
564 chunk = chunk->next;
565 S_AdpcmGetSamples( chunk, sfxScratchBuffer);
566 sampleOffset = 0;
567 sfxScratchIndex++;
568 }
569 }
570 }
571
S_PaintChannelFromMuLaw(channel_t * ch,sfx_t * sc,int count,int sampleOffset,int bufferOffset)572 void S_PaintChannelFromMuLaw( channel_t *ch, sfx_t *sc, int count, int sampleOffset, int bufferOffset ) {
573 int data;
574 int leftvol, rightvol;
575 int i;
576 portable_samplepair_t *samp;
577 sndBuffer *chunk;
578 byte *samples;
579 float ooff;
580
581 leftvol = ch->leftvol*snd_vol;
582 rightvol = ch->rightvol*snd_vol;
583
584 samp = &paintbuffer[ bufferOffset ];
585 chunk = sc->soundData;
586 while (sampleOffset>=(SND_CHUNK_SIZE*2)) {
587 chunk = chunk->next;
588 sampleOffset -= (SND_CHUNK_SIZE*2);
589 if (!chunk) {
590 chunk = sc->soundData;
591 }
592 }
593
594 if (!ch->doppler) {
595 samples = (byte *)chunk->sndChunk + sampleOffset;
596 for ( i=0 ; i<count ; i++ ) {
597 data = mulawToShort[*samples];
598 samp[i].left += (data * leftvol)>>8;
599 samp[i].right += (data * rightvol)>>8;
600 samples++;
601 if (samples == (byte *)chunk->sndChunk+(SND_CHUNK_SIZE*2)) {
602 chunk = chunk->next;
603 samples = (byte *)chunk->sndChunk;
604 }
605 }
606 } else {
607 ooff = sampleOffset;
608 samples = (byte *)chunk->sndChunk;
609 for ( i=0 ; i<count ; i++ ) {
610 data = mulawToShort[samples[(int)(ooff)]];
611 ooff = ooff + ch->dopplerScale;
612 samp[i].left += (data * leftvol)>>8;
613 samp[i].right += (data * rightvol)>>8;
614 if (ooff >= SND_CHUNK_SIZE*2) {
615 chunk = chunk->next;
616 if (!chunk) {
617 chunk = sc->soundData;
618 }
619 samples = (byte *)chunk->sndChunk;
620 ooff = 0.0;
621 }
622 }
623 }
624 }
625
626 /*
627 ===================
628 S_PaintChannels
629 ===================
630 */
S_PaintChannels(int endtime)631 void S_PaintChannels( int endtime ) {
632 int i;
633 int end;
634 channel_t *ch;
635 sfx_t *sc;
636 int ltime, count;
637 int sampleOffset;
638
639
640 snd_vol = s_volume->value*255;
641
642 //Com_Printf ("%i to %i\n", s_paintedtime, endtime);
643 while ( s_paintedtime < endtime ) {
644 // if paintbuffer is smaller than DMA buffer
645 // we may need to fill it multiple times
646 end = endtime;
647 if ( endtime - s_paintedtime > PAINTBUFFER_SIZE ) {
648 end = s_paintedtime + PAINTBUFFER_SIZE;
649 }
650
651 // clear the paint buffer to either music or zeros
652 if ( s_rawend < s_paintedtime ) {
653 if ( s_rawend ) {
654 //Com_DPrintf ("background sound underrun\n");
655 }
656 Com_Memset(paintbuffer, 0, (end - s_paintedtime) * sizeof(portable_samplepair_t));
657 } else {
658 // copy from the streaming sound source
659 int s;
660 int stop;
661
662 stop = (end < s_rawend) ? end : s_rawend;
663
664 for ( i = s_paintedtime ; i < stop ; i++ ) {
665 s = i&(MAX_RAW_SAMPLES-1);
666 paintbuffer[i-s_paintedtime] = s_rawsamples[s];
667 }
668 // if (i != end)
669 // Com_Printf ("partial stream\n");
670 // else
671 // Com_Printf ("full stream\n");
672 for ( ; i < end ; i++ ) {
673 paintbuffer[i-s_paintedtime].left =
674 paintbuffer[i-s_paintedtime].right = 0;
675 }
676 }
677
678 // paint in the channels.
679 ch = s_channels;
680 for ( i = 0; i < MAX_CHANNELS ; i++, ch++ ) {
681 if ( !ch->thesfx || (ch->leftvol<0.25 && ch->rightvol<0.25 )) {
682 continue;
683 }
684
685 ltime = s_paintedtime;
686 sc = ch->thesfx;
687
688 sampleOffset = ltime - ch->startSample;
689 count = end - ltime;
690 if ( sampleOffset + count > sc->soundLength ) {
691 count = sc->soundLength - sampleOffset;
692 }
693
694 if ( count > 0 ) {
695 if( sc->soundCompressionMethod == 1) {
696 S_PaintChannelFromADPCM (ch, sc, count, sampleOffset, ltime - s_paintedtime);
697 } else if( sc->soundCompressionMethod == 2) {
698 S_PaintChannelFromWavelet (ch, sc, count, sampleOffset, ltime - s_paintedtime);
699 } else if( sc->soundCompressionMethod == 3) {
700 S_PaintChannelFromMuLaw (ch, sc, count, sampleOffset, ltime - s_paintedtime);
701 } else {
702 S_PaintChannelFrom16 (ch, sc, count, sampleOffset, ltime - s_paintedtime);
703 }
704 }
705 }
706
707 // paint in the looped channels.
708 ch = loop_channels;
709 for ( i = 0; i < numLoopChannels ; i++, ch++ ) {
710 if ( !ch->thesfx || (!ch->leftvol && !ch->rightvol )) {
711 continue;
712 }
713
714 ltime = s_paintedtime;
715 sc = ch->thesfx;
716
717 if (sc->soundData==NULL || sc->soundLength==0) {
718 continue;
719 }
720 // we might have to make two passes if it
721 // is a looping sound effect and the end of
722 // the sample is hit
723 do {
724 sampleOffset = (ltime % sc->soundLength);
725
726 count = end - ltime;
727 if ( sampleOffset + count > sc->soundLength ) {
728 count = sc->soundLength - sampleOffset;
729 }
730
731 if ( count > 0 ) {
732 if( sc->soundCompressionMethod == 1) {
733 S_PaintChannelFromADPCM (ch, sc, count, sampleOffset, ltime - s_paintedtime);
734 } else if( sc->soundCompressionMethod == 2) {
735 S_PaintChannelFromWavelet (ch, sc, count, sampleOffset, ltime - s_paintedtime);
736 } else if( sc->soundCompressionMethod == 3) {
737 S_PaintChannelFromMuLaw (ch, sc, count, sampleOffset, ltime - s_paintedtime);
738 } else {
739 S_PaintChannelFrom16 (ch, sc, count, sampleOffset, ltime - s_paintedtime);
740 }
741 ltime += count;
742 }
743 } while ( ltime < end);
744 }
745
746 // transfer out according to DMA format
747 S_TransferPaintBuffer( end );
748 s_paintedtime = end;
749 }
750 }
751