aboutsummaryrefslogtreecommitdiffstats
path: root/code/client/snd_mix.c
diff options
context:
space:
mode:
Diffstat (limited to 'code/client/snd_mix.c')
-rwxr-xr-xcode/client/snd_mix.c1362
1 files changed, 681 insertions, 681 deletions
diff --git a/code/client/snd_mix.c b/code/client/snd_mix.c
index ec983b9..02be59c 100755
--- a/code/client/snd_mix.c
+++ b/code/client/snd_mix.c
@@ -1,681 +1,681 @@
-/*
-===========================================================================
-Copyright (C) 1999-2005 Id Software, Inc.
-
-This file is part of Quake III Arena source code.
-
-Quake III Arena source code is free software; you can redistribute it
-and/or modify it under the terms of the GNU General Public License as
-published by the Free Software Foundation; either version 2 of the License,
-or (at your option) any later version.
-
-Quake III Arena source code is distributed in the hope that it will be
-useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
-MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-GNU General Public License for more details.
-
-You should have received a copy of the GNU General Public License
-along with Foobar; if not, write to the Free Software
-Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
-===========================================================================
-*/
-// snd_mix.c -- portable code to mix sounds for snd_dma.c
-
-#include "snd_local.h"
-
-static portable_samplepair_t paintbuffer[PAINTBUFFER_SIZE];
-static int snd_vol;
-
-// bk001119 - these not static, required by unix/snd_mixa.s
-int* snd_p;
-int snd_linear_count;
-short* snd_out;
-
-#if !( (defined __linux__ || defined __FreeBSD__ ) && (defined __i386__) ) // rb010123
-#if !id386
-
-void S_WriteLinearBlastStereo16 (void)
-{
- int i;
- int val;
-
- for (i=0 ; i<snd_linear_count ; i+=2)
- {
- val = snd_p[i]>>8;
- if (val > 0x7fff)
- snd_out[i] = 0x7fff;
- else if (val < -32768)
- snd_out[i] = -32768;
- else
- snd_out[i] = val;
-
- val = snd_p[i+1]>>8;
- if (val > 0x7fff)
- snd_out[i+1] = 0x7fff;
- else if (val < -32768)
- snd_out[i+1] = -32768;
- else
- snd_out[i+1] = val;
- }
-}
-#else
-
-__declspec( naked ) void S_WriteLinearBlastStereo16 (void)
-{
- __asm {
-
- push edi
- push ebx
- mov ecx,ds:dword ptr[snd_linear_count]
- mov ebx,ds:dword ptr[snd_p]
- mov edi,ds:dword ptr[snd_out]
-LWLBLoopTop:
- mov eax,ds:dword ptr[-8+ebx+ecx*4]
- sar eax,8
- cmp eax,07FFFh
- jg LClampHigh
- cmp eax,0FFFF8000h
- jnl LClampDone
- mov eax,0FFFF8000h
- jmp LClampDone
-LClampHigh:
- mov eax,07FFFh
-LClampDone:
- mov edx,ds:dword ptr[-4+ebx+ecx*4]
- sar edx,8
- cmp edx,07FFFh
- jg LClampHigh2
- cmp edx,0FFFF8000h
- jnl LClampDone2
- mov edx,0FFFF8000h
- jmp LClampDone2
-LClampHigh2:
- mov edx,07FFFh
-LClampDone2:
- shl edx,16
- and eax,0FFFFh
- or edx,eax
- mov ds:dword ptr[-4+edi+ecx*2],edx
- sub ecx,2
- jnz LWLBLoopTop
- pop ebx
- pop edi
- ret
- }
-}
-
-#endif
-#else
-// forward declare, implementation somewhere else
-void S_WriteLinearBlastStereo16 (void);
-#endif
-
-void S_TransferStereo16 (unsigned long *pbuf, int endtime)
-{
- int lpos;
- int ls_paintedtime;
-
- snd_p = (int *) paintbuffer;
- ls_paintedtime = s_paintedtime;
-
- while (ls_paintedtime < endtime)
- {
- // handle recirculating buffer issues
- lpos = ls_paintedtime & ((dma.samples>>1)-1);
-
- snd_out = (short *) pbuf + (lpos<<1);
-
- snd_linear_count = (dma.samples>>1) - lpos;
- if (ls_paintedtime + snd_linear_count > endtime)
- snd_linear_count = endtime - ls_paintedtime;
-
- snd_linear_count <<= 1;
-
- // write a linear blast of samples
- S_WriteLinearBlastStereo16 ();
-
- snd_p += snd_linear_count;
- ls_paintedtime += (snd_linear_count>>1);
- }
-}
-
-/*
-===================
-S_TransferPaintBuffer
-
-===================
-*/
-void S_TransferPaintBuffer(int endtime)
-{
- int out_idx;
- int count;
- int out_mask;
- int *p;
- int step;
- int val;
- unsigned long *pbuf;
-
- pbuf = (unsigned long *)dma.buffer;
-
-
- if ( s_testsound->integer ) {
- int i;
- int count;
-
- // write a fixed sine wave
- count = (endtime - s_paintedtime);
- for (i=0 ; i<count ; i++)
- paintbuffer[i].left = paintbuffer[i].right = sin((s_paintedtime+i)*0.1)*20000*256;
- }
-
-
- if (dma.samplebits == 16 && dma.channels == 2)
- { // optimized case
- S_TransferStereo16 (pbuf, endtime);
- }
- else
- { // general case
- p = (int *) paintbuffer;
- count = (endtime - s_paintedtime) * dma.channels;
- out_mask = dma.samples - 1;
- out_idx = s_paintedtime * dma.channels & out_mask;
- step = 3 - dma.channels;
-
- if (dma.samplebits == 16)
- {
- short *out = (short *) pbuf;
- while (count--)
- {
- val = *p >> 8;
- p+= step;
- if (val > 0x7fff)
- val = 0x7fff;
- else if (val < -32768)
- val = -32768;
- out[out_idx] = val;
- out_idx = (out_idx + 1) & out_mask;
- }
- }
- else if (dma.samplebits == 8)
- {
- unsigned char *out = (unsigned char *) pbuf;
- while (count--)
- {
- val = *p >> 8;
- p+= step;
- if (val > 0x7fff)
- val = 0x7fff;
- else if (val < -32768)
- val = -32768;
- out[out_idx] = (val>>8) + 128;
- out_idx = (out_idx + 1) & out_mask;
- }
- }
- }
-}
-
-
-/*
-===============================================================================
-
-CHANNEL MIXING
-
-===============================================================================
-*/
-
-static void S_PaintChannelFrom16( channel_t *ch, const sfx_t *sc, int count, int sampleOffset, int bufferOffset ) {
- int data, aoff, boff;
- int leftvol, rightvol;
- int i, j;
- portable_samplepair_t *samp;
- sndBuffer *chunk;
- short *samples;
- float ooff, fdata, fdiv, fleftvol, frightvol;
-
- samp = &paintbuffer[ bufferOffset ];
-
- if (ch->doppler) {
- sampleOffset = sampleOffset*ch->oldDopplerScale;
- }
-
- chunk = sc->soundData;
- while (sampleOffset>=SND_CHUNK_SIZE) {
- chunk = chunk->next;
- sampleOffset -= SND_CHUNK_SIZE;
- if (!chunk) {
- chunk = sc->soundData;
- }
- }
-
- if (!ch->doppler || ch->dopplerScale==1.0f) {
-#if idppc_altivec
- vector signed short volume_vec;
- vector unsigned int volume_shift;
- int vectorCount, samplesLeft, chunkSamplesLeft;
-#endif
- leftvol = ch->leftvol*snd_vol;
- rightvol = ch->rightvol*snd_vol;
- samples = chunk->sndChunk;
-#if idppc_altivec
- ((short *)&volume_vec)[0] = leftvol;
- ((short *)&volume_vec)[1] = leftvol;
- ((short *)&volume_vec)[4] = leftvol;
- ((short *)&volume_vec)[5] = leftvol;
- ((short *)&volume_vec)[2] = rightvol;
- ((short *)&volume_vec)[3] = rightvol;
- ((short *)&volume_vec)[6] = rightvol;
- ((short *)&volume_vec)[7] = rightvol;
- volume_shift = vec_splat_u32(8);
- i = 0;
-
- while(i < count) {
- /* Try to align destination to 16-byte boundary */
- while(i < count && (((unsigned long)&samp[i] & 0x1f) || ((count-i) < 8) || ((SND_CHUNK_SIZE - sampleOffset) < 8))) {
- data = samples[sampleOffset++];
- samp[i].left += (data * leftvol)>>8;
- samp[i].right += (data * rightvol)>>8;
-
- if (sampleOffset == SND_CHUNK_SIZE) {
- chunk = chunk->next;
- samples = chunk->sndChunk;
- sampleOffset = 0;
- }
- i++;
- }
- /* Destination is now aligned. Process as many 8-sample
- chunks as we can before we run out of room from the current
- sound chunk. We do 8 per loop to avoid extra source data reads. */
- samplesLeft = count - i;
- chunkSamplesLeft = SND_CHUNK_SIZE - sampleOffset;
- if(samplesLeft > chunkSamplesLeft)
- samplesLeft = chunkSamplesLeft;
-
- vectorCount = samplesLeft / 8;
-
- if(vectorCount)
- {
- vector unsigned char tmp;
- vector short s0, s1, sampleData0, sampleData1;
- vector short samples0, samples1;
- vector signed int left0, right0;
- vector signed int merge0, merge1;
- vector signed int d0, d1, d2, d3;
- vector unsigned char samplePermute0 =
- (vector unsigned char)(0, 1, 4, 5, 0, 1, 4, 5, 2, 3, 6, 7, 2, 3, 6, 7);
- vector unsigned char samplePermute1 =
- (vector unsigned char)(8, 9, 12, 13, 8, 9, 12, 13, 10, 11, 14, 15, 10, 11, 14, 15);
- vector unsigned char loadPermute0, loadPermute1;
-
- // Rather than permute the vectors after we load them to do the sample
- // replication and rearrangement, we permute the alignment vector so
- // we do everything in one step below and avoid data shuffling.
- tmp = vec_lvsl(0,&samples[sampleOffset]);
- loadPermute0 = vec_perm(tmp,tmp,samplePermute0);
- loadPermute1 = vec_perm(tmp,tmp,samplePermute1);
-
- s0 = *(vector short *)&samples[sampleOffset];
- while(vectorCount)
- {
- /* Load up source (16-bit) sample data */
- s1 = *(vector short *)&samples[sampleOffset+7];
-
- /* Load up destination sample data */
- d0 = *(vector signed int *)&samp[i];
- d1 = *(vector signed int *)&samp[i+2];
- d2 = *(vector signed int *)&samp[i+4];
- d3 = *(vector signed int *)&samp[i+6];
-
- sampleData0 = vec_perm(s0,s1,loadPermute0);
- sampleData1 = vec_perm(s0,s1,loadPermute1);
-
- merge0 = vec_mule(sampleData0,volume_vec);
- merge0 = vec_sra(merge0,volume_shift); /* Shift down to proper range */
-
- merge1 = vec_mulo(sampleData0,volume_vec);
- merge1 = vec_sra(merge1,volume_shift);
-
- d0 = vec_add(merge0,d0);
- d1 = vec_add(merge1,d1);
-
- merge0 = vec_mule(sampleData1,volume_vec);
- merge0 = vec_sra(merge0,volume_shift); /* Shift down to proper range */
-
- merge1 = vec_mulo(sampleData1,volume_vec);
- merge1 = vec_sra(merge1,volume_shift);
-
- d2 = vec_add(merge0,d2);
- d3 = vec_add(merge1,d3);
-
- /* Store destination sample data */
- *(vector signed int *)&samp[i] = d0;
- *(vector signed int *)&samp[i+2] = d1;
- *(vector signed int *)&samp[i+4] = d2;
- *(vector signed int *)&samp[i+6] = d3;
-
- i += 8;
- vectorCount--;
- s0 = s1;
- sampleOffset += 8;
- }
- if (sampleOffset == SND_CHUNK_SIZE) {
- chunk = chunk->next;
- samples = chunk->sndChunk;
- sampleOffset = 0;
- }
- }
- }
-#else
- for ( i=0 ; i<count ; i++ ) {
- data = samples[sampleOffset++];
- samp[i].left += (data * leftvol)>>8;
- samp[i].right += (data * rightvol)>>8;
-
- if (sampleOffset == SND_CHUNK_SIZE) {
- chunk = chunk->next;
- samples = chunk->sndChunk;
- sampleOffset = 0;
- }
- }
-#endif
- } else {
- fleftvol = ch->leftvol*snd_vol;
- frightvol = ch->rightvol*snd_vol;
-
- ooff = sampleOffset;
- samples = chunk->sndChunk;
-
-
-
-
- for ( i=0 ; i<count ; i++ ) {
-
- aoff = ooff;
- ooff = ooff + ch->dopplerScale;
- boff = ooff;
- fdata = 0;
- for (j=aoff; j<boff; j++) {
- if (j == SND_CHUNK_SIZE) {
- chunk = chunk->next;
- if (!chunk) {
- chunk = sc->soundData;
- }
- samples = chunk->sndChunk;
- ooff -= SND_CHUNK_SIZE;
- }
- fdata += samples[j&(SND_CHUNK_SIZE-1)];
- }
- fdiv = 256 * (boff-aoff);
- samp[i].left += (fdata * fleftvol)/fdiv;
- samp[i].right += (fdata * frightvol)/fdiv;
- }
- }
-}
-
-void S_PaintChannelFromWavelet( channel_t *ch, sfx_t *sc, int count, int sampleOffset, int bufferOffset ) {
- int data;
- int leftvol, rightvol;
- int i;
- portable_samplepair_t *samp;
- sndBuffer *chunk;
- short *samples;
-
- leftvol = ch->leftvol*snd_vol;
- rightvol = ch->rightvol*snd_vol;
-
- i = 0;
- samp = &paintbuffer[ bufferOffset ];
- chunk = sc->soundData;
- while (sampleOffset>=(SND_CHUNK_SIZE_FLOAT*4)) {
- chunk = chunk->next;
- sampleOffset -= (SND_CHUNK_SIZE_FLOAT*4);
- i++;
- }
-
- if (i!=sfxScratchIndex || sfxScratchPointer != sc) {
- S_AdpcmGetSamples( chunk, sfxScratchBuffer );
- sfxScratchIndex = i;
- sfxScratchPointer = sc;
- }
-
- samples = sfxScratchBuffer;
-
- for ( i=0 ; i<count ; i++ ) {
- data = samples[sampleOffset++];
- samp[i].left += (data * leftvol)>>8;
- samp[i].right += (data * rightvol)>>8;
-
- if (sampleOffset == SND_CHUNK_SIZE*2) {
- chunk = chunk->next;
- decodeWavelet(chunk, sfxScratchBuffer);
- sfxScratchIndex++;
- sampleOffset = 0;
- }
- }
-}
-
-void S_PaintChannelFromADPCM( channel_t *ch, sfx_t *sc, int count, int sampleOffset, int bufferOffset ) {
- int data;
- int leftvol, rightvol;
- int i;
- portable_samplepair_t *samp;
- sndBuffer *chunk;
- short *samples;
-
- leftvol = ch->leftvol*snd_vol;
- rightvol = ch->rightvol*snd_vol;
-
- i = 0;
- samp = &paintbuffer[ bufferOffset ];
- chunk = sc->soundData;
-
- if (ch->doppler) {
- sampleOffset = sampleOffset*ch->oldDopplerScale;
- }
-
- while (sampleOffset>=(SND_CHUNK_SIZE*4)) {
- chunk = chunk->next;
- sampleOffset -= (SND_CHUNK_SIZE*4);
- i++;
- }
-
- if (i!=sfxScratchIndex || sfxScratchPointer != sc) {
- S_AdpcmGetSamples( chunk, sfxScratchBuffer );
- sfxScratchIndex = i;
- sfxScratchPointer = sc;
- }
-
- samples = sfxScratchBuffer;
-
- for ( i=0 ; i<count ; i++ ) {
- data = samples[sampleOffset++];
- samp[i].left += (data * leftvol)>>8;
- samp[i].right += (data * rightvol)>>8;
-
- if (sampleOffset == SND_CHUNK_SIZE*4) {
- chunk = chunk->next;
- S_AdpcmGetSamples( chunk, sfxScratchBuffer);
- sampleOffset = 0;
- sfxScratchIndex++;
- }
- }
-}
-
-void S_PaintChannelFromMuLaw( channel_t *ch, sfx_t *sc, int count, int sampleOffset, int bufferOffset ) {
- int data;
- int leftvol, rightvol;
- int i;
- portable_samplepair_t *samp;
- sndBuffer *chunk;
- byte *samples;
- float ooff;
-
- leftvol = ch->leftvol*snd_vol;
- rightvol = ch->rightvol*snd_vol;
-
- samp = &paintbuffer[ bufferOffset ];
- chunk = sc->soundData;
- while (sampleOffset>=(SND_CHUNK_SIZE*2)) {
- chunk = chunk->next;
- sampleOffset -= (SND_CHUNK_SIZE*2);
- if (!chunk) {
- chunk = sc->soundData;
- }
- }
-
- if (!ch->doppler) {
- samples = (byte *)chunk->sndChunk + sampleOffset;
- for ( i=0 ; i<count ; i++ ) {
- data = mulawToShort[*samples];
- samp[i].left += (data * leftvol)>>8;
- samp[i].right += (data * rightvol)>>8;
- samples++;
- if (samples == (byte *)chunk->sndChunk+(SND_CHUNK_SIZE*2)) {
- chunk = chunk->next;
- samples = (byte *)chunk->sndChunk;
- }
- }
- } else {
- ooff = sampleOffset;
- samples = (byte *)chunk->sndChunk;
- for ( i=0 ; i<count ; i++ ) {
- data = mulawToShort[samples[(int)(ooff)]];
- ooff = ooff + ch->dopplerScale;
- samp[i].left += (data * leftvol)>>8;
- samp[i].right += (data * rightvol)>>8;
- if (ooff >= SND_CHUNK_SIZE*2) {
- chunk = chunk->next;
- if (!chunk) {
- chunk = sc->soundData;
- }
- samples = (byte *)chunk->sndChunk;
- ooff = 0.0;
- }
- }
- }
-}
-
-/*
-===================
-S_PaintChannels
-===================
-*/
-void S_PaintChannels( int endtime ) {
- int i;
- int end;
- channel_t *ch;
- sfx_t *sc;
- int ltime, count;
- int sampleOffset;
-
-
- snd_vol = s_volume->value*255;
-
-//Com_Printf ("%i to %i\n", s_paintedtime, endtime);
- while ( s_paintedtime < endtime ) {
- // if paintbuffer is smaller than DMA buffer
- // we may need to fill it multiple times
- end = endtime;
- if ( endtime - s_paintedtime > PAINTBUFFER_SIZE ) {
- end = s_paintedtime + PAINTBUFFER_SIZE;
- }
-
- // clear the paint buffer to either music or zeros
- if ( s_rawend < s_paintedtime ) {
- if ( s_rawend ) {
- //Com_DPrintf ("background sound underrun\n");
- }
- Com_Memset(paintbuffer, 0, (end - s_paintedtime) * sizeof(portable_samplepair_t));
- } else {
- // copy from the streaming sound source
- int s;
- int stop;
-
- stop = (end < s_rawend) ? end : s_rawend;
-
- for ( i = s_paintedtime ; i < stop ; i++ ) {
- s = i&(MAX_RAW_SAMPLES-1);
- paintbuffer[i-s_paintedtime] = s_rawsamples[s];
- }
-// if (i != end)
-// Com_Printf ("partial stream\n");
-// else
-// Com_Printf ("full stream\n");
- for ( ; i < end ; i++ ) {
- paintbuffer[i-s_paintedtime].left =
- paintbuffer[i-s_paintedtime].right = 0;
- }
- }
-
- // paint in the channels.
- ch = s_channels;
- for ( i = 0; i < MAX_CHANNELS ; i++, ch++ ) {
- if ( !ch->thesfx || (ch->leftvol<0.25 && ch->rightvol<0.25 )) {
- continue;
- }
-
- ltime = s_paintedtime;
- sc = ch->thesfx;
-
- sampleOffset = ltime - ch->startSample;
- count = end - ltime;
- if ( sampleOffset + count > sc->soundLength ) {
- count = sc->soundLength - sampleOffset;
- }
-
- if ( count > 0 ) {
- if( sc->soundCompressionMethod == 1) {
- S_PaintChannelFromADPCM (ch, sc, count, sampleOffset, ltime - s_paintedtime);
- } else if( sc->soundCompressionMethod == 2) {
- S_PaintChannelFromWavelet (ch, sc, count, sampleOffset, ltime - s_paintedtime);
- } else if( sc->soundCompressionMethod == 3) {
- S_PaintChannelFromMuLaw (ch, sc, count, sampleOffset, ltime - s_paintedtime);
- } else {
- S_PaintChannelFrom16 (ch, sc, count, sampleOffset, ltime - s_paintedtime);
- }
- }
- }
-
- // paint in the looped channels.
- ch = loop_channels;
- for ( i = 0; i < numLoopChannels ; i++, ch++ ) {
- if ( !ch->thesfx || (!ch->leftvol && !ch->rightvol )) {
- continue;
- }
-
- ltime = s_paintedtime;
- sc = ch->thesfx;
-
- if (sc->soundData==NULL || sc->soundLength==0) {
- continue;
- }
- // we might have to make two passes if it
- // is a looping sound effect and the end of
- // the sample is hit
- do {
- sampleOffset = (ltime % sc->soundLength);
-
- count = end - ltime;
- if ( sampleOffset + count > sc->soundLength ) {
- count = sc->soundLength - sampleOffset;
- }
-
- if ( count > 0 ) {
- if( sc->soundCompressionMethod == 1) {
- S_PaintChannelFromADPCM (ch, sc, count, sampleOffset, ltime - s_paintedtime);
- } else if( sc->soundCompressionMethod == 2) {
- S_PaintChannelFromWavelet (ch, sc, count, sampleOffset, ltime - s_paintedtime);
- } else if( sc->soundCompressionMethod == 3) {
- S_PaintChannelFromMuLaw (ch, sc, count, sampleOffset, ltime - s_paintedtime);
- } else {
- S_PaintChannelFrom16 (ch, sc, count, sampleOffset, ltime - s_paintedtime);
- }
- ltime += count;
- }
- } while ( ltime < end);
- }
-
- // transfer out according to DMA format
- S_TransferPaintBuffer( end );
- s_paintedtime = end;
- }
-}
+/*
+===========================================================================
+Copyright (C) 1999-2005 Id Software, Inc.
+
+This file is part of Quake III Arena source code.
+
+Quake III Arena source code is free software; you can redistribute it
+and/or modify it under the terms of the GNU General Public License as
+published by the Free Software Foundation; either version 2 of the License,
+or (at your option) any later version.
+
+Quake III Arena source code is distributed in the hope that it will be
+useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with Foobar; if not, write to the Free Software
+Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+===========================================================================
+*/
+// snd_mix.c -- portable code to mix sounds for snd_dma.c
+
+#include "snd_local.h"
+
+static portable_samplepair_t paintbuffer[PAINTBUFFER_SIZE];
+static int snd_vol;
+
+// bk001119 - these not static, required by unix/snd_mixa.s
+int* snd_p;
+int snd_linear_count;
+short* snd_out;
+
+#if !( (defined __linux__ || defined __FreeBSD__ ) && (defined __i386__) ) // rb010123
+#if !id386
+
+void S_WriteLinearBlastStereo16 (void)
+{
+ int i;
+ int val;
+
+ for (i=0 ; i<snd_linear_count ; i+=2)
+ {
+ val = snd_p[i]>>8;
+ if (val > 0x7fff)
+ snd_out[i] = 0x7fff;
+ else if (val < -32768)
+ snd_out[i] = -32768;
+ else
+ snd_out[i] = val;
+
+ val = snd_p[i+1]>>8;
+ if (val > 0x7fff)
+ snd_out[i+1] = 0x7fff;
+ else if (val < -32768)
+ snd_out[i+1] = -32768;
+ else
+ snd_out[i+1] = val;
+ }
+}
+#else
+
+__declspec( naked ) void S_WriteLinearBlastStereo16 (void)
+{
+ __asm {
+
+ push edi
+ push ebx
+ mov ecx,ds:dword ptr[snd_linear_count]
+ mov ebx,ds:dword ptr[snd_p]
+ mov edi,ds:dword ptr[snd_out]
+LWLBLoopTop:
+ mov eax,ds:dword ptr[-8+ebx+ecx*4]
+ sar eax,8
+ cmp eax,07FFFh
+ jg LClampHigh
+ cmp eax,0FFFF8000h
+ jnl LClampDone
+ mov eax,0FFFF8000h
+ jmp LClampDone
+LClampHigh:
+ mov eax,07FFFh
+LClampDone:
+ mov edx,ds:dword ptr[-4+ebx+ecx*4]
+ sar edx,8
+ cmp edx,07FFFh
+ jg LClampHigh2
+ cmp edx,0FFFF8000h
+ jnl LClampDone2
+ mov edx,0FFFF8000h
+ jmp LClampDone2
+LClampHigh2:
+ mov edx,07FFFh
+LClampDone2:
+ shl edx,16
+ and eax,0FFFFh
+ or edx,eax
+ mov ds:dword ptr[-4+edi+ecx*2],edx
+ sub ecx,2
+ jnz LWLBLoopTop
+ pop ebx
+ pop edi
+ ret
+ }
+}
+
+#endif
+#else
+// forward declare, implementation somewhere else
+void S_WriteLinearBlastStereo16 (void);
+#endif
+
+void S_TransferStereo16 (unsigned long *pbuf, int endtime)
+{
+ int lpos;
+ int ls_paintedtime;
+
+ snd_p = (int *) paintbuffer;
+ ls_paintedtime = s_paintedtime;
+
+ while (ls_paintedtime < endtime)
+ {
+ // handle recirculating buffer issues
+ lpos = ls_paintedtime & ((dma.samples>>1)-1);
+
+ snd_out = (short *) pbuf + (lpos<<1);
+
+ snd_linear_count = (dma.samples>>1) - lpos;
+ if (ls_paintedtime + snd_linear_count > endtime)
+ snd_linear_count = endtime - ls_paintedtime;
+
+ snd_linear_count <<= 1;
+
+ // write a linear blast of samples
+ S_WriteLinearBlastStereo16 ();
+
+ snd_p += snd_linear_count;
+ ls_paintedtime += (snd_linear_count>>1);
+ }
+}
+
+/*
+===================
+S_TransferPaintBuffer
+
+===================
+*/
+void S_TransferPaintBuffer(int endtime)
+{
+ int out_idx;
+ int count;
+ int out_mask;
+ int *p;
+ int step;
+ int val;
+ unsigned long *pbuf;
+
+ pbuf = (unsigned long *)dma.buffer;
+
+
+ if ( s_testsound->integer ) {
+ int i;
+ int count;
+
+ // write a fixed sine wave
+ count = (endtime - s_paintedtime);
+ for (i=0 ; i<count ; i++)
+ paintbuffer[i].left = paintbuffer[i].right = sin((s_paintedtime+i)*0.1)*20000*256;
+ }
+
+
+ if (dma.samplebits == 16 && dma.channels == 2)
+ { // optimized case
+ S_TransferStereo16 (pbuf, endtime);
+ }
+ else
+ { // general case
+ p = (int *) paintbuffer;
+ count = (endtime - s_paintedtime) * dma.channels;
+ out_mask = dma.samples - 1;
+ out_idx = s_paintedtime * dma.channels & out_mask;
+ step = 3 - dma.channels;
+
+ if (dma.samplebits == 16)
+ {
+ short *out = (short *) pbuf;
+ while (count--)
+ {
+ val = *p >> 8;
+ p+= step;
+ if (val > 0x7fff)
+ val = 0x7fff;
+ else if (val < -32768)
+ val = -32768;
+ out[out_idx] = val;
+ out_idx = (out_idx + 1) & out_mask;
+ }
+ }
+ else if (dma.samplebits == 8)
+ {
+ unsigned char *out = (unsigned char *) pbuf;
+ while (count--)
+ {
+ val = *p >> 8;
+ p+= step;
+ if (val > 0x7fff)
+ val = 0x7fff;
+ else if (val < -32768)
+ val = -32768;
+ out[out_idx] = (val>>8) + 128;
+ out_idx = (out_idx + 1) & out_mask;
+ }
+ }
+ }
+}
+
+
+/*
+===============================================================================
+
+CHANNEL MIXING
+
+===============================================================================
+*/
+
+static void S_PaintChannelFrom16( channel_t *ch, const sfx_t *sc, int count, int sampleOffset, int bufferOffset ) {
+ int data, aoff, boff;
+ int leftvol, rightvol;
+ int i, j;
+ portable_samplepair_t *samp;
+ sndBuffer *chunk;
+ short *samples;
+ float ooff, fdata, fdiv, fleftvol, frightvol;
+
+ samp = &paintbuffer[ bufferOffset ];
+
+ if (ch->doppler) {
+ sampleOffset = sampleOffset*ch->oldDopplerScale;
+ }
+
+ chunk = sc->soundData;
+ while (sampleOffset>=SND_CHUNK_SIZE) {
+ chunk = chunk->next;
+ sampleOffset -= SND_CHUNK_SIZE;
+ if (!chunk) {
+ chunk = sc->soundData;
+ }
+ }
+
+ if (!ch->doppler || ch->dopplerScale==1.0f) {
+#if idppc_altivec
+ vector signed short volume_vec;
+ vector unsigned int volume_shift;
+ int vectorCount, samplesLeft, chunkSamplesLeft;
+#endif
+ leftvol = ch->leftvol*snd_vol;
+ rightvol = ch->rightvol*snd_vol;
+ samples = chunk->sndChunk;
+#if idppc_altivec
+ ((short *)&volume_vec)[0] = leftvol;
+ ((short *)&volume_vec)[1] = leftvol;
+ ((short *)&volume_vec)[4] = leftvol;
+ ((short *)&volume_vec)[5] = leftvol;
+ ((short *)&volume_vec)[2] = rightvol;
+ ((short *)&volume_vec)[3] = rightvol;
+ ((short *)&volume_vec)[6] = rightvol;
+ ((short *)&volume_vec)[7] = rightvol;
+ volume_shift = vec_splat_u32(8);
+ i = 0;
+
+ while(i < count) {
+ /* Try to align destination to 16-byte boundary */
+ while(i < count && (((unsigned long)&samp[i] & 0x1f) || ((count-i) < 8) || ((SND_CHUNK_SIZE - sampleOffset) < 8))) {
+ data = samples[sampleOffset++];
+ samp[i].left += (data * leftvol)>>8;
+ samp[i].right += (data * rightvol)>>8;
+
+ if (sampleOffset == SND_CHUNK_SIZE) {
+ chunk = chunk->next;
+ samples = chunk->sndChunk;
+ sampleOffset = 0;
+ }
+ i++;
+ }
+ /* Destination is now aligned. Process as many 8-sample
+ chunks as we can before we run out of room from the current
+ sound chunk. We do 8 per loop to avoid extra source data reads. */
+ samplesLeft = count - i;
+ chunkSamplesLeft = SND_CHUNK_SIZE - sampleOffset;
+ if(samplesLeft > chunkSamplesLeft)
+ samplesLeft = chunkSamplesLeft;
+
+ vectorCount = samplesLeft / 8;
+
+ if(vectorCount)
+ {
+ vector unsigned char tmp;
+ vector short s0, s1, sampleData0, sampleData1;
+ vector short samples0, samples1;
+ vector signed int left0, right0;
+ vector signed int merge0, merge1;
+ vector signed int d0, d1, d2, d3;
+ vector unsigned char samplePermute0 =
+ (vector unsigned char)(0, 1, 4, 5, 0, 1, 4, 5, 2, 3, 6, 7, 2, 3, 6, 7);
+ vector unsigned char samplePermute1 =
+ (vector unsigned char)(8, 9, 12, 13, 8, 9, 12, 13, 10, 11, 14, 15, 10, 11, 14, 15);
+ vector unsigned char loadPermute0, loadPermute1;
+
+ // Rather than permute the vectors after we load them to do the sample
+ // replication and rearrangement, we permute the alignment vector so
+ // we do everything in one step below and avoid data shuffling.
+ tmp = vec_lvsl(0,&samples[sampleOffset]);
+ loadPermute0 = vec_perm(tmp,tmp,samplePermute0);
+ loadPermute1 = vec_perm(tmp,tmp,samplePermute1);
+
+ s0 = *(vector short *)&samples[sampleOffset];
+ while(vectorCount)
+ {
+ /* Load up source (16-bit) sample data */
+ s1 = *(vector short *)&samples[sampleOffset+7];
+
+ /* Load up destination sample data */
+ d0 = *(vector signed int *)&samp[i];
+ d1 = *(vector signed int *)&samp[i+2];
+ d2 = *(vector signed int *)&samp[i+4];
+ d3 = *(vector signed int *)&samp[i+6];
+
+ sampleData0 = vec_perm(s0,s1,loadPermute0);
+ sampleData1 = vec_perm(s0,s1,loadPermute1);
+
+ merge0 = vec_mule(sampleData0,volume_vec);
+ merge0 = vec_sra(merge0,volume_shift); /* Shift down to proper range */
+
+ merge1 = vec_mulo(sampleData0,volume_vec);
+ merge1 = vec_sra(merge1,volume_shift);
+
+ d0 = vec_add(merge0,d0);
+ d1 = vec_add(merge1,d1);
+
+ merge0 = vec_mule(sampleData1,volume_vec);
+ merge0 = vec_sra(merge0,volume_shift); /* Shift down to proper range */
+
+ merge1 = vec_mulo(sampleData1,volume_vec);
+ merge1 = vec_sra(merge1,volume_shift);
+
+ d2 = vec_add(merge0,d2);
+ d3 = vec_add(merge1,d3);
+
+ /* Store destination sample data */
+ *(vector signed int *)&samp[i] = d0;
+ *(vector signed int *)&samp[i+2] = d1;
+ *(vector signed int *)&samp[i+4] = d2;
+ *(vector signed int *)&samp[i+6] = d3;
+
+ i += 8;
+ vectorCount--;
+ s0 = s1;
+ sampleOffset += 8;
+ }
+ if (sampleOffset == SND_CHUNK_SIZE) {
+ chunk = chunk->next;
+ samples = chunk->sndChunk;
+ sampleOffset = 0;
+ }
+ }
+ }
+#else
+ for ( i=0 ; i<count ; i++ ) {
+ data = samples[sampleOffset++];
+ samp[i].left += (data * leftvol)>>8;
+ samp[i].right += (data * rightvol)>>8;
+
+ if (sampleOffset == SND_CHUNK_SIZE) {
+ chunk = chunk->next;
+ samples = chunk->sndChunk;
+ sampleOffset = 0;
+ }
+ }
+#endif
+ } else {
+ fleftvol = ch->leftvol*snd_vol;
+ frightvol = ch->rightvol*snd_vol;
+
+ ooff = sampleOffset;
+ samples = chunk->sndChunk;
+
+
+
+
+ for ( i=0 ; i<count ; i++ ) {
+
+ aoff = ooff;
+ ooff = ooff + ch->dopplerScale;
+ boff = ooff;
+ fdata = 0;
+ for (j=aoff; j<boff; j++) {
+ if (j == SND_CHUNK_SIZE) {
+ chunk = chunk->next;
+ if (!chunk) {
+ chunk = sc->soundData;
+ }
+ samples = chunk->sndChunk;
+ ooff -= SND_CHUNK_SIZE;
+ }
+ fdata += samples[j&(SND_CHUNK_SIZE-1)];
+ }
+ fdiv = 256 * (boff-aoff);
+ samp[i].left += (fdata * fleftvol)/fdiv;
+ samp[i].right += (fdata * frightvol)/fdiv;
+ }
+ }
+}
+
+void S_PaintChannelFromWavelet( channel_t *ch, sfx_t *sc, int count, int sampleOffset, int bufferOffset ) {
+ int data;
+ int leftvol, rightvol;
+ int i;
+ portable_samplepair_t *samp;
+ sndBuffer *chunk;
+ short *samples;
+
+ leftvol = ch->leftvol*snd_vol;
+ rightvol = ch->rightvol*snd_vol;
+
+ i = 0;
+ samp = &paintbuffer[ bufferOffset ];
+ chunk = sc->soundData;
+ while (sampleOffset>=(SND_CHUNK_SIZE_FLOAT*4)) {
+ chunk = chunk->next;
+ sampleOffset -= (SND_CHUNK_SIZE_FLOAT*4);
+ i++;
+ }
+
+ if (i!=sfxScratchIndex || sfxScratchPointer != sc) {
+ S_AdpcmGetSamples( chunk, sfxScratchBuffer );
+ sfxScratchIndex = i;
+ sfxScratchPointer = sc;
+ }
+
+ samples = sfxScratchBuffer;
+
+ for ( i=0 ; i<count ; i++ ) {
+ data = samples[sampleOffset++];
+ samp[i].left += (data * leftvol)>>8;
+ samp[i].right += (data * rightvol)>>8;
+
+ if (sampleOffset == SND_CHUNK_SIZE*2) {
+ chunk = chunk->next;
+ decodeWavelet(chunk, sfxScratchBuffer);
+ sfxScratchIndex++;
+ sampleOffset = 0;
+ }
+ }
+}
+
+void S_PaintChannelFromADPCM( channel_t *ch, sfx_t *sc, int count, int sampleOffset, int bufferOffset ) {
+ int data;
+ int leftvol, rightvol;
+ int i;
+ portable_samplepair_t *samp;
+ sndBuffer *chunk;
+ short *samples;
+
+ leftvol = ch->leftvol*snd_vol;
+ rightvol = ch->rightvol*snd_vol;
+
+ i = 0;
+ samp = &paintbuffer[ bufferOffset ];
+ chunk = sc->soundData;
+
+ if (ch->doppler) {
+ sampleOffset = sampleOffset*ch->oldDopplerScale;
+ }
+
+ while (sampleOffset>=(SND_CHUNK_SIZE*4)) {
+ chunk = chunk->next;
+ sampleOffset -= (SND_CHUNK_SIZE*4);
+ i++;
+ }
+
+ if (i!=sfxScratchIndex || sfxScratchPointer != sc) {
+ S_AdpcmGetSamples( chunk, sfxScratchBuffer );
+ sfxScratchIndex = i;
+ sfxScratchPointer = sc;
+ }
+
+ samples = sfxScratchBuffer;
+
+ for ( i=0 ; i<count ; i++ ) {
+ data = samples[sampleOffset++];
+ samp[i].left += (data * leftvol)>>8;
+ samp[i].right += (data * rightvol)>>8;
+
+ if (sampleOffset == SND_CHUNK_SIZE*4) {
+ chunk = chunk->next;
+ S_AdpcmGetSamples( chunk, sfxScratchBuffer);
+ sampleOffset = 0;
+ sfxScratchIndex++;
+ }
+ }
+}
+
+void S_PaintChannelFromMuLaw( channel_t *ch, sfx_t *sc, int count, int sampleOffset, int bufferOffset ) {
+ int data;
+ int leftvol, rightvol;
+ int i;
+ portable_samplepair_t *samp;
+ sndBuffer *chunk;
+ byte *samples;
+ float ooff;
+
+ leftvol = ch->leftvol*snd_vol;
+ rightvol = ch->rightvol*snd_vol;
+
+ samp = &paintbuffer[ bufferOffset ];
+ chunk = sc->soundData;
+ while (sampleOffset>=(SND_CHUNK_SIZE*2)) {
+ chunk = chunk->next;
+ sampleOffset -= (SND_CHUNK_SIZE*2);
+ if (!chunk) {
+ chunk = sc->soundData;
+ }
+ }
+
+ if (!ch->doppler) {
+ samples = (byte *)chunk->sndChunk + sampleOffset;
+ for ( i=0 ; i<count ; i++ ) {
+ data = mulawToShort[*samples];
+ samp[i].left += (data * leftvol)>>8;
+ samp[i].right += (data * rightvol)>>8;
+ samples++;
+ if (samples == (byte *)chunk->sndChunk+(SND_CHUNK_SIZE*2)) {
+ chunk = chunk->next;
+ samples = (byte *)chunk->sndChunk;
+ }
+ }
+ } else {
+ ooff = sampleOffset;
+ samples = (byte *)chunk->sndChunk;
+ for ( i=0 ; i<count ; i++ ) {
+ data = mulawToShort[samples[(int)(ooff)]];
+ ooff = ooff + ch->dopplerScale;
+ samp[i].left += (data * leftvol)>>8;
+ samp[i].right += (data * rightvol)>>8;
+ if (ooff >= SND_CHUNK_SIZE*2) {
+ chunk = chunk->next;
+ if (!chunk) {
+ chunk = sc->soundData;
+ }
+ samples = (byte *)chunk->sndChunk;
+ ooff = 0.0;
+ }
+ }
+ }
+}
+
+/*
+===================
+S_PaintChannels
+===================
+*/
+void S_PaintChannels( int endtime ) {
+ int i;
+ int end;
+ channel_t *ch;
+ sfx_t *sc;
+ int ltime, count;
+ int sampleOffset;
+
+
+ snd_vol = s_volume->value*255;
+
+//Com_Printf ("%i to %i\n", s_paintedtime, endtime);
+ while ( s_paintedtime < endtime ) {
+ // if paintbuffer is smaller than DMA buffer
+ // we may need to fill it multiple times
+ end = endtime;
+ if ( endtime - s_paintedtime > PAINTBUFFER_SIZE ) {
+ end = s_paintedtime + PAINTBUFFER_SIZE;
+ }
+
+ // clear the paint buffer to either music or zeros
+ if ( s_rawend < s_paintedtime ) {
+ if ( s_rawend ) {
+ //Com_DPrintf ("background sound underrun\n");
+ }
+ Com_Memset(paintbuffer, 0, (end - s_paintedtime) * sizeof(portable_samplepair_t));
+ } else {
+ // copy from the streaming sound source
+ int s;
+ int stop;
+
+ stop = (end < s_rawend) ? end : s_rawend;
+
+ for ( i = s_paintedtime ; i < stop ; i++ ) {
+ s = i&(MAX_RAW_SAMPLES-1);
+ paintbuffer[i-s_paintedtime] = s_rawsamples[s];
+ }
+// if (i != end)
+// Com_Printf ("partial stream\n");
+// else
+// Com_Printf ("full stream\n");
+ for ( ; i < end ; i++ ) {
+ paintbuffer[i-s_paintedtime].left =
+ paintbuffer[i-s_paintedtime].right = 0;
+ }
+ }
+
+ // paint in the channels.
+ ch = s_channels;
+ for ( i = 0; i < MAX_CHANNELS ; i++, ch++ ) {
+ if ( !ch->thesfx || (ch->leftvol<0.25 && ch->rightvol<0.25 )) {
+ continue;
+ }
+
+ ltime = s_paintedtime;
+ sc = ch->thesfx;
+
+ sampleOffset = ltime - ch->startSample;
+ count = end - ltime;
+ if ( sampleOffset + count > sc->soundLength ) {
+ count = sc->soundLength - sampleOffset;
+ }
+
+ if ( count > 0 ) {
+ if( sc->soundCompressionMethod == 1) {
+ S_PaintChannelFromADPCM (ch, sc, count, sampleOffset, ltime - s_paintedtime);
+ } else if( sc->soundCompressionMethod == 2) {
+ S_PaintChannelFromWavelet (ch, sc, count, sampleOffset, ltime - s_paintedtime);
+ } else if( sc->soundCompressionMethod == 3) {
+ S_PaintChannelFromMuLaw (ch, sc, count, sampleOffset, ltime - s_paintedtime);
+ } else {
+ S_PaintChannelFrom16 (ch, sc, count, sampleOffset, ltime - s_paintedtime);
+ }
+ }
+ }
+
+ // paint in the looped channels.
+ ch = loop_channels;
+ for ( i = 0; i < numLoopChannels ; i++, ch++ ) {
+ if ( !ch->thesfx || (!ch->leftvol && !ch->rightvol )) {
+ continue;
+ }
+
+ ltime = s_paintedtime;
+ sc = ch->thesfx;
+
+ if (sc->soundData==NULL || sc->soundLength==0) {
+ continue;
+ }
+ // we might have to make two passes if it
+ // is a looping sound effect and the end of
+ // the sample is hit
+ do {
+ sampleOffset = (ltime % sc->soundLength);
+
+ count = end - ltime;
+ if ( sampleOffset + count > sc->soundLength ) {
+ count = sc->soundLength - sampleOffset;
+ }
+
+ if ( count > 0 ) {
+ if( sc->soundCompressionMethod == 1) {
+ S_PaintChannelFromADPCM (ch, sc, count, sampleOffset, ltime - s_paintedtime);
+ } else if( sc->soundCompressionMethod == 2) {
+ S_PaintChannelFromWavelet (ch, sc, count, sampleOffset, ltime - s_paintedtime);
+ } else if( sc->soundCompressionMethod == 3) {
+ S_PaintChannelFromMuLaw (ch, sc, count, sampleOffset, ltime - s_paintedtime);
+ } else {
+ S_PaintChannelFrom16 (ch, sc, count, sampleOffset, ltime - s_paintedtime);
+ }
+ ltime += count;
+ }
+ } while ( ltime < end);
+ }
+
+ // transfer out according to DMA format
+ S_TransferPaintBuffer( end );
+ s_paintedtime = end;
+ }
+}