; ; 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 . ; ;**************************************************************************** ;* ;* 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