/* snd_mixa.S x86 assembly-language sound code Copyright (C) 1996-1997 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: Free Software Foundation, Inc. 59 Temple Place - Suite 330 Boston, MA 02111-1307, USA $Id$ */ #ifdef HAVE_CONFIG_H # include <config.h> #endif #include "asm_i386.h" // #include "quakeasm.h" #ifdef USE_INTEL_ASM #ifdef WIN32 # undef PIC //no such thing in win32 #endif .text .extern C(snd_scaletable) .extern C(paintbuffer) .extern C(snd_linear_count) .extern C(snd_p) .extern C(snd_vol) .extern C(snd_out) //---------------------------------------------------------------------- // 8-bit sound-mixing code //---------------------------------------------------------------------- #define ch 4+16 #define sc 8+16 #define count 12+16 .globl C(NOT_SND_PaintChannelFrom8) #ifdef PIC .type C(NOT_SND_PaintChannelFrom8),@function #endif C(NOT_SND_PaintChannelFrom8): pushl %esi // preserve register variables pushl %edi pushl %ebx pushl %ebp // int data; // short *lscale, *rscale; // unsigned char *sfx; // int i; movl ch(%esp),%ebx movl sc(%esp),%esi // if (ch->leftvol > 255) // ch->leftvol = 255; // if (ch->rightvol > 255) // ch->rightvol = 255; movl ch_leftvol(%ebx),%eax movl ch_rightvol(%ebx),%edx cmpl $255,%eax jna LLeftSet movl $255,%eax LLeftSet: cmpl $255,%edx jna LRightSet movl $255,%edx LRightSet: // lscale = snd_scaletable[ch->leftvol >> 3]; // rscale = snd_scaletable[ch->rightvol >> 3]; // sfx = (signed char *)sc->data + ch->pos; // ch->pos += count; andl $0xF8,%eax addl $(sfxc_data),%esi andl $0xF8,%edx movl ch_pos(%ebx),%edi movl count(%esp),%ecx addl %edi,%esi shll $7,%eax addl %ecx,%edi addl %ecx,%esi shll $7,%edx movl %edi,ch_pos(%ebx) #ifdef PIC call .Lpic1 .Lpic1: popl %ebx addl $C(_GLOBAL_OFFSET_TABLE_)+[.-.Lpic1],%ebx movl C(snd_scaletable)@GOT(%ebx,%eax),%eax movl C(snd_scaletable)@GOT(%ebx,%edx),%edx movl C(paintbuffer)@GOT(%ebx),%ebx #else leal C(snd_scaletable)(%eax),%eax leal C(snd_scaletable)(%edx),%edx leal C(paintbuffer),%ebx #endif pushl %ebx // save paintbuffer offset testl $1,%ecx leal 0(%ebx,%ecx,psp_size),%ecx movl $0,%ebx movb -1(%esi),%bl jz LMix8Loop movl (%eax,%ebx,4),%edi movl (%edx,%ebx,4),%ebp addl psp_left-psp_size(%ecx),%edi addl psp_right-psp_size(%ecx),%ebp movl %edi,psp_left-psp_size(%ecx) movl %ebp,psp_right-psp_size(%ecx) movb -2(%esi),%bl subl $psp_size,%ecx decl %esi cmpl (%esp),%ecx jz LDone // for (i=0 ; i<count ; i++) // { LMix8Loop: // data = sfx[i]; // paintbuffer[i].left += lscale[data]; // paintbuffer[i].right += rscale[data]; movl (%eax,%ebx,4),%edi movl (%edx,%ebx,4),%ebp addl psp_left-psp_size(%ecx),%edi addl psp_right-psp_size(%ecx),%ebp movb -2(%esi),%bl movl %edi,psp_left-psp_size(%ecx) movl %ebp,psp_right-psp_size(%ecx) movl (%eax,%ebx,4),%edi movl (%edx,%ebx,4),%ebp movb -3(%esi),%bl addl psp_left-psp_size*2(%ecx),%edi addl psp_right-psp_size*2(%ecx),%ebp movl %edi,psp_left-psp_size*2(%ecx) movl %ebp,psp_right-psp_size*2(%ecx) // } subl $2*psp_size,%ecx subl $2,%esi cmpl (%esp),%ecx jnz LMix8Loop LDone: addl $4,%esp // remove paintbuffer offset popl %ebp popl %ebx popl %edi popl %esi ret #ifdef PIC .Lfe1: .size C(NOT_SND_PaintChannelFrom8),.Lfe1-C(NOT_SND_PaintChannelFrom8) #endif //---------------------------------------------------------------------- // Transfer of stereo buffer to 16-bit DMA buffer code //---------------------------------------------------------------------- .globl C(SND_WriteLinearBlastStereo16) #ifdef PIC .type C(SND_WriteLinearBlastStereo16),@function #endif C(SND_WriteLinearBlastStereo16): pushl %esi // preserve register variables pushl %edi pushl %ebx #ifdef PIC call .Lpic2 .Lpic2: popl %ebx addl $C(_GLOBAL_OFFSET_TABLE_)+[.-.Lpic2],%ebx #endif // int i; // int val; #ifdef PIC movl C(snd_linear_count)@GOTOFF(%ebx),%ecx movl C(snd_vol)@GOTOFF(%ebx),%esi movl C(snd_out)@GOTOFF(%ebx),%edi movl C(snd_p)@GOTOFF(%ebx),%ebx #else movl C(snd_linear_count),%ecx movl C(snd_vol),%esi movl C(snd_out),%edi movl C(snd_p),%ebx #endif // for (i=0 ; i<snd_linear_count ; i+=2) // { LWLBLoopTop: // val = (snd_p[i]*snd_vol)>>8; // if (val > 0x7fff) // snd_out[i] = 0x7fff; // else if (val < (short)0x8000) // snd_out[i] = (short)0x8000; // else // snd_out[i] = val; movl -8(%ebx,%ecx,4),%eax imull %esi,%eax sarl $8,%eax cmpl $0x7FFF,%eax jg LClampHigh cmpl $0xFFFF8000,%eax jnl LClampDone movl $0xFFFF8000,%eax jmp LClampDone LClampHigh: movl $0x7FFF,%eax LClampDone: // val = (snd_p[i+1]*snd_vol)>>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; movl -4(%ebx,%ecx,4),%edx imull %esi,%edx sarl $8,%edx cmpl $0x7FFF,%edx jg LClampHigh2 cmpl $0xFFFF8000,%edx jnl LClampDone2 movl $0xFFFF8000,%edx jmp LClampDone2 LClampHigh2: movl $0x7FFF,%edx LClampDone2: shll $16,%edx andl $0xFFFF,%eax orl %eax,%edx movl %edx,-4(%edi,%ecx,2) // } subl $2,%ecx jnz LWLBLoopTop // snd_p += snd_linear_count; popl %ebx popl %edi popl %esi ret #ifdef PIC .Lfe2: .size C(SND_WriteLinearBlastStereo16),.Lfe2-C(SND_WriteLinearBlastStereo16) #endif #endif // USE_INTEL_ASM