CnC_Red_Alert/WINVQ/VQM32/SOSCODEC.ASM

1272 lines
33 KiB
NASM
Raw Permalink Normal View History

;
; Command & Conquer Red Alert(tm)
; Copyright 2025 Electronic Arts 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 3 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, see <http://www.gnu.org/licenses/>.
;
;****************************************************************************
;*
;* Copyright (c) 1994, HMI, INC. All Rights Reserved
;*
;*---------------------------------------------------------------------------
;*
;* FILE
;* soscodec.asm
;*
;* DESCRIPTION
;* HMI SOS ADPCM compression/decompression.
;*
;* PROGRAMMER
;* Nick Skrepetos
;* Denzil E. Long, Jr. (Fixed bugs, rewrote for watcom)
;* Bill Petro (Added stereo support)
;* DATE
;* Febuary 15, 1995
;*
;*---------------------------------------------------------------------------
;*
;* PUBLIC
;*
;****************************************************************************
IDEAL
P386
MODEL USE32 FLAT
LOCALS ??
STRUC sCompInfo
lpSource DD ? ;Compressed data pointer
lpDest DD ? ;Uncompressed data pointer
dwCompSize DD ? ;Compressed size
dwUnCompSize DD ? ;Uncompressed size
wBitSize DW ? ;Bit size for decompression
wChannels DW ? ;number of channels
dwSampleIndex DD ? ;Index into sample
dwPredicted DD ? ;Next predicted value
dwDifference DD ? ;Difference from last sample
wCodeBuf DW ? ;Holds 2 nibbles for decompression
wCode DW ? ;Current 4 bit code
wStep DW ? ;Step value in table
wIndex DW ? ;Index into step table
dwSampleIndex2 DD ? ;Index into sample
dwPredicted2 DD ? ;Next predicted value
dwDifference2 DD ? ;Difference from last sample
wCodeBuf2 DW ? ;Holds 2 nibbles for decompression
wCode2 DW ? ;Current 4 bit code
wStep2 DW ? ;Step value in table
wIndex2 DW ? ;Index into step table
ENDS sCompInfo
DATASEG
;* Index table for stepping into step table
wCODECIndexTab DW -1,-1,-1,-1,2,4,6,8
DW -1,-1,-1,-1,2,4,6,8
;Lookup table of replacement values
;The actual sound value is replaced with an index to lookup in this table
;The index only takes up a nibble(4bits) and represents an int(16bits)
;Essentially:
;Get a value
;compare it with the value before it
;find closest value in table and store the index into the table
;if i'm going down then negitize it
;go to next byte.
;Theory for stereo:
;1)handle stereo and mono in two seperate loops. cleaner...
;start at byte 0 and skip every other byte(or word) both write and read
;when we get done set start byte to 1 and do it again
;This table essentialy round off to closes values in 3 distinct bands
; precalculated and optimized(i guess) for human hearing.
wCODECStepTab DW 7,8,9,10,11,12,13,14
DW 16,17,19,21,23,25,28,31
DW 34,37,41,45,50,55,60,66
DW 73,80,88,97,107,118,130,143
DW 157,173,190,209,230,253,279,307
DW 337,371,408,449,494,544,598,658
DW 724,796,876,963,1060,1166,1282,1411
DW 1552,1707,1878,2066,2272,2499,2749,3024
DW 3327,3660,4026,4428,4871,5358,5894,6484
DW 7132,7845,8630,9493,10442,11487,12635,13899
DW 15289,16818,18500,20350,22385,24623,27086,29794
DW 32767
dwCODECByteIndex DD 0 ; this is when to stop compressing
dwCODECBytesProcessed DD 0 ; this is how many so far compressed
dwCODECTempStep DD 0 ; tempory storage for step value
wCODECMask DW 0 ; Current mask
CODESEG
;****************************************************************************
;*
;* NAME
;* sosCODECInitStream - Initialize compression stream.
;*
;* SYNOPSIS
;* sosCODECInitStream(CompInfo)
;*
;* void sosCODECInitStream(_SOS_COMPRESS_INFO *);
;*
;* FUNCTION
;* Initialize compression stream for compression and decompression.
;*
;* INPUTS
;* CompInfo - Compression information structure.
;*
;* RESULT
;* NONE
;*
;****************************************************************************
GLOBAL C VQA_sosCODECInitStream:NEAR
PROC VQA_sosCODECInitStream C NEAR
ARG sSOSInfo:NEAR PTR
mov eax,[sSOSInfo]
mov [(sCompInfo eax).wIndex],0 ; starting index 0
mov [(sCompInfo eax).wStep],7 ; start with a step of 7
mov [(sCompInfo eax).dwPredicted],0 ; no predicted value
mov [(sCompInfo eax).dwSampleIndex],0 ;start at head of index
mov [(sCompInfo eax).wIndex2],0 ; starting index 0
mov [(sCompInfo eax).wStep2],7 ; start with a step of 7
mov [(sCompInfo eax).dwPredicted2],0 ; no predicted value
mov [(sCompInfo eax).dwSampleIndex2],0 ;start at head of index
ret
ENDP VQA_sosCODECInitStream
;****************************************************************************
;*
;* NAME
;* sosCODECCompressData - Compress audio data.
;*
;* SYNOPSIS
;* Size = sosCODECCompressData(CompInfo, NumBytes)
;*
;* long sosCODECCompressData(_SOS_COMPRESS_INFO *, long);
;*
;* FUNCTION
;* Compress an audio data stream into 4:1 ADPCM. 16 bit data is
;* compressed 4:1, 8 bit data is compressed 2:1.
;*
;* INPUTS
;* CompInfo - Pointer to initialized compress information structure.
;* NumBytes - Number of bytes to compress.
;*
;* RESULT
;* Size - Size of compressed data.
;*
;****************************************************************************
GLOBAL C VQA_sosCODECCompressData:NEAR
PROC VQA_sosCODECCompressData C NEAR
ARG sSOSInfo:NEAR PTR
ARG wBytes:DWORD
push esi
push edi
push ebx
push ecx
push edx
;*---------------------------------------------------------------------------
;* Initialize
;*---------------------------------------------------------------------------
mov ebx,[sSOSInfo]
mov eax,[wBytes]
mov [dwCODECBytesProcessed],eax
mov [(sCompInfo ebx).dwSampleIndex],0 ;start at head of index
mov [(sCompInfo ebx).dwSampleIndex2],0 ;start at head of index
; Check for 16 bit decompression
cmp [(sCompInfo ebx).wBitSize],16 ;16 bit requested?
jne short ??skipByteDivide ;no so skip divide
shr eax,1 ;divide size by 2
??skipByteDivide:
mov [dwCODECByteIndex],eax
mov esi,[(sCompInfo ebx).lpSource] ;ESI = source
mov edi,[(sCompInfo ebx).lpDest] ;EDI = dest
cmp [(sCompInfo ebx).wChannels],2 ;stereo check
je ??mainloopl
;------------------------------------------------------------------------
; Mono start
;------------------------------------------------------------------------
??mainloop:
cmp [(sCompInfo ebx).wBitSize],16 ;are we doing 16 bit
jne short ??input8Bit ;no. goto 8 bit input
movsx eax,[word ptr esi] ;Get 16bit sample
add esi,2
jmp short ??computeDiff ;skip 8 bit load
??input8Bit:
mov ah,[esi] ;Get 8bit sample
inc esi
xor al,al ;zero out low byte
xor ah,80h ;flip sign bit
movsx eax,ax
??computeDiff:
movsx ecx,[word ptr (sCompInfo ebx).dwPredicted]
sub eax,ecx ;sample-predicted
xor ecx,ecx ;clear ecx
cmp eax,0 ;Diff > = 0
jge ??positive
neg eax ;else difference= -difference
or ecx,8 ;set nibble sign bit in ecx
??positive:
mov [(sCompInfo ebx).wCode],cx ;Store code
movsx ecx,[(sCompInfo ebx).wStep] ;Get step value
mov [dwCODECTempStep],ecx
mov edx,4 ;mask value (i think)
mov ecx,3 ;loop count
??quantizeLoop:
cmp eax,[dwCODECTempStep] ;Diff < step ?
jl short ??nextQLoop ;goto nextQloop
; OR in mask value into code and adjust difference.
or [(sCompInfo ebx).wCode],dx ;else or mask into code
sub eax,[dwCODECTempStep] ;difference-=tempstep
??nextQLoop:
shr [dwCODECTempStep],1 ; TempStep>>=1
shr edx,1 ; mask>>=1
loop ??quantizeLoop ; back to quatize loop
;-----------------------------------------------------------------------------------------
; now i'v got the new diff and code is masked right
;-----------------------------------------------------------------------------------------
; store off new difference value
mov [(sCompInfo ebx).dwDifference],eax
; determine if sample index is even or odd.
; this will determine if we need to get a new token or not.
test [(sCompInfo ebx).dwSampleIndex],1 ; is it even? (starts at 0)
jne short ??storeToken ; if so goto store token
; else its odd so get token
xor eax,eax
mov ax,[(sCompInfo ebx).wCode] ;ax=wCode
and eax,0Fh ;and off high nibble
mov [(sCompInfo ebx).wCodeBuf],ax ;wCodeBuf=ax
jmp short ??calcDifference ;goto calcDifference
??storeToken:
; fetch new token
xor eax,eax
mov ax,[(sCompInfo ebx).wCode] ;ax=code
shl eax,4 ;shift low nibble to high
or ax,[(sCompInfo ebx).wCodeBuf] ;or in the stored nibble
mov [edi],al ;*dest=al
inc edi ;dest++
??calcDifference:
mov [(sCompInfo ebx).dwDifference],0 ;dwDifference=0
xor ecx,ecx ;ecx=0
mov cx,[(sCompInfo ebx).wStep] ;cx=Step
xor eax,eax ;eax=0
mov ax,[(sCompInfo ebx).wCode] ;ax=wCode
test eax,4 ;Check 0100
je short ??no4
add [(sCompInfo ebx).dwDifference],ecx ;difference+=step
??no4:
test eax,2 ;Check 0010
je short ??no2
mov edx,ecx ;edx=wStep
shr edx,1 ;edx>>1
add [(sCompInfo ebx).dwDifference],edx ;Difference=wstep>>1
??no2:
test eax,1 ;Check 0001
je short ??no1
mov edx,ecx ;edx=wStep
shr edx,2 ;edx>>2
add [(sCompInfo ebx).dwDifference],edx ;Difference=wstep>>2
??no1:
mov edx,ecx
shr edx,3
add [(sCompInfo ebx).dwDifference],edx ;Difference=wstep>>3
test eax,8 ;Check 1000
je short ??no8
neg [(sCompInfo ebx).dwDifference] ;Negate diff because sign bit was set
??no8:
mov eax,[(sCompInfo ebx).dwPredicted]
add eax,[(sCompInfo ebx).dwDifference] ;eax=Preditcted+Difference
cmp eax,7FFFh
jl short ??noOverflow
mov eax,7FFFh ;if overflow store 7fff in diff
??noOverflow:
cmp eax,0FFFF8000h
jg short ??noUnderflow
mov eax,0FFFF8000h ;if overflow 0FFFF8000 in diff
??noUnderflow:
mov [(sCompInfo ebx).dwPredicted],eax ;store into predicted
xor ecx,ecx
mov cx,[(sCompInfo ebx).wCode] ;cx=Code
xor eax,eax
shl ecx,1 ;cx<<1
mov ax,[wCODECIndexTab + ecx] ;ax=Indextab[ecx]
add [(sCompInfo ebx).wIndex],ax ;wIndex+=ax
cmp [(sCompInfo ebx).wIndex],8000h ; check if wIndex < 0
jb short ??checkOverflow
mov [(sCompInfo ebx).wIndex],0 ; reset index to zero
jmp short ??adjustStep
??checkOverflow:
cmp [(sCompInfo ebx).wIndex],88 ; check if wIndex > 88
jbe short ??adjustStep
mov [(sCompInfo ebx).wIndex],88 ; reset index to 88
??adjustStep:
; fetch wIndex so we can fetch new step value
xor ecx,ecx
mov cx,[(sCompInfo ebx).wIndex]
xor eax,eax
shl ecx,1
mov ax,[wCODECStepTab + ecx]
; advance index and store step value
add [(sCompInfo ebx).dwSampleIndex],1
mov [(sCompInfo ebx).wStep],ax
; decrement bytes processed and loop back.
dec [dwCODECByteIndex]
jne ??mainloop ; }while !0
jmp ??exitout
;-----------------------------------------------------------------------
;Stereo Left Side
;-----------------------------------------------------------------------
??mainloopl:
; determine bit size for input ;do{
cmp [(sCompInfo ebx).wBitSize],16 ;are we doing 16 bit
jne short ??input8Bitl ;no. goto 8 bit input **
movsx eax,[word ptr esi] ;load next word from source
add esi,4 ;inc source by 2 words **
jmp short ??computeDiffl ;skip 8 bit load **
??input8Bitl:
mov ah,[esi] ;Get 8 bit sample
add esi,2 ;inc source by 2 bytes **
xor al,al ;zero out low byte
xor ah,80h ;flip sign bit
movsx eax,ax ;sign extend into eax
??computeDiffl:
; compute difference
movsx ecx,[word ptr (sCompInfo ebx).dwPredicted]
;load predicted (starts at 0)
sub eax,ecx ;difference=sample-preditcted
; check if dwDifference > 0. ECX is the
; sign bit, it is initialized to positive.
xor ecx,ecx ;clear ecx
cmp eax,0 ;if(difference>=0)
jge short ??positivel ;goto positive
neg eax ;else difference= -difference
or ecx,8 ;set nibble sign bit in ecx
??positivel:
mov [(sCompInfo ebx).wCode],cx ;Store code from cx into struct
; set up to quantize difference. initialize
; wCODECTempStep = step value.
movsx ecx,[(sCompInfo ebx).wStep] ;ecx=step value(starts at 7)
mov [dwCODECTempStep],ecx ;tempstep=step
mov edx,4 ;edx=4 mask value (i think)
mov ecx,3 ;ecx is loop number so loop 3 times
??quantizeLoopl:
; check to see if difference > tempstep value.
cmp eax,[dwCODECTempStep] ;if(difference < tempstep)
jl short ??nextQLoopl ;goto nextQloop
; OR in mask value into code and adjust difference.
or [(sCompInfo ebx).wCode],dx ;else or mask into code
sub eax,[dwCODECTempStep] ;difference-=tempstep
??nextQLoopl:
; shift down tempstep and mask
shr [dwCODECTempStep],1 ; TempStep>>=1
shr edx,1 ; mask>>=1
loop ??quantizeLoopl ; back to quatize loop
;------------------------------------------------------------------------------------------
; now i'v got the new diff and code is masked right
; store off new difference value
mov [(sCompInfo ebx).dwDifference],eax
; determine if sample index is even or odd.
; this will determine if we need to get a new token or not.
test [(sCompInfo ebx).dwSampleIndex],1 ; is it even? (starts at 0)
jne short ??storeTokenl ; if so goto store token **
; else its odd so get token
xor eax,eax
mov ax,[(sCompInfo ebx).wCode] ;ax=wCode
and eax,0Fh ;and off high nibble
mov [(sCompInfo ebx).wCodeBuf],ax ;wCodeBuf=ax
jmp short ??calcDifferencel ;goto calcDifference **
??storeTokenl:
; fetch new token
xor eax,eax
mov ax,[(sCompInfo ebx).wCode] ;ax=code
shl eax,4 ;shift low nibble to hign nibble
or ax,[(sCompInfo ebx).wCodeBuf] ;or in the stored nibble
mov [edi],al ;*dest=al
add edi,2 ;dest+=2 **
??calcDifferencel:
mov [(sCompInfo ebx).dwDifference],0;dwDifference=0
xor ecx,ecx ;ecx=0
mov cx,[(sCompInfo ebx).wStep] ;cx=Step
xor eax,eax ;eax=0
mov ax,[(sCompInfo ebx).wCode] ;ax=wCode
test eax,4 ;Check 0100
je short ??no4l ; **
add [(sCompInfo ebx).dwDifference],ecx ;difference+=step
??no4l:
test eax,2 ;Check 0010
je short ??no2l ; **
mov edx,ecx ;edx=wStep
shr edx,1 ;edx>>1
add [(sCompInfo ebx).dwDifference],edx ;Difference=wstep>>1
??no2l:
test eax,1 ;Check 0001
je short ??no1l ; **
mov edx,ecx ;edx=wStep
shr edx,2 ;edx>>2
add [(sCompInfo ebx).dwDifference],edx ;Difference=wstep>>2
??no1l:
mov edx,ecx
shr edx,3
add [(sCompInfo ebx).dwDifference],edx ;Difference=wstep>>3
test eax,8 ;Check 1000
je short ??no8l
;Negate diff because sign bit was set
neg [(sCompInfo ebx).dwDifference]
??no8l:
mov eax,[(sCompInfo ebx).dwPredicted]
add eax,[(sCompInfo ebx).dwDifference] ;eax=Preditcted+Difference
cmp eax,7FFFh
jl short ??noOverflowl
mov eax,7FFFh ;if overflow store 7fff in diff
??noOverflowl:
cmp eax,0FFFF8000h
jg short ??noUnderflowl
mov eax,0FFFF8000h ;if overflow 0FFFF8000 in diff
??noUnderflowl:
mov [(sCompInfo ebx).dwPredicted],eax ;store into predicted
xor ecx,ecx ;adjust index
mov cx,[(sCompInfo ebx).wCode] ;cx=Code
xor eax,eax
shl ecx,1 ;cx<<1
mov ax,[wCODECIndexTab + ecx] ;ax=Indextab[ecx]
add [(sCompInfo ebx).wIndex],ax ;wIndex+=ax
cmp [(sCompInfo ebx).wIndex],8000h ;check if wIndex < 0
jb short ??checkOverflowl ; **
mov [(sCompInfo ebx).wIndex],0 ; reset index to zero
jmp short ??adjustStepl ; **
??checkOverflowl:
; check if wIndex > 88
cmp [(sCompInfo ebx).wIndex],88
jbe short ??adjustStepl ; **
; reset index to 88
mov [(sCompInfo ebx).wIndex],88
??adjustStepl:
; fetch wIndex so we can fetch new step value
xor ecx,ecx
mov cx,[(sCompInfo ebx).wIndex]
xor eax,eax
shl ecx,1
mov ax,[wCODECStepTab + ecx]
; advance index and store step value
add [(sCompInfo ebx).dwSampleIndex],1
mov [(sCompInfo ebx).wStep],ax
; decrement bytes processed and loop back.
sub [dwCODECByteIndex],2 ; sub 2 for stereo **
jne ??mainloopl ; }while !0 **
;-------------------------------------------------------------------------
;Right channel re-set up varibles
;-------------------------------------------------------------------------
mov eax,[wBytes]
mov esi,[(sCompInfo ebx).lpSource] ; point to source buffer
mov edi,[(sCompInfo ebx).lpDest] ; point to destination buffer
inc esi ; skip first byte
inc edi ; ship first byte
; Check for 16 bit compression
cmp [(sCompInfo ebx).wBitSize],16
je short ??do16bit
mov [dwCODECByteIndex],eax
jmp short ??mainloopr
??do16bit:
shr eax,1 ;16 bit so half as many bytes
inc esi ;16 bit so 1 more byte to skip
mov [dwCODECByteIndex],eax
;-----------------------------------------------------------------------
;Start of Stereo Right Side
;-----------------------------------------------------------------------
??mainloopr:
; determine bit size for input ;do{
cmp [(sCompInfo ebx).wBitSize],16 ;are we doing 16 bit
jne short ??input8Bitr ;no. goto 8 bit input **
movsx eax,[word ptr esi] ;load next word from source
add esi,4 ;inc source by 2 words **
jmp short ??computeDiffr ;skip 8 bit load **
??input8Bitr:
mov ah,[esi] ;Get 8 bit sample
add esi,2 ;inc source by 2 bytes **
xor al,al ;zero out low byte
xor ah,80h ;flip sign bit
movsx eax,ax ;sign extend into eax
??computeDiffr:
; compute difference
movsx ecx,[word ptr (sCompInfo ebx).dwPredicted2]
;load predicted (starts at 0)
sub eax,ecx ;difference=sample-preditcted
; check if dwDifference > 0. ECX is the
; sign bit, it is initialized to positive.
xor ecx,ecx ;clear ecx
cmp eax,0 ;if(difference>=0)
jge short ??positiver ;goto positive
neg eax ;else difference= -difference
or ecx,8 ;set nibble sign bit in ecx
??positiver:
mov [(sCompInfo ebx).wCode2],cx ;Store code from cx into struct
; set up to quantize difference. initialize
; wCODECTempStep = step value.
movsx ecx,[(sCompInfo ebx).wStep2] ;ecx=step value(starts at 7)
mov [dwCODECTempStep],ecx ;tempstep=step
mov edx,4 ;edx=4 mask value (i think)
mov ecx,3 ;ecx is loop number so loop 3 times
??quantizeLoopr:
; check to see if difference > tempstep value.
cmp eax,[dwCODECTempStep] ;if(difference < tempstep)
jl short ??nextQLoopr ;goto nextQloop
; OR in mask value into code and adjust difference.
or [(sCompInfo ebx).wCode2],dx ;else or mask into code
sub eax,[dwCODECTempStep] ;difference-=tempstep
??nextQLoopr:
; shift down tempstep and mask
shr [dwCODECTempStep],1 ; TempStep>>=1
shr edx,1 ; mask>>=1
loop ??quantizeLoopr ; back to quatize loop
;------------------------------------------------------------------------------------------
; now i'v got the new diff and code is masked right
; store off new difference value
mov [(sCompInfo ebx).dwDifference2],eax
; determine if sample index is even or odd.
; this will determine if we need to get a new token or not.
test [(sCompInfo ebx).dwSampleIndex2],1 ; is it even? (starts at 0)
jne short ??storeTokenr ; if so goto store token **
; else its odd so get token
xor eax,eax
mov ax,[(sCompInfo ebx).wCode2] ;ax=wCode
and eax,0Fh ;and off high nibble
mov [(sCompInfo ebx).wCodeBuf2],ax ;wCodeBuf=ax
jmp short ??calcDifferencer ;goto calcDifference **
??storeTokenr:
xor eax,eax
mov ax,[(sCompInfo ebx).wCode2] ;ax=code
shl eax,4 ;shift low nibble to hign nibble
or ax,[(sCompInfo ebx).wCodeBuf2] ;or in the stored nibble
mov [edi],al ;*dest=al
add edi,2 ;dest+=2 **
??calcDifferencer:
mov [(sCompInfo ebx).dwDifference2],0 ;dwDifference=0
xor ecx,ecx ;ecx=0
mov cx,[(sCompInfo ebx).wStep2] ;cx=Step
xor eax,eax ;eax=0
mov ax,[(sCompInfo ebx).wCode2] ;ax=wCode
test eax,4 ;Check 0100
je short ??no4r
add [(sCompInfo ebx).dwDifference2],ecx ;difference+=step
??no4r:
test eax,2 ;Check 0010
je short ??no2r
mov edx,ecx ;edx=wStep
shr edx,1 ;edx>>1
add [(sCompInfo ebx).dwDifference2],edx ;Difference=wstep>>1
??no2r:
test eax,1 ;Check 0001
je short ??no1r
mov edx,ecx ;edx=wStep
shr edx,2 ;edx>>2
add [(sCompInfo ebx).dwDifference2],edx ;Difference=wstep>>2
??no1r:
mov edx,ecx
shr edx,3
add [(sCompInfo ebx).dwDifference2],edx ;Difference=wstep>>3
test eax,8 ;Check 1000
je short ??no8r
neg [(sCompInfo ebx).dwDifference2]
??no8r:
; add difference to predicted value.
mov eax,[(sCompInfo ebx).dwPredicted2]
add eax,[(sCompInfo ebx).dwDifference2] ;eax=Preditcted+Difference
cmp eax,7FFFh
jl short ??noOverflowr
mov eax,7FFFh ;if overflow store 7fff in diff
??noOverflowr:
cmp eax,0FFFF8000h
jg short ??noUnderflowr
mov eax,0FFFF8000h ;if overflow 0FFFF8000 in diff
??noUnderflowr:
mov [(sCompInfo ebx).dwPredicted2],eax ;store into predicted
xor ecx,ecx ;adjust index
mov cx,[(sCompInfo ebx).wCode2] ;cx=Code
xor eax,eax
shl ecx,1 ;cx<<1
mov ax,[wCODECIndexTab + ecx] ;ax=Indextab[ecx]
add [(sCompInfo ebx).wIndex2],ax ;wIndex+=ax
cmp [(sCompInfo ebx).wIndex2],8000h ;check if wIndex < 0
jb short ??checkOverflowr
mov [(sCompInfo ebx).wIndex2],0 ;reset index to zero
jmp short ??adjustStepr
??checkOverflowr:
cmp [(sCompInfo ebx).wIndex2],88 ;check if wIndex > 88
jbe short ??adjustStepr
mov [(sCompInfo ebx).wIndex2],88 ;reset index to 88
??adjustStepr:
; fetch wIndex so we can fetch new step value
xor ecx,ecx
mov cx,[(sCompInfo ebx).wIndex2]
xor eax,eax
shl ecx,1
mov ax,[wCODECStepTab + ecx]
; advance index and store step value
add [(sCompInfo ebx).dwSampleIndex2],1
mov [(sCompInfo ebx).wStep2],ax
; decrement bytes processed and loop back.
sub [dwCODECByteIndex],2 ; sub 2 for stereo
jne ??mainloopr ; }while !0
;-------------------------------------------------------------------------
;Final clean up
;-------------------------------------------------------------------------
??exitout:
; save off ESI and EDI back into compress info structure.
; mov [(sCompInfo ebx).lpSource],esi
; mov [(sCompInfo ebx).lpDest],edi
; set up return value for number of bytes processed.
mov eax,[dwCODECBytesProcessed]
shr eax,1
cmp [(sCompInfo ebx).wBitSize],16
jne ??leave
shr eax,1 ;if not 16 bit then div/2
??leave:
pop edx
pop ecx
pop ebx
pop edi
pop esi
ret
ENDP VQA_sosCODECCompressData
;****************************************************************************
;*
;* NAME
;* sosCODECDecompressData - Decompress audio data.
;*
;* SYNOPSIS
;* Size = sosCODECDecompressData(CompInfo, NumBytes)
;*
;* long sosCODECDecompressData(_SOS_COMPRESS_INFO *, long);
;*
;* FUNCTION
;* Decompress data from a 4:1 ADPCM compressed stream. The number of
;* bytes decompressed is returned.
;*
;* INPUTS
;* CompInfo - Compress information structure.
;* NumBytes - Number of bytes to compress.
;*
;* RESULT
;* Size - Size of decompressed data.
;*
;****************************************************************************
GLOBAL C VQA_sosCODECDecompressData:NEAR
PROC VQA_sosCODECDecompressData C NEAR
ARG sSOSInfo:NEAR PTR
ARG wBytes:DWORD
push esi
push edi
push ebx
push ecx
push edx
;*---------------------------------------------------------------------------
;* Initialize
;*---------------------------------------------------------------------------
mov ebx,[sSOSInfo]
mov eax,[wBytes]
mov [dwCODECBytesProcessed],eax
mov [(sCompInfo ebx).dwSampleIndex],0 ;start at head of index
mov [(sCompInfo ebx).dwSampleIndex2],0 ;start at head of index
;* Check for 16 bit decompression
cmp [(sCompInfo ebx).wBitSize],16
jne short ??skipByteDivide
shr eax,1
??skipByteDivide:
mov [dwCODECByteIndex],eax
mov esi,[(sCompInfo ebx).lpSource]
mov edi,[(sCompInfo ebx).lpDest]
cmp [(sCompInfo ebx).wChannels],2 ;stereo check
je ??mainloopl ;do left side first
; Determine if sample index is even or odd. This will determine
; if we need to get a new token or not.
;*---------------------------------------------------------------------------
;* Main Mono Loop
;*---------------------------------------------------------------------------
??mainloop:
test [(sCompInfo ebx).dwSampleIndex],1 ;odd ??
je short ??fetchToken ;if so get new token
xor eax,eax ;else shift int codebuf
mov ax,[(sCompInfo ebx).wCodeBuf] ;ored with Code
shr eax,4
and eax,000Fh
mov [(sCompInfo ebx).wCode],ax
jmp short ??calcDifference
??fetchToken:
xor eax,eax ;get a new token
mov al,[esi] ;put in codebuf
mov [(sCompInfo ebx).wCodeBuf],ax
inc esi
and eax,000Fh
mov [(sCompInfo ebx).wCode],ax ;and then code
??calcDifference:
mov [(sCompInfo ebx).dwDifference],0 ;reset diff
xor ecx,ecx
mov cx,[(sCompInfo ebx).wStep] ;cx is step value
test eax,4 ;Check for wCode & 4
je short ??no4
add [(sCompInfo ebx).dwDifference],ecx ;Add wStep
??no4:
test eax,2 ;Check for wCode & 2
je short ??no2
mov edx,ecx ;Add wStep >> 1
shr edx,1
add [(sCompInfo ebx).dwDifference],edx
??no2:
test eax,1 ;Check for wCode & 1
je short ??no1
mov edx,ecx ;Add wStep >> 2
shr edx,2
add [(sCompInfo ebx).dwDifference],edx
??no1:
mov edx,ecx ;Add in wStep >> 3
shr edx,3
add [(sCompInfo ebx).dwDifference],edx
test eax,8 ;Check for wCode & 8
je short ??no8
neg [(sCompInfo ebx).dwDifference] ;Negate diff
??no8:
; add difference to predicted value.
mov eax,[(sCompInfo ebx).dwPredicted]
add eax,[(sCompInfo ebx).dwDifference]
; make sure there is no under or overflow.
cmp eax,7FFFh
jl short ??noOverflow
mov eax,7FFFh
??noOverflow:
cmp eax,0FFFF8000h
jg short ??noUnderflow
mov eax,0FFFF8000h
??noUnderflow:
mov [(sCompInfo ebx).dwPredicted],eax
cmp [(sCompInfo ebx).wBitSize],16
jne short ??output8Bit
mov [edi],ax ;Output 16bit sample
add edi,2
jmp short ??adjustIndex
??output8Bit:
; output 8 bit sample
xor ah,80h
mov [edi],ah
inc edi
??adjustIndex:
xor ecx,ecx
mov cx,[(sCompInfo ebx).wCode]
xor eax,eax
shl ecx,1
mov ax,[wCODECIndexTab + ecx]
add [(sCompInfo ebx).wIndex],ax ;check if wIndex < 0
cmp [(sCompInfo ebx).wIndex],8000h
jb short ??checkOverflow
mov [(sCompInfo ebx).wIndex],0 ;reset index to zero
jmp short ??adjustStep
??checkOverflow:
cmp [(sCompInfo ebx).wIndex],88 ;check if wIndex > 88
jbe short ??adjustStep
mov [(sCompInfo ebx).wIndex],88 ;reset index to 88
??adjustStep:
; fetch wIndex so we can fetch new step value
xor ecx,ecx
mov cx,[(sCompInfo ebx).wIndex]
xor eax,eax
shl ecx,1
mov ax,[wCODECStepTab + ecx]
; advance index and store step value
add [(sCompInfo ebx).dwSampleIndex],1
mov [(sCompInfo ebx).wStep],ax
; decrement bytes processed and loop back.
dec [dwCODECByteIndex]
jne ??mainloop
jmp ??exitout
;--------------------------------------------------------------------------
;Left Channel Start
;--------------------------------------------------------------------------
??mainloopl:
test [(sCompInfo ebx).dwSampleIndex],1
je short ??fetchTokenl
xor eax,eax
mov ax,[(sCompInfo ebx).wCodeBuf]
shr eax,4
and eax,000Fh
mov [(sCompInfo ebx).wCode],ax
jmp short ??calcDifferencel
??fetchTokenl:
xor eax,eax
mov al,[esi]
mov [(sCompInfo ebx).wCodeBuf],ax
add esi,2 ;2 for stereo
and eax,000Fh
mov [(sCompInfo ebx).wCode],ax
??calcDifferencel:
; reset difference
mov [(sCompInfo ebx).dwDifference],0
xor ecx,ecx
mov cx,[(sCompInfo ebx).wStep]
test eax,4 ;Check for wCode & 4
je short ??no4l
add [(sCompInfo ebx).dwDifference],ecx ;Add wStep
??no4l:
test eax,2 ;Check for wCode & 2
je short ??no2l
mov edx,ecx ;Add wStep >> 1
shr edx,1
add [(sCompInfo ebx).dwDifference],edx
??no2l:
test eax,1 ;Check for wCode & 1
je short ??no1l
mov edx,ecx ;Add wStep >> 2
shr edx,2
add [(sCompInfo ebx).dwDifference],edx
??no1l:
mov edx,ecx ;Add in wStep >> 3
shr edx,3
add [(sCompInfo ebx).dwDifference],edx
test eax,8 ;Check for wCode & 8
je short ??no8l
neg [(sCompInfo ebx).dwDifference] ;Negate diff
??no8l:
; add difference to predicted value.
mov eax,[(sCompInfo ebx).dwPredicted]
add eax,[(sCompInfo ebx).dwDifference]
; make sure there is no under or overflow.
cmp eax,7FFFh
jl short ??noOverflowl
mov eax,7FFFh
??noOverflowl:
cmp eax,0FFFF8000h
jg short ??noUnderflowl
mov eax,0FFFF8000h
??noUnderflowl:
mov [(sCompInfo ebx).dwPredicted],eax
cmp [(sCompInfo ebx).wBitSize],16
jne short ??output8Bitl
mov [edi],ax ;Output 16bit sample
add edi,4 ;4 for stereo
jmp short ??adjustIndexl
??output8Bitl:
; output 8 bit sample
xor ah,80h
mov [edi],ah
add edi,2 ;2 for stereo
??adjustIndexl:
xor ecx,ecx
mov cx,[(sCompInfo ebx).wCode]
xor eax,eax
shl ecx,1
mov ax,[wCODECIndexTab + ecx]
add [(sCompInfo ebx).wIndex],ax
; check if wIndex < 0
cmp [(sCompInfo ebx).wIndex],8000h
jb short ??checkOverflowl
mov [(sCompInfo ebx).wIndex],0
jmp short ??adjustStepl ;reset index to zero
??checkOverflowl:
cmp [(sCompInfo ebx).wIndex],88 ; check if wIndex > 88
jbe short ??adjustStepl
mov [(sCompInfo ebx).wIndex],88 ; reset index to 88
??adjustStepl:
; fetch wIndex so we can fetch new step value
xor ecx,ecx
mov cx,[(sCompInfo ebx).wIndex]
xor eax,eax
shl ecx,1
mov ax,[wCODECStepTab + ecx]
; advance index and store step value
add [(sCompInfo ebx).dwSampleIndex],1
mov [(sCompInfo ebx).wStep],ax
; decrement bytes processed and loop back.
sub [dwCODECByteIndex],2
jne ??mainloopl
;----------------------------------------------------------------------------
; Right Side Setup
;----------------------------------------------------------------------------
mov eax,[wBytes]
mov [dwCODECBytesProcessed],eax
mov esi,[(sCompInfo ebx).lpSource]
mov edi,[(sCompInfo ebx).lpDest]
inc esi ; skip left channel
inc edi ; skip left channel
cmp [(sCompInfo ebx).wBitSize],16 ;16 bit ??
je short ??doByteDivide
mov [dwCODECByteIndex],eax
jmp short ??mainloopr
??doByteDivide:
shr eax,1 ;Divide size by two
inc edi ; 16 bit so skip 1 more
mov [dwCODECByteIndex],eax
;--------------------------------------------------------------------------
;Right Channel Start
;--------------------------------------------------------------------------
??mainloopr:
test [(sCompInfo ebx).dwSampleIndex2],1
je short ??fetchTokenr
xor eax,eax
mov ax,[(sCompInfo ebx).wCodeBuf2]
shr eax,4
and eax,000Fh
mov [(sCompInfo ebx).wCode2],ax
jmp short ??calcDifferencer
??fetchTokenr:
xor eax,eax
mov al,[esi]
mov [(sCompInfo ebx).wCodeBuf2],ax
add esi,2 ;2 for stereo
and eax,000Fh
mov [(sCompInfo ebx).wCode2],ax
??calcDifferencer:
; reset difference
mov [(sCompInfo ebx).dwDifference2],0
xor ecx,ecx
mov cx,[(sCompInfo ebx).wStep2]
test eax,4 ;Check for wCode & 4
je short ??no4r
add [(sCompInfo ebx).dwDifference2],ecx ;Add wStep
??no4r:
test eax,2 ;Check for wCode & 2
je short ??no2r
mov edx,ecx ;Add wStep >> 1
shr edx,1
add [(sCompInfo ebx).dwDifference2],edx
??no2r:
test eax,1 ;Check for wCode & 1
je short ??no1r
mov edx,ecx ;Add wStep >> 2
shr edx,2
add [(sCompInfo ebx).dwDifference2],edx
??no1r:
mov edx,ecx ;Add in wStep >> 3
shr edx,3
add [(sCompInfo ebx).dwDifference2],edx
test eax,8 ;Check for wCode & 8
je short ??no8r
neg [(sCompInfo ebx).dwDifference2] ;Negate diff
??no8r:
; add difference to predicted value.
mov eax,[(sCompInfo ebx).dwPredicted2]
add eax,[(sCompInfo ebx).dwDifference2]
cmp eax,7FFFh
jl short ??noOverflowr
mov eax,7FFFh
??noOverflowr:
cmp eax,0FFFF8000h
jg short ??noUnderflowr
mov eax,0FFFF8000h
??noUnderflowr:
mov [(sCompInfo ebx).dwPredicted2],eax
cmp [(sCompInfo ebx).wBitSize],16
jne short ??output8Bitr
mov [edi],ax ;Output 16bit sample
add edi,4 ;4 for stereo ***
jmp short ??adjustIndexr
??output8Bitr:
; output 8 bit sample
xor ah,80h
mov [edi],ah
add edi,2 ;2 for stereo
??adjustIndexr:
xor ecx,ecx
mov cx,[(sCompInfo ebx).wCode2]
xor eax,eax
shl ecx,1
mov ax,[wCODECIndexTab + ecx]
add [(sCompInfo ebx).wIndex2],ax
; check if wIndex < 0
cmp [(sCompInfo ebx).wIndex2],8000h
jb short ??checkOverflowr
; reset index to zero
mov [(sCompInfo ebx).wIndex2],0
jmp short ??adjustStepr
??checkOverflowr:
; check if wIndex > 88
cmp [(sCompInfo ebx).wIndex2],88
jbe short ??adjustStepr
mov [(sCompInfo ebx).wIndex2],88 ; reset index to 88
??adjustStepr:
; fetch wIndex so we can fetch new step value
xor ecx,ecx
mov cx,[(sCompInfo ebx).wIndex2]
xor eax,eax
shl ecx,1
mov ax,[wCODECStepTab + ecx]
; advance index and store step value
add [(sCompInfo ebx).dwSampleIndex2],1
mov [(sCompInfo ebx).wStep2],ax
; decrement bytes processed and loop back.
sub [dwCODECByteIndex],2
jne ??mainloopr
??exitout:
; don't think we need this but just in case i'll leave it here!!
; mov [(sCompInfo ebx).lpSource],esi
; mov [(sCompInfo ebx).lpDest],edi
; set up return value for number of bytes processed.
mov eax,[dwCODECBytesProcessed]
pop edx
pop ecx
pop ebx
pop edi
pop esi
ret
ENDP VQA_sosCODECDecompressData
END