123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682 |
- /*
- ===========================================================================
- 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;
- }
- }
|