Quake-III-Arena

Quake III Arena GPL Source Release
Log | Files | Refs

snd_mix.c (17274B)


      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 Foobar; 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 "snd_local.h"
     25 
     26 static portable_samplepair_t paintbuffer[PAINTBUFFER_SIZE];
     27 static int snd_vol;
     28 
     29 // bk001119 - these not static, required by unix/snd_mixa.s
     30 int*     snd_p;  
     31 int      snd_linear_count;
     32 short*   snd_out;
     33 
     34 #if !( (defined __linux__ || defined __FreeBSD__ ) && (defined __i386__) ) // rb010123
     35 #if	!id386
     36 
     37 void S_WriteLinearBlastStereo16 (void)
     38 {
     39 	int		i;
     40 	int		val;
     41 
     42 	for (i=0 ; i<snd_linear_count ; i+=2)
     43 	{
     44 		val = snd_p[i]>>8;
     45 		if (val > 0x7fff)
     46 			snd_out[i] = 0x7fff;
     47 		else if (val < -32768)
     48 			snd_out[i] = -32768;
     49 		else
     50 			snd_out[i] = val;
     51 
     52 		val = snd_p[i+1]>>8;
     53 		if (val > 0x7fff)
     54 			snd_out[i+1] = 0x7fff;
     55 		else if (val < -32768)
     56 			snd_out[i+1] = -32768;
     57 		else
     58 			snd_out[i+1] = val;
     59 	}
     60 }
     61 #else
     62 
     63 __declspec( naked ) void S_WriteLinearBlastStereo16 (void)
     64 {
     65 	__asm {
     66 
     67  push edi
     68  push ebx
     69  mov ecx,ds:dword ptr[snd_linear_count]
     70  mov ebx,ds:dword ptr[snd_p]
     71  mov edi,ds:dword ptr[snd_out]
     72 LWLBLoopTop:
     73  mov eax,ds:dword ptr[-8+ebx+ecx*4]
     74  sar eax,8
     75  cmp eax,07FFFh
     76  jg LClampHigh
     77  cmp eax,0FFFF8000h
     78  jnl LClampDone
     79  mov eax,0FFFF8000h
     80  jmp LClampDone
     81 LClampHigh:
     82  mov eax,07FFFh
     83 LClampDone:
     84  mov edx,ds:dword ptr[-4+ebx+ecx*4]
     85  sar edx,8
     86  cmp edx,07FFFh
     87  jg LClampHigh2
     88  cmp edx,0FFFF8000h
     89  jnl LClampDone2
     90  mov edx,0FFFF8000h
     91  jmp LClampDone2
     92 LClampHigh2:
     93  mov edx,07FFFh
     94 LClampDone2:
     95  shl edx,16
     96  and eax,0FFFFh
     97  or edx,eax
     98  mov ds:dword ptr[-4+edi+ecx*2],edx
     99  sub ecx,2
    100  jnz LWLBLoopTop
    101  pop ebx
    102  pop edi
    103  ret
    104 	}
    105 }
    106 
    107 #endif
    108 #else
    109 // forward declare, implementation somewhere else
    110 void S_WriteLinearBlastStereo16 (void);
    111 #endif
    112 
    113 void S_TransferStereo16 (unsigned long *pbuf, int endtime)
    114 {
    115 	int		lpos;
    116 	int		ls_paintedtime;
    117 	
    118 	snd_p = (int *) paintbuffer;
    119 	ls_paintedtime = s_paintedtime;
    120 
    121 	while (ls_paintedtime < endtime)
    122 	{
    123 	// handle recirculating buffer issues
    124 		lpos = ls_paintedtime & ((dma.samples>>1)-1);
    125 
    126 		snd_out = (short *) pbuf + (lpos<<1);
    127 
    128 		snd_linear_count = (dma.samples>>1) - lpos;
    129 		if (ls_paintedtime + snd_linear_count > endtime)
    130 			snd_linear_count = endtime - ls_paintedtime;
    131 
    132 		snd_linear_count <<= 1;
    133 
    134 	// write a linear blast of samples
    135 		S_WriteLinearBlastStereo16 ();
    136 
    137 		snd_p += snd_linear_count;
    138 		ls_paintedtime += (snd_linear_count>>1);
    139 	}
    140 }
    141 
    142 /*
    143 ===================
    144 S_TransferPaintBuffer
    145 
    146 ===================
    147 */
    148 void S_TransferPaintBuffer(int endtime)
    149 {
    150 	int 	out_idx;
    151 	int 	count;
    152 	int 	out_mask;
    153 	int 	*p;
    154 	int 	step;
    155 	int		val;
    156 	unsigned long *pbuf;
    157 
    158 	pbuf = (unsigned long *)dma.buffer;
    159 
    160 
    161 	if ( s_testsound->integer ) {
    162 		int		i;
    163 		int		count;
    164 
    165 		// write a fixed sine wave
    166 		count = (endtime - s_paintedtime);
    167 		for (i=0 ; i<count ; i++)
    168 			paintbuffer[i].left = paintbuffer[i].right = sin((s_paintedtime+i)*0.1)*20000*256;
    169 	}
    170 
    171 
    172 	if (dma.samplebits == 16 && dma.channels == 2)
    173 	{	// optimized case
    174 		S_TransferStereo16 (pbuf, endtime);
    175 	}
    176 	else
    177 	{	// general case
    178 		p = (int *) paintbuffer;
    179 		count = (endtime - s_paintedtime) * dma.channels;
    180 		out_mask = dma.samples - 1; 
    181 		out_idx = s_paintedtime * dma.channels & out_mask;
    182 		step = 3 - dma.channels;
    183 
    184 		if (dma.samplebits == 16)
    185 		{
    186 			short *out = (short *) pbuf;
    187 			while (count--)
    188 			{
    189 				val = *p >> 8;
    190 				p+= step;
    191 				if (val > 0x7fff)
    192 					val = 0x7fff;
    193 				else if (val < -32768)
    194 					val = -32768;
    195 				out[out_idx] = val;
    196 				out_idx = (out_idx + 1) & out_mask;
    197 			}
    198 		}
    199 		else if (dma.samplebits == 8)
    200 		{
    201 			unsigned char *out = (unsigned char *) pbuf;
    202 			while (count--)
    203 			{
    204 				val = *p >> 8;
    205 				p+= step;
    206 				if (val > 0x7fff)
    207 					val = 0x7fff;
    208 				else if (val < -32768)
    209 					val = -32768;
    210 				out[out_idx] = (val>>8) + 128;
    211 				out_idx = (out_idx + 1) & out_mask;
    212 			}
    213 		}
    214 	}
    215 }
    216 
    217 
    218 /*
    219 ===============================================================================
    220 
    221 CHANNEL MIXING
    222 
    223 ===============================================================================
    224 */
    225 
    226 static void S_PaintChannelFrom16( channel_t *ch, const sfx_t *sc, int count, int sampleOffset, int bufferOffset ) {
    227 	int						data, aoff, boff;
    228 	int						leftvol, rightvol;
    229 	int						i, j;
    230 	portable_samplepair_t	*samp;
    231 	sndBuffer				*chunk;
    232 	short					*samples;
    233 	float					ooff, fdata, fdiv, fleftvol, frightvol;
    234 
    235 	samp = &paintbuffer[ bufferOffset ];
    236 
    237 	if (ch->doppler) {
    238 		sampleOffset = sampleOffset*ch->oldDopplerScale;
    239 	}
    240 
    241 	chunk = sc->soundData;
    242 	while (sampleOffset>=SND_CHUNK_SIZE) {
    243 		chunk = chunk->next;
    244 		sampleOffset -= SND_CHUNK_SIZE;
    245 		if (!chunk) {
    246 			chunk = sc->soundData;
    247 		}
    248 	}
    249 
    250 	if (!ch->doppler || ch->dopplerScale==1.0f) {
    251 #if idppc_altivec
    252 		vector signed short volume_vec;
    253 		vector unsigned int volume_shift;
    254 		int vectorCount, samplesLeft, chunkSamplesLeft;
    255 #endif
    256 		leftvol = ch->leftvol*snd_vol;
    257 		rightvol = ch->rightvol*snd_vol;
    258 		samples = chunk->sndChunk;
    259 #if idppc_altivec
    260 		((short *)&volume_vec)[0] = leftvol;
    261 		((short *)&volume_vec)[1] = leftvol;
    262 		((short *)&volume_vec)[4] = leftvol;
    263 		((short *)&volume_vec)[5] = leftvol;
    264 		((short *)&volume_vec)[2] = rightvol;
    265 		((short *)&volume_vec)[3] = rightvol;
    266 		((short *)&volume_vec)[6] = rightvol;
    267 		((short *)&volume_vec)[7] = rightvol;
    268 		volume_shift = vec_splat_u32(8);
    269 		i = 0;
    270 
    271 		while(i < count) {
    272 			/* Try to align destination to 16-byte boundary */
    273 			while(i < count && (((unsigned long)&samp[i] & 0x1f) || ((count-i) < 8) || ((SND_CHUNK_SIZE - sampleOffset) < 8))) {
    274 				data  = samples[sampleOffset++];
    275 				samp[i].left += (data * leftvol)>>8;
    276 				samp[i].right += (data * rightvol)>>8;
    277 	
    278 				if (sampleOffset == SND_CHUNK_SIZE) {
    279 					chunk = chunk->next;
    280 					samples = chunk->sndChunk;
    281 					sampleOffset = 0;
    282 				}
    283 				i++;
    284 			}
    285 			/* Destination is now aligned.  Process as many 8-sample 
    286 			   chunks as we can before we run out of room from the current
    287 			   sound chunk.  We do 8 per loop to avoid extra source data reads. */
    288 			samplesLeft = count - i;
    289 			chunkSamplesLeft = SND_CHUNK_SIZE - sampleOffset;
    290 			if(samplesLeft > chunkSamplesLeft)
    291 				samplesLeft = chunkSamplesLeft;
    292 			
    293 			vectorCount = samplesLeft / 8;
    294 			
    295 			if(vectorCount)
    296 			{
    297 				vector unsigned char tmp;
    298 				vector short s0, s1, sampleData0, sampleData1;
    299 				vector short samples0, samples1;
    300 				vector signed int left0, right0;
    301 				vector signed int merge0, merge1;
    302 				vector signed int d0, d1, d2, d3;				
    303 				vector unsigned char samplePermute0 = 
    304 					(vector unsigned char)(0, 1, 4, 5, 0, 1, 4, 5, 2, 3, 6, 7, 2, 3, 6, 7);
    305 				vector unsigned char samplePermute1 = 
    306 					(vector unsigned char)(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 		for ( i=0 ; i<count ; i++ ) {
    369 			data  = samples[sampleOffset++];
    370 			samp[i].left += (data * leftvol)>>8;
    371 			samp[i].right += (data * rightvol)>>8;
    372 
    373 			if (sampleOffset == SND_CHUNK_SIZE) {
    374 				chunk = chunk->next;
    375 				samples = chunk->sndChunk;
    376 				sampleOffset = 0;
    377 			}
    378 		}
    379 #endif
    380 	} else {
    381 		fleftvol = ch->leftvol*snd_vol;
    382 		frightvol = ch->rightvol*snd_vol;
    383 
    384 		ooff = sampleOffset;
    385 		samples = chunk->sndChunk;
    386 		
    387 
    388 
    389 
    390 		for ( i=0 ; i<count ; i++ ) {
    391 
    392 			aoff = ooff;
    393 			ooff = ooff + ch->dopplerScale;
    394 			boff = ooff;
    395 			fdata = 0;
    396 			for (j=aoff; j<boff; j++) {
    397 				if (j == SND_CHUNK_SIZE) {
    398 					chunk = chunk->next;
    399 					if (!chunk) {
    400 						chunk = sc->soundData;
    401 					}
    402 					samples = chunk->sndChunk;
    403 					ooff -= SND_CHUNK_SIZE;
    404 				}
    405 				fdata  += samples[j&(SND_CHUNK_SIZE-1)];
    406 			}
    407 			fdiv = 256 * (boff-aoff);
    408 			samp[i].left += (fdata * fleftvol)/fdiv;
    409 			samp[i].right += (fdata * frightvol)/fdiv;
    410 		}
    411 	}
    412 }
    413 
    414 void S_PaintChannelFromWavelet( channel_t *ch, sfx_t *sc, int count, int sampleOffset, int bufferOffset ) {
    415 	int						data;
    416 	int						leftvol, rightvol;
    417 	int						i;
    418 	portable_samplepair_t	*samp;
    419 	sndBuffer				*chunk;
    420 	short					*samples;
    421 
    422 	leftvol = ch->leftvol*snd_vol;
    423 	rightvol = ch->rightvol*snd_vol;
    424 
    425 	i = 0;
    426 	samp = &paintbuffer[ bufferOffset ];
    427 	chunk = sc->soundData;
    428 	while (sampleOffset>=(SND_CHUNK_SIZE_FLOAT*4)) {
    429 		chunk = chunk->next;
    430 		sampleOffset -= (SND_CHUNK_SIZE_FLOAT*4);
    431 		i++;
    432 	}
    433 
    434 	if (i!=sfxScratchIndex || sfxScratchPointer != sc) {
    435 		S_AdpcmGetSamples( chunk, sfxScratchBuffer );
    436 		sfxScratchIndex = i;
    437 		sfxScratchPointer = sc;
    438 	}
    439 
    440 	samples = sfxScratchBuffer;
    441 
    442 	for ( i=0 ; i<count ; i++ ) {
    443 		data  = samples[sampleOffset++];
    444 		samp[i].left += (data * leftvol)>>8;
    445 		samp[i].right += (data * rightvol)>>8;
    446 
    447 		if (sampleOffset == SND_CHUNK_SIZE*2) {
    448 			chunk = chunk->next;
    449 			decodeWavelet(chunk, sfxScratchBuffer);
    450 			sfxScratchIndex++;
    451 			sampleOffset = 0;
    452 		}
    453 	}
    454 }
    455 
    456 void S_PaintChannelFromADPCM( channel_t *ch, sfx_t *sc, int count, int sampleOffset, int bufferOffset ) {
    457 	int						data;
    458 	int						leftvol, rightvol;
    459 	int						i;
    460 	portable_samplepair_t	*samp;
    461 	sndBuffer				*chunk;
    462 	short					*samples;
    463 
    464 	leftvol = ch->leftvol*snd_vol;
    465 	rightvol = ch->rightvol*snd_vol;
    466 
    467 	i = 0;
    468 	samp = &paintbuffer[ bufferOffset ];
    469 	chunk = sc->soundData;
    470 
    471 	if (ch->doppler) {
    472 		sampleOffset = sampleOffset*ch->oldDopplerScale;
    473 	}
    474 
    475 	while (sampleOffset>=(SND_CHUNK_SIZE*4)) {
    476 		chunk = chunk->next;
    477 		sampleOffset -= (SND_CHUNK_SIZE*4);
    478 		i++;
    479 	}
    480 
    481 	if (i!=sfxScratchIndex || sfxScratchPointer != sc) {
    482 		S_AdpcmGetSamples( chunk, sfxScratchBuffer );
    483 		sfxScratchIndex = i;
    484 		sfxScratchPointer = sc;
    485 	}
    486 
    487 	samples = sfxScratchBuffer;
    488 
    489 	for ( i=0 ; i<count ; i++ ) {
    490 		data  = samples[sampleOffset++];
    491 		samp[i].left += (data * leftvol)>>8;
    492 		samp[i].right += (data * rightvol)>>8;
    493 
    494 		if (sampleOffset == SND_CHUNK_SIZE*4) {
    495 			chunk = chunk->next;
    496 			S_AdpcmGetSamples( chunk, sfxScratchBuffer);
    497 			sampleOffset = 0;
    498 			sfxScratchIndex++;
    499 		}
    500 	}
    501 }
    502 
    503 void S_PaintChannelFromMuLaw( channel_t *ch, sfx_t *sc, int count, int sampleOffset, int bufferOffset ) {
    504 	int						data;
    505 	int						leftvol, rightvol;
    506 	int						i;
    507 	portable_samplepair_t	*samp;
    508 	sndBuffer				*chunk;
    509 	byte					*samples;
    510 	float					ooff;
    511 
    512 	leftvol = ch->leftvol*snd_vol;
    513 	rightvol = ch->rightvol*snd_vol;
    514 
    515 	samp = &paintbuffer[ bufferOffset ];
    516 	chunk = sc->soundData;
    517 	while (sampleOffset>=(SND_CHUNK_SIZE*2)) {
    518 		chunk = chunk->next;
    519 		sampleOffset -= (SND_CHUNK_SIZE*2);
    520 		if (!chunk) {
    521 			chunk = sc->soundData;
    522 		}
    523 	}
    524 
    525 	if (!ch->doppler) {
    526 		samples = (byte *)chunk->sndChunk + sampleOffset;
    527 		for ( i=0 ; i<count ; i++ ) {
    528 			data  = mulawToShort[*samples];
    529 			samp[i].left += (data * leftvol)>>8;
    530 			samp[i].right += (data * rightvol)>>8;
    531 			samples++;
    532 			if (samples == (byte *)chunk->sndChunk+(SND_CHUNK_SIZE*2)) {
    533 				chunk = chunk->next;
    534 				samples = (byte *)chunk->sndChunk;
    535 			}
    536 		}
    537 	} else {
    538 		ooff = sampleOffset;
    539 		samples = (byte *)chunk->sndChunk;
    540 		for ( i=0 ; i<count ; i++ ) {
    541 			data  = mulawToShort[samples[(int)(ooff)]];
    542 			ooff = ooff + ch->dopplerScale;
    543 			samp[i].left += (data * leftvol)>>8;
    544 			samp[i].right += (data * rightvol)>>8;
    545 			if (ooff >= SND_CHUNK_SIZE*2) {
    546 				chunk = chunk->next;
    547 				if (!chunk) {
    548 					chunk = sc->soundData;
    549 				}
    550 				samples = (byte *)chunk->sndChunk;
    551 				ooff = 0.0;
    552 			}
    553 		}
    554 	}
    555 }
    556 
    557 /*
    558 ===================
    559 S_PaintChannels
    560 ===================
    561 */
    562 void S_PaintChannels( int endtime ) {
    563 	int 	i;
    564 	int 	end;
    565 	channel_t *ch;
    566 	sfx_t	*sc;
    567 	int		ltime, count;
    568 	int		sampleOffset;
    569 
    570 
    571 	snd_vol = s_volume->value*255;
    572 
    573 //Com_Printf ("%i to %i\n", s_paintedtime, endtime);
    574 	while ( s_paintedtime < endtime ) {
    575 		// if paintbuffer is smaller than DMA buffer
    576 		// we may need to fill it multiple times
    577 		end = endtime;
    578 		if ( endtime - s_paintedtime > PAINTBUFFER_SIZE ) {
    579 			end = s_paintedtime + PAINTBUFFER_SIZE;
    580 		}
    581 
    582 		// clear the paint buffer to either music or zeros
    583 		if ( s_rawend < s_paintedtime ) {
    584 			if ( s_rawend ) {
    585 				//Com_DPrintf ("background sound underrun\n");
    586 			}
    587 			Com_Memset(paintbuffer, 0, (end - s_paintedtime) * sizeof(portable_samplepair_t));
    588 		} else {
    589 			// copy from the streaming sound source
    590 			int		s;
    591 			int		stop;
    592 
    593 			stop = (end < s_rawend) ? end : s_rawend;
    594 
    595 			for ( i = s_paintedtime ; i < stop ; i++ ) {
    596 				s = i&(MAX_RAW_SAMPLES-1);
    597 				paintbuffer[i-s_paintedtime] = s_rawsamples[s];
    598 			}
    599 //		if (i != end)
    600 //			Com_Printf ("partial stream\n");
    601 //		else
    602 //			Com_Printf ("full stream\n");
    603 			for ( ; i < end ; i++ ) {
    604 				paintbuffer[i-s_paintedtime].left =
    605 				paintbuffer[i-s_paintedtime].right = 0;
    606 			}
    607 		}
    608 
    609 		// paint in the channels.
    610 		ch = s_channels;
    611 		for ( i = 0; i < MAX_CHANNELS ; i++, ch++ ) {		
    612 			if ( !ch->thesfx || (ch->leftvol<0.25 && ch->rightvol<0.25 )) {
    613 				continue;
    614 			}
    615 
    616 			ltime = s_paintedtime;
    617 			sc = ch->thesfx;
    618 
    619 			sampleOffset = ltime - ch->startSample;
    620 			count = end - ltime;
    621 			if ( sampleOffset + count > sc->soundLength ) {
    622 				count = sc->soundLength - sampleOffset;
    623 			}
    624 
    625 			if ( count > 0 ) {	
    626 				if( sc->soundCompressionMethod == 1) {
    627 					S_PaintChannelFromADPCM		(ch, sc, count, sampleOffset, ltime - s_paintedtime);
    628 				} else if( sc->soundCompressionMethod == 2) {
    629 					S_PaintChannelFromWavelet	(ch, sc, count, sampleOffset, ltime - s_paintedtime);
    630 				} else if( sc->soundCompressionMethod == 3) {
    631 					S_PaintChannelFromMuLaw	(ch, sc, count, sampleOffset, ltime - s_paintedtime);
    632 				} else {
    633 					S_PaintChannelFrom16		(ch, sc, count, sampleOffset, ltime - s_paintedtime);
    634 				}
    635 			}
    636 		}
    637 
    638 		// paint in the looped channels.
    639 		ch = loop_channels;
    640 		for ( i = 0; i < numLoopChannels ; i++, ch++ ) {		
    641 			if ( !ch->thesfx || (!ch->leftvol && !ch->rightvol )) {
    642 				continue;
    643 			}
    644 
    645 			ltime = s_paintedtime;
    646 			sc = ch->thesfx;
    647 
    648 			if (sc->soundData==NULL || sc->soundLength==0) {
    649 				continue;
    650 			}
    651 			// we might have to make two passes if it
    652 			// is a looping sound effect and the end of
    653 			// the sample is hit
    654 			do {
    655 				sampleOffset = (ltime % sc->soundLength);
    656 
    657 				count = end - ltime;
    658 				if ( sampleOffset + count > sc->soundLength ) {
    659 					count = sc->soundLength - sampleOffset;
    660 				}
    661 
    662 				if ( count > 0 ) {	
    663 					if( sc->soundCompressionMethod == 1) {
    664 						S_PaintChannelFromADPCM		(ch, sc, count, sampleOffset, ltime - s_paintedtime);
    665 					} else if( sc->soundCompressionMethod == 2) {
    666 						S_PaintChannelFromWavelet	(ch, sc, count, sampleOffset, ltime - s_paintedtime);
    667 					} else if( sc->soundCompressionMethod == 3) {
    668 						S_PaintChannelFromMuLaw		(ch, sc, count, sampleOffset, ltime - s_paintedtime);
    669 					} else {
    670 						S_PaintChannelFrom16		(ch, sc, count, sampleOffset, ltime - s_paintedtime);
    671 					}
    672 					ltime += count;
    673 				}
    674 			} while ( ltime < end);
    675 		}
    676 
    677 		// transfer out according to DMA format
    678 		S_TransferPaintBuffer( end );
    679 		s_paintedtime = end;
    680 	}
    681 }