Serious-Engine/Sources/Engine/Sound/SoundMixer386.asm
Ryan C. Gordon 24cb244d43 First attempt to hand-merge Ryan's Linux and Mac OS X port.
This was a _ton_ of changes, made 15 years ago, so there are probably some
problems to work out still.

Among others: Engine/Base/Stream.* was mostly abandoned and will need to be
re-ported.

Still, this is a pretty good start, and probably holds a world record for
lines of changes or something.  :)
2016-03-28 23:46:13 -04:00

373 lines
11 KiB
NASM

; /* Copyright (c) 2002-2012 Croteam Ltd. All rights reserved. */
;
; ------- YOU DO NOT NEED THIS FILE UNDER WIN32 AT THE MOMENT. -------
;
; Chances are, you will need NASM (http://www.octium.net/nasm/) to assemble
; this file.
;
; If we were smart, we'd move all the inline asm to similar files, which
; cleans up the C, and makes the assembly (ahem) more portable. NASM can
; generate Visual C compatible object files as well as Linux ELF and Intel
; Mac Mach-O binaries.
;
; --ryan.
; asm shortcuts
%define O offset
%define Q qword
%define D dword
%define W word
%define B byte
%define TRUE 1
%define FALSE 0
; ************************
; ** Start Data Block **
; ************************
SECTION .data
global slMixerBufferSize
global bEndOfSound
global bNotLoop
global fLeftOfs
global fLeftStep
global fOfsDelta
global fPhase
global fRightOfs
global fRightStep
global fSoundSampleRate
global fStep
global fixLeftOfs
global fixRightOfs
global mmSurroundFactor
global mmVolumeGain
global pswSrcBuffer
global pvMixerBuffer
global slLastLeftSample
global slLastRightSample
global slLeftFilter
global slLeftVolume
global slRightFilter
global slRightVolume
global slSoundBufferSize
slMixerBufferSize dd 0
pvMixerBuffer dd 0
pswSrcBuffer dd 0
slLeftVolume dd 0
slRightVolume dd 0
slLeftFilter dd 0
slRightFilter dd 0
slLastLeftSample dd 0
slLastRightSample dd 0
slSoundBufferSize dd 0
fSoundSampleRate dd 0
fPhase dd 0
fOfsDelta dd 0
fStep dd 0
fLeftStep dd 0
fRightStep dd 0
fLeftOfs dd 0
fRightOfs dd 0
fixLeftOfs dd 0, 0
fixRightOfs dd 0, 0
mmSurroundFactor dd 0, 0
mmLeftStep dd 0, 0
mmRightStep dd 0, 0
mmVolumeGain dd 0, 0
mmInvFactor dd 0x00007FFF, 0x00007FFF
bNotLoop dd 0
bEndOfSound dd 0
f65536 dd 65536.0
f4G dd 4294967296.0
; ************************
; ** End Data Block **
; ************************
; ************************
; ** Start Code Block **
; ************************
SEGMENT .text
global MixMono_asm
MixMono_asm:
push ebx ; Save GCC register.
; convert from floats to fixints 32:16
fld D [fLeftOfs]
fmul D [f65536]
fld D [fRightOfs]
fmul D [f65536]
fld D [fLeftStep]
fmul D [f65536]
fld D [fRightStep]
fmul D [f4G]
fistp Q [mmRightStep] ; fixint 32:32
fistp Q [mmLeftStep] ; fixint 32:16
fistp Q [fixRightOfs] ; fixint 32:16
fistp Q [fixLeftOfs] ; fixint 32:16
; get last played sample (for filtering purposes)
movzx eax,W [slLastRightSample]
movzx edx,W [slLastLeftSample]
shl eax,16
or eax,edx
movd mm6,eax ; MM6 = 0 | 0 || lastRightSample | lastLeftSample
; get volume
movd mm5,D [slRightVolume]
movd mm0,D [slLeftVolume]
psllq mm5,32
por mm5,mm0 ; MM5 = rightVolume || leftVolume
; get filter
mov eax,D [slRightFilter]
mov edx,D [slLeftFilter]
shl eax,16
or eax,edx
movd mm7,eax ; MM7 = 0 | 0 || rightFilter | leftFilter
; get offset of each channel inside sound and loop thru destination buffer
mov W [mmRightStep],0
movzx eax,W [fixLeftOfs]
movzx edx,W [fixRightOfs]
shl edx,16
or eax,edx ; EAX = right ofs frac | left ofs frac
mov ebx,D [fixLeftOfs+2] ; EBX = left ofs int
mov edx,D [fixRightOfs+2] ; EDX = right ofs int
mov esi,D [pswSrcBuffer] ; ESI = source sound buffer start ptr
mov edi,D [pvMixerBuffer] ; EDI = mixer buffer ptr
mov ecx,D [slMixerBufferSize] ; ECX = samples counter
sampleLoop_MixMono:
; check if source offsets came to the end of source sound buffer
cmp ebx,D [slSoundBufferSize]
jl lNotEnd_MixMono
sub ebx,D [slSoundBufferSize]
push D [bNotLoop]
pop D [bEndOfSound]
lNotEnd_MixMono:
; same for right channel
cmp edx,D [slSoundBufferSize]
jl rNotEnd_MixMono
sub edx,D [slSoundBufferSize]
push D [bNotLoop]
pop D [bEndOfSound]
rNotEnd_MixMono:
; check end of sample
cmp ecx,0
jle near loopEnd_MixMono
cmp D [bEndOfSound],TRUE
je near loopEnd_MixMono
; get sound samples
movd mm1,D [esi+ ebx*2] ; MM1 = 0 | 0 || nextLeftSample | leftSample
movd mm2,D [esi+ edx*2] ; MM2 = 0 | 0 || nextRightSample | RightSample
psllq mm2,32
por mm1,mm2 ; MM1 = nextRightSample | rightSample || nextLeftSample | leftSample
; calc linear interpolation factor (strength)
movd mm3,eax ; MM3 = 0 | 0 || right frac | left frac
punpcklwd mm3,mm3
psrlw mm3,1 ; MM3 = rightFrac | rightFrac || leftFrac | leftFrac
pxor mm3,Q [mmInvFactor] ; MM3 = rightFrac | 1-rightFrac || leftFrac | 1-leftFrac
; apply linear interpolation
pmaddwd mm1,mm3
psrad mm1,15
packssdw mm1,mm1 ; MM1 = ? | ? || linearRightSample | linearLeftSample
; apply filter
psubsw mm1,mm6
pmulhw mm1,mm7
psllw mm1,1
paddsw mm1,mm6
movq mm6,mm1
; apply volume adjustment
movq mm0,mm5
psrad mm0,16
packssdw mm0,mm0
pmulhw mm1,mm0
psllw mm1,1
pxor mm1,Q [mmSurroundFactor]
paddd mm5,Q [mmVolumeGain] ; modify volume
; unpack to 32bit and mix it into destination buffer
punpcklwd mm1,mm1
psrad mm1,16 ; MM1 = finalRightSample || finalLeftSample
paddd mm1,Q [edi]
movq Q [edi],mm1
; advance to next samples in source sound
add eax,D [mmRightStep+0]
adc edx,D [mmRightStep+4]
add ax,W [mmLeftStep +0]
adc ebx,D [mmLeftStep +2]
add edi,8
dec ecx
jmp sampleLoop_MixMono
loopEnd_MixMono:
; store modified asm local vars
mov D [fixLeftOfs +0],eax
shr eax,16
mov D [fixRightOfs+0],eax
mov D [fixLeftOfs +2],ebx
mov D [fixRightOfs+2],edx
movd eax,mm6
mov edx,eax
and eax,0x0000FFFF
shr edx,16
mov D [slLastLeftSample],eax
mov D [slLastRightSample],edx
pop ebx ; Restore GCC register.
emms
ret
global MixStereo_asm
MixStereo_asm:
push ebx ; Save GCC register.
; convert from floats to fixints 32:16
fld D [fLeftOfs]
fmul D [f65536]
fld D [fRightOfs]
fmul D [f65536]
fld D [fLeftStep]
fmul D [f65536]
fld D [fRightStep]
fmul D [f4G]
fistp Q [mmRightStep] ; fixint 32:32
fistp Q [mmLeftStep] ; fixint 32:16
fistp Q [fixRightOfs] ; fixint 32:16
fistp Q [fixLeftOfs] ; fixint 32:16
; get last played sample (for filtering purposes)
movzx eax,W [slLastRightSample]
movzx edx,W [slLastLeftSample]
shl eax,16
or eax,edx
movd mm6,eax ; MM6 = 0 | 0 || lastRightSample | lastLeftSample
; get volume
movd mm5,D [slRightVolume]
movd mm0,D [slLeftVolume]
psllq mm5,32
por mm5,mm0 ; MM5 = rightVolume || leftVolume
; get filter
mov eax,D [slRightFilter]
mov edx,D [slLeftFilter]
shl eax,16
or eax,edx
movd mm7,eax ; MM7 = 0 | 0 || rightFilter | leftFilter
; get offset of each channel inside sound and loop thru destination buffer
mov W [mmRightStep],0
movzx eax,W [fixLeftOfs]
movzx edx,W [fixRightOfs]
shl edx,16
or eax,edx ; EAX = right ofs frac | left ofs frac
mov ebx,D [fixLeftOfs+2] ; EBX = left ofs int
mov edx,D [fixRightOfs+2] ; EDX = right ofs int
mov esi,D [pswSrcBuffer] ; ESI = source sound buffer start ptr
mov edi,D [pvMixerBuffer] ; EDI = mixer buffer ptr
mov ecx,D [slMixerBufferSize] ; ECX = samples counter
sampleLoop_MixStereo:
; check if source offsets came to the end of source sound buffer
cmp ebx,D [slSoundBufferSize]
jl lNotEnd_MixStereo
sub ebx,D [slSoundBufferSize]
push D [bNotLoop]
pop D [bEndOfSound]
lNotEnd_MixStereo:
; same for right channel
cmp edx,D [slSoundBufferSize]
jl rNotEnd_MixStereo
sub edx,D [slSoundBufferSize]
push D [bNotLoop]
pop D [bEndOfSound]
rNotEnd_MixStereo:
; check end of sample
cmp ecx,0
jle near loopEnd_MixStereo
cmp D [bEndOfSound],TRUE
je near loopEnd_MixStereo
; get sound samples
movq mm1,Q [esi+ ebx*4]
movq mm2,Q [esi+ edx*4]
pslld mm1,16
psrad mm1,16 ; MM1 = 0 | nextLeftSample || 0 | leftSample
psrad mm2,16 ; MM2 = 0 | nextRightSample || 0 | rightSample
packssdw mm1,mm2 ; MM1 = nextRightSample | rightSample || nextLeftSample | leftSample
; calc linear interpolation factor (strength)
movd mm3,eax ; MM3 = 0 | 0 || right frac | left frac
punpcklwd mm3,mm3
psrlw mm3,1 ; MM3 = rightFrac | rightFrac || leftFrac | leftFrac
pxor mm3,Q [mmInvFactor] ; MM3 = rightFrac | 1-rightFrac || leftFrac | 1-leftFrac
; apply linear interpolation
pmaddwd mm1,mm3
psrad mm1,15
packssdw mm1,mm1 ; MM1 = ? | ? || linearRightSample | linearLeftSample
; apply filter
psubsw mm1,mm6
pmulhw mm1,mm7
psllw mm1,1
paddsw mm1,mm6
movq mm6,mm1
; apply volume adjustment
movq mm0,mm5
psrad mm0,16
packssdw mm0,mm0
pmulhw mm1,mm0
psllw mm1,1
pxor mm1,Q [mmSurroundFactor]
paddd mm5,Q [mmVolumeGain] ; modify volume
; unpack to 32bit and mix it into destination buffer
punpcklwd mm1,mm1
psrad mm1,16 ; MM1 = finalRightSample || finalLeftSample
paddd mm1,Q [edi]
movq Q [edi],mm1
; advance to next samples in source sound
add eax,D [mmRightStep+0]
adc edx,D [mmRightStep+4]
add ax,W [mmLeftStep +0]
adc ebx,D [mmLeftStep +2]
add edi,8
dec ecx
jmp sampleLoop_MixStereo
loopEnd_MixStereo:
; store modified asm local vars
mov D [fixLeftOfs +0],eax
shr eax,16
mov D [fixRightOfs+0],eax
mov D [fixLeftOfs +2],ebx
mov D [fixRightOfs+2],edx
movd eax,mm6
mov edx,eax
and eax,0x0000FFFF
shr edx,16
mov D [slLastLeftSample],eax
mov D [slLastRightSample],edx
emms
pop ebx ; Restore GCC register.
ret
; ************************
; ** End Code Block **
; ************************