/* * SND_MIX.java * Copyright (C) 2004 * * $Id: SND_MIX.java,v 1.2 2004-07-08 20:24:29 hzi Exp $ */ /* Copyright (C) 1997-2001 Id Software, Inc. This program 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. This program 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 this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ package jake2.client; import jake2.game.cvar_t; import jake2.util.Math3D; /** * SND_MIX */ public class SND_MIX extends SND_MEM { static final int MAX_CHANNELS = 32; static class playsound_t { playsound_t prev, next; sfx_t sfx; float volume; float attenuation; int entnum; int entchannel; boolean fixed_origin; // use origin field instead of entnum's origin float[] origin = { 0, 0, 0 }; long begin; // begin on this sample public void clear() { prev = next = null; sfx = null; volume = attenuation = begin = entnum = entchannel = 0; fixed_origin = false; Math3D.VectorClear(origin); } }; static class channel_t { sfx_t sfx; // sfx number int leftvol; // 0-255 volume int rightvol; // 0-255 volume int end; // end time in global paintsamples int pos; // sample position in sfx int looping; // where to loop, -1 = no looping OBSOLETE? int entnum; // to allow overriding a specific sound int entchannel; // float[] origin = { 0, 0, 0 }; // only use if fixed_origin is set float[] dist_mult = { 0, 0, 0 }; // distance multiplier (attenuation/clipK) int master_vol; // 0-255 master volume boolean fixed_origin; // use origin instead of fetching entnum's origin boolean autosound; // from an entity->sound, cleared each frame void clear() { sfx = null; leftvol = rightvol = end = pos = looping = entnum = entchannel = master_vol = 0; Math3D.VectorClear(origin); Math3D.VectorClear(dist_mult); fixed_origin = autosound = false; } }; static cvar_t s_volume; static int s_rawend; //// snd_mix.c -- portable code to mix sounds for snd_dma.c // // #include "client.h" // #include "snd_loc.h" // // #define PAINTBUFFER_SIZE 2048 // portable_samplepair_t paintbuffer[PAINTBUFFER_SIZE]; static int[][] snd_scaletable = new int[32][256]; // int *snd_p, snd_linear_count, snd_vol; // short *snd_out; // // void S_WriteLinearBlastStereo16 (void); // // #if !(defined __linux__ && defined __i386__) // #if !id386 // // void S_WriteLinearBlastStereo16 (void) // { // int i; // int val; // // for (i=0 ; i>8; // if (val > 0x7fff) // snd_out[i] = 0x7fff; // else if (val < (short)0x8000) // snd_out[i] = (short)0x8000; // else // snd_out[i] = val; // // val = snd_p[i+1]>>8; // if (val > 0x7fff) // snd_out[i+1] = 0x7fff; // else if (val < (short)0x8000) // snd_out[i+1] = (short)0x8000; // 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 // #endif // // void S_TransferStereo16 (unsigned long *pbuf, int endtime) // { // int lpos; // int lpaintedtime; // // snd_p = (int *) paintbuffer; // lpaintedtime = paintedtime; // // while (lpaintedtime < endtime) // { // // handle recirculating buffer issues // lpos = lpaintedtime & ((dma.samples>>1)-1); // // snd_out = (short *) pbuf + (lpos<<1); // // snd_linear_count = (dma.samples>>1) - lpos; // if (lpaintedtime + snd_linear_count > endtime) // snd_linear_count = endtime - lpaintedtime; // // snd_linear_count <<= 1; // // // write a linear blast of samples // S_WriteLinearBlastStereo16 (); // // snd_p += snd_linear_count; // lpaintedtime += (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->value) // { // int i; // int count; // // // write a fixed sine wave // count = (endtime - paintedtime); // for (i=0 ; i> 8; // p+= step; // if (val > 0x7fff) // val = 0x7fff; // else if (val < (short)0x8000) // val = (short)0x8000; // 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 < (short)0x8000) // val = (short)0x8000; // out[out_idx] = (val>>8) + 128; // out_idx = (out_idx + 1) & out_mask; // } // } // } // } // // // /* // =============================================================================== // // CHANNEL MIXING // // =============================================================================== // */ // // void S_PaintChannelFrom8 (channel_t *ch, sfxcache_t *sc, int endtime, int offset); // void S_PaintChannelFrom16 (channel_t *ch, sfxcache_t *sc, int endtime, int offset); // // void S_PaintChannels(int endtime) // { // int i; // int end; // channel_t *ch; // sfxcache_t *sc; // int ltime, count; // playsound_t *ps; // // snd_vol = s_volume->value*256; // //// Com_Printf ("%i to %i\n", paintedtime, endtime); // while (paintedtime < endtime) // { // // if paintbuffer is smaller than DMA buffer // end = endtime; // if (endtime - paintedtime > PAINTBUFFER_SIZE) // end = paintedtime + PAINTBUFFER_SIZE; // // // start any playsounds // while (1) // { // ps = s_pendingplays.next; // if (ps == &s_pendingplays) // break; // no more pending sounds // if (ps->begin <= paintedtime) // { // S_IssuePlaysound (ps); // continue; // } // // if (ps->begin < end) // end = ps->begin; // stop here // break; // } // // // clear the paint buffer // if (s_rawend < paintedtime) // { //// Com_Printf ("clear\n"); // memset(paintbuffer, 0, (end - 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=paintedtime ; isfx || (!ch->leftvol && !ch->rightvol) ) // break; // // // max painting is to the end of the buffer // count = end - ltime; // // // might be stopped by running out of data // if (ch->end - ltime < count) // count = ch->end - ltime; // // sc = S_LoadSound (ch->sfx); // if (!sc) // break; // // if (count > 0 && ch->sfx) // { // if (sc->width == 1)// FIXME; 8 bit asm is wrong now // S_PaintChannelFrom8(ch, sc, count, ltime - paintedtime); // else // S_PaintChannelFrom16(ch, sc, count, ltime - paintedtime); // // ltime += count; // } // // // if at end of loop, restart // if (ltime >= ch->end) // { // if (ch->autosound) // { // autolooping sounds always go back to start // ch->pos = 0; // ch->end = ltime + sc->length; // } // else if (sc->loopstart >= 0) // { // ch->pos = sc->loopstart; // ch->end = ltime + sc->length - ch->pos; // } // else // { // channel just stopped // ch->sfx = NULL; // } // } // } // // } // // // transfer out according to DMA format // S_TransferPaintBuffer(end); // paintedtime = end; // } // } // static void InitScaletable () { int i, j; int scale; s_volume.modified = false; for (i=0 ; i<32 ; i++) { scale = (int)(i * 8 * 256 * s_volume.value); for (j=0 ; j<256 ; j++) snd_scaletable[i][j] = ((byte)j) * scale; } } // // // #if !(defined __linux__ && defined __i386__) // #if !id386 // // void S_PaintChannelFrom8 (channel_t *ch, sfxcache_t *sc, int count, int offset) // { // int data; // int *lscale, *rscale; // unsigned char *sfx; // int i; // portable_samplepair_t *samp; // // if (ch->leftvol > 255) // ch->leftvol = 255; // if (ch->rightvol > 255) // ch->rightvol = 255; // // //ZOID-- >>11 has been changed to >>3, >>11 didn't make much sense // //as it would always be zero. // lscale = snd_scaletable[ ch->leftvol >> 3]; // rscale = snd_scaletable[ ch->rightvol >> 3]; // sfx = (signed char *)sc->data + ch->pos; // // samp = &paintbuffer[offset]; // // for (i=0 ; ileft += lscale[data]; // samp->right += rscale[data]; // } // // ch->pos += count; // } // // #else // // __declspec( naked ) void S_PaintChannelFrom8 (channel_t *ch, sfxcache_t *sc, int count, int offset) // { // __asm { // push esi // push edi // push ebx // push ebp // mov ebx,ds:dword ptr[4+16+esp] // mov esi,ds:dword ptr[8+16+esp] // mov eax,ds:dword ptr[4+ebx] // mov edx,ds:dword ptr[8+ebx] // cmp eax,255 // jna LLeftSet // mov eax,255 // LLeftSet: // cmp edx,255 // jna LRightSet // mov edx,255 // LRightSet: // and eax,0F8h // add esi,20 // and edx,0F8h // mov edi,ds:dword ptr[16+ebx] // mov ecx,ds:dword ptr[12+16+esp] // add esi,edi // shl eax,7 // add edi,ecx // shl edx,7 // mov ds:dword ptr[16+ebx],edi // add eax,offset snd_scaletable // add edx,offset snd_scaletable // sub ebx,ebx // mov bl,ds:byte ptr[-1+esi+ecx*1] // test ecx,1 // jz LMix8Loop // mov edi,ds:dword ptr[eax+ebx*4] // mov ebp,ds:dword ptr[edx+ebx*4] // add edi,ds:dword ptr[paintbuffer+0-8+ecx*8] // add ebp,ds:dword ptr[paintbuffer+4-8+ecx*8] // mov ds:dword ptr[paintbuffer+0-8+ecx*8],edi // mov ds:dword ptr[paintbuffer+4-8+ecx*8],ebp // mov bl,ds:byte ptr[-2+esi+ecx*1] // dec ecx // jz LDone // LMix8Loop: // mov edi,ds:dword ptr[eax+ebx*4] // mov ebp,ds:dword ptr[edx+ebx*4] // add edi,ds:dword ptr[paintbuffer+0-8+ecx*8] // add ebp,ds:dword ptr[paintbuffer+4-8+ecx*8] // mov bl,ds:byte ptr[-2+esi+ecx*1] // mov ds:dword ptr[paintbuffer+0-8+ecx*8],edi // mov ds:dword ptr[paintbuffer+4-8+ecx*8],ebp // mov edi,ds:dword ptr[eax+ebx*4] // mov ebp,ds:dword ptr[edx+ebx*4] // mov bl,ds:byte ptr[-3+esi+ecx*1] // add edi,ds:dword ptr[paintbuffer+0-8*2+ecx*8] // add ebp,ds:dword ptr[paintbuffer+4-8*2+ecx*8] // mov ds:dword ptr[paintbuffer+0-8*2+ecx*8],edi // mov ds:dword ptr[paintbuffer+4-8*2+ecx*8],ebp // sub ecx,2 // jnz LMix8Loop // LDone: // pop ebp // pop ebx // pop edi // pop esi // ret // } // } // // #endif // #endif // // void S_PaintChannelFrom16 (channel_t *ch, sfxcache_t *sc, int count, int offset) // { // int data; // int left, right; // int leftvol, rightvol; // signed short *sfx; // int i; // portable_samplepair_t *samp; // // leftvol = ch->leftvol*snd_vol; // rightvol = ch->rightvol*snd_vol; // sfx = (signed short *)sc->data + ch->pos; // // samp = &paintbuffer[offset]; // for (i=0 ; i>8; // right = (data * rightvol)>>8; // samp->left += left; // samp->right += right; // } // // ch->pos += count; // } // // }