;*──────────────────────────────────────────────────────────────────────────* ; SAMP_A.ASM 386 ; (c) Adeline 1993 ;*──────────────────────────────────────────────────────────────────────────* ;*--------------------------------------------------------------------------* include wave.inc ;*--------------------------------------------------------------------------* MIDPOINT MACRO IFDEF SAMPLE16BIT xor eax, eax ELSE mov eax, 80808080h ENDIF ENDM ;*--------------------------------------------------------------------------* .386 jumps .model FLAT, SYSCALL .CODE ;*--------------------------------------------------------------------------* PUBLIC driver_start driver_start dd OFFSET ListFuncs IFDEF SB16 db 'Sound Blaster 16 (DSP 4.XX)' ELSEIFDEF SBPRO db 'Sound Blaster Pro (DSP 3.XX)' ELSEIFDEF SBLASTER1 db 'Sound Blaster 2 (DSP 2.01+)' ELSEIFDEF SBLASTER db 'Sound Blaster (DSP 1.00-2.00)' ELSEIFDEF MWSS db 'Microsoft Windows Sound System (AD1848 SoundPort)' ELSEIFDEF GOLD db 'Adlib Gold (Yamaha GOLD)' ELSEIFDEF GUS db 'Advanced Gravis UltraSound' ELSEIFDEF PAS16 db 'Media Vision Pro Audio Spectrum 16' ELSEIFDEF PAS db 'Media Vision Pro Audio Spectrum/Spectrum Plus' ENDIF db ' Wave Driver,', 13, 10 IFDEF SAMPLE16BIT db '16 bit' ELSE db '8 bit' ENDIF IFDEF STEREO db ' Stereo' ELSE db ' Mono' ENDIF IFDEF SURROUND db ' Surround' ENDIF db ' playback, Version 1.00.', 13, 10 IFDEF GUS db 'Copyright (C) 1991,1992 Miles Design, Inc.', 0Dh, 0Ah db 'Copyright (C) 1993,1994 Advanced Gravis Computer ' db 'Technology Ltd. All rights reserved.', 0Dh, 0Ah db 'Copyright (C) 1992,1993,1994 Forte Technologies.', 0Dh, 0Ah db 'Copyright (C) 1994 Adeline Software International.', 0Dh, 0Ah db 'All rights reserved.', 0Dh, 0Ah db 'UltraSound conversion by Jayeson Lee-Steere.', 0Dh, 0Ah db 'Adeline Software conversion by Serge Plagnol.', 0Dh, 0Ah db 'MIDI and Digital sound library by Forte.', 0Dh, 0Ah, 0Ah, 0 ELSE db 'Copyright (c) Adeline Software International 1994, All Rights Reserved.', 13, 10, 10, 0 ENDIF ListFuncs dd offset InitCard dd offset ClearCard dd offset AskVars dd offset MixSample dd offset GiveSampleInfo0 dd offset StopSample dd offset StopOneSample dd offset SampleInList dd offset GetSnapSample dd offset PauseSample dd offset ContinueSample dd offset SaveStateSample dd offset RestoreStateSample dd offset GetDMAAddr dd offset GetBufferSize dd offset ChangeVolume dd offset ShiftSamples dd offset StopOneSampleLong ;*--------------------------------------------------------------------------* ADDRESS equ 0 FRACT equ 4 LEFT equ 8 C_REPEAT equ 12 INCR equ 14 SON equ 16 HANDLE equ 20 START equ 24 DLENGTH equ 28 VOL_LEFT equ 32 VOL_RIGHT equ 34 INFO0 equ 36 INTERPOL equ 40 LAST_SAMPLE equ 41 ;*--------------------------------------------------------------------------* DSP_VO8S_CMD equ 14h DSP_VO8_CMD equ 1Ch DSP_TIME_CMD equ 40h DSP_RATE_CMD equ 41h DSP_BSIZE_CMD equ 48h DSP_VO8H_CMD equ 90h DSP_VO16S_CMD equ 0B0h DSP_VO16_CMD equ 0B6h DSP_VO8S_4_CMD equ 0C0h DSP_VO8_4_CMD equ 0C6h DSP_ONSPK_CMD equ 0D1h DSP_OFFSPK_CMD equ 0D3h DSP_16MONO_MODE equ 10h DSP_16STEREO_MODE equ 30h DSP_8MONO_MODE equ 00h DSP_8STEREO_MODE equ 20h RESET_TEST_CODE equ 0AAh ;*--------------------------------------------------------------------------* ifndef NOIRQ VOICE_OUT equ 0 ; equ to access the 2 arrays below AUTO_OUT equ 1 MASK1 equ 2 MASK2 equ 3 ADDX_REG equ 4 COUNT_REG equ 6 MASK_REG equ 8 MODE_REG equ 10 FF_REG equ 12 PAGE_REG equ 14 DMA0 equ $ ; Ports for DMA0 DMA0_VOICE_OUT db 48H DMA0_AUTO_OUT db 58H DMA0_MASK1 db 00H DMA0_MASK2 db 04H DMA0_ADDX_REG dw 00H DMA0_COUNT_REG dw 01H DMA0_MASK_REG dw 0AH DMA0_MODE_REG dw 0BH DMA0_FF_REG dw 0CH DMA0_PAGE_REG dw 87H DMA1 equ $ ; Ports for DMA1 DMA1_VOICE_OUT db 49H DMA1_AUTO_OUT db 59H DMA1_MASK1 db 01H DMA1_MASK2 db 05H DMA1_ADDX_REG dw 02H DMA1_COUNT_REG dw 03H DMA1_MASK_REG dw 0AH DMA1_MODE_REG dw 0BH DMA1_FF_REG dw 0CH DMA1_PAGE_REG dw 83H DMA3 equ $ ; Ports for DMA3 DMA3_VOICE_OUT db 4BH DMA3_AUTO_OUT db 5BH DMA3_MASK1 db 03H DMA3_MASK2 db 07H DMA3_ADDX_REG dw 06H DMA3_COUNT_REG dw 07H DMA3_MASK_REG dw 0AH DMA3_MODE_REG dw 0BH DMA3_FF_REG dw 0CH DMA3_PAGE_REG dw 82H DMA5 equ $ ; Ports for DMA5 DMA5_VOICE_OUT db 49H DMA5_AUTO_OUT db 59H DMA5_MASK1 db 01H DMA5_MASK2 db 05H DMA5_ADDX_REG dw 0C4H DMA5_COUNT_REG dw 0C6H DMA5_MASK_REG dw 0D4H DMA5_MODE_REG dw 0D6H DMA5_FF_REG dw 0D8H DMA5_PAGE_REG dw 08BH DMA6 equ $ ; Ports for DMA6 DMA6_VOICE_OUT db 4AH DMA6_AUTO_OUT db 5AH DMA6_MASK1 db 02H DMA6_MASK2 db 06H DMA6_ADDX_REG dw 0C8H DMA6_COUNT_REG dw 0CAH DMA6_MASK_REG dw 0D4H DMA6_MODE_REG dw 0D6H DMA6_FF_REG dw 0D8H DMA6_PAGE_REG dw 089H DMA7 equ $ ; Ports for DMA7 DMA7_VOICE_OUT db 4BH DMA7_AUTO_OUT db 5BH DMA7_MASK1 db 03H DMA7_MASK2 db 07H DMA7_ADDX_REG dw 0CCH DMA7_COUNT_REG dw 0CEH DMA7_MASK_REG dw 0D4H DMA7_MODE_REG dw 0D6H DMA7_FF_REG dw 0D8H DMA7_PAGE_REG dw 08AH ALIGN 4 TAB_DMA dd offset DMA0 dd offset DMA1 dd 0 dd offset DMA3 dd 0 dd offset DMA5 dd offset DMA6 dd offset DMA7 endif ;*--------------------------------------------------------------------------* CurrentList db STRUCT_SIZE*LIST_SIZE+4 dup (?) SonList db STRUCT_SIZE*LIST_SIZE+4 dup (?) BackCurrentList db STRUCT_SIZE*LIST_SIZE+4 dup (?) BackSonList db STRUCT_SIZE*LIST_SIZE+4 dup (?) SnapList db SNAP_SIZE*LIST_SIZE dup (?) IRQ_mask db ? FlagPause db 0 WaveBase db 'WaveBase',0 WaveIRQ db 'WaveIRQ',0 WaveDMA db 'WaveDMA',0 WaveRate db 'WaveRate' Empty db 0 ifdef SBPRO OkIRQ db 0 Filter db ? endif ifdef GOLD Mixer_13 db ? Mixer_14 db ? Gold_IRQ db 3, 4, 5, 7, 10, 11, 12, 15 endif ifdef SB16 SB16_IRQ db 2, 5, 7, 10 endif EVEN ifdef MWSS MWSSFreq dw 11025, 3, 16000, 2, 18900, 5, 22050, 7 dw 27429, 4, 32000, 6, 33075, 0dh, 37800, 9 dw 44100, 0Bh MWSSIrq db 0, 0, 010000b, 0, 0, 0, 0, 001000b, 0, 010000b db 011000b, 100000b, 0, 0, 0, 0 MWSSDma db 01b, 10b, 0, 11b, 0, 0, 0, 0 endif Critical dw ? DoUpdate dw ? Old_RIRQ_Seg dw ? Old_PIRQ_Sel dw ? Old_18_Sel dw ? Old_RIRQ_Off dw ? ALIGN 4 Old_PIRQ_Off dd ? Old_18_Off dd ? ifdef GOLD ListNames dd offset WaveBase dd offset Empty elseifdef SB16 ListNames dd offset WaveBase dd offset WaveRate dd offset Empty elseifdef GUS ListNames dd offset WaveRate dd offset Empty elseifdef PAS ListNames dd offset WaveRate dd offset Empty else ListNames dd offset WaveBase dd offset WaveRate dd offset WaveIRQ dd offset WaveDMA dd offset Empty endif public Nolanguage PlayRate ListVars equ $ ifdef GOLD BASE_ADDR dd 388h ; By default 388h PlayRate dd 22000 ; By default 22 Khz IRQ_number dd ? ; no default (read card) DMA_number dd ? ; no default (read card) elseifdef SBLASTER BASE_ADDR dd 220h ; By default 220h PlayRate dd 22000 ; By default 22 Khz IRQ_number dd 5 ; By default 5 DMA_number dd 1 ; By default 1 elseifdef MWSS BASE_ADDR dd 540h ; By default 540h PlayRate dd 22000 ; By default 22 Khz IRQ_number dd 9 ; By default 9 DMA_number dd 1 ; By default 1 elseifdef GUS PlayRate dd 22000 ; By default 22 Khz elseifdef PAS PlayRate dd 22000 ; By default 22 Khz IRQ_number dd 0 ; no default DMA_number dd 0 ; no default else BASE_ADDR dd 0 ; no default PlayRate dd 22000 ; By default 22 Khz IRQ_number dd 0 ; no default DMA_number dd 0 ; no default endif INT_number dd 0Dh ; By default 0Dh public Nolanguage BufferHalf BufferHalf dd ? follow dd -1 backfollow dd -1 ifndef NOIRQ DMA dd offset DMA1 ; By default DMA1 endif weirdcount dd ? backweirdcount dd ? TheVolumeR dd ? TheVolumeL dd ? save_1 dd ? save_2 dd ? save_3 dd ? save_4 dd ? public Nolanguage BUFFER_DMA public Nolanguage CURRENT_BUFFER ifdef RAM_CARD BUFFER_DMA dd ? ; adress of the buffer R_BUFFER_CARD dd ? ; adress of the buffer on the card for Right channel MID_R_BUFFER_CARD dd ? ; adress of the mid buffer for Right channel CURRENT_R_BUFFER_CARD dd ? ; current half for Right channel L_BUFFER_CARD dd ? ; adress of the buffer on the card for Left channel MID_L_BUFFER_CARD dd ? ; adress of the mid buffer for Left channel CURRENT_L_BUFFER_CARD dd ? ; current half for Left channel else BUFFER_DMA dd ? ; adress of the buffer MID_BUFFER_DMA dd ? ; adress of the mid buffer CURRENT_BUFFER dd ? ; current half endif ifdef INTERRRUPT DMA_COUNT dd ? DMA_PTR dd ? endif ;---------------------------------------------------------------------------- IFDEF PAS MV_filter dd ? MV_xchannel dd ? DPMI_real_int LABEL BYTE ;DPMI real-mode interrupt structure int_DI dw ? ;*** MUST REMAIN CONTIGUOUS *** dw 0 int_SI dw ? dw 0 int_BP dw ? dw 0 dd 0 int_BX dw ? dw 0 int_DX dw ? dw 0 int_CX dw ? dw 0 int_AX dw ? dw 0 int_flags dw ? int_ES dw ? int_DS dw ? dw 0 dw 0 dw 0 dw 0 dw 0 dw 0 ENDIF ;*--------------------------------------------------------------------------* Redirector PROC int 18h iretd Redirector ENDP ;*--------------------------------------------------------------------------* setalc MACRO db 0D6h ENDM lve MACRO Reg, Exp lea Reg, [Exp] ENDM ;*--------------------------------------------------------------------------* GET_REAL_VECT MACRO mov ax, 0200h int 31h ENDM SET_REAL_VECT MACRO mov ax, 0201h int 31h ENDM GET_PROT_VECT MACRO mov ax, 0204h int 31h ENDM SET_PROT_VECT MACRO mov ax, 0205h int 31h ENDM CRIT_SECT MACRO ; Enter Critical Section ;-) mov word ptr[Critical], 1 ; tell the IRQ not to update the buffer ; we'll take care of it if nescessary O:-) ENDM END_CRIT_SECT MACRO ; Exit Critical Section O:-) local NoUpdate ; Update buffer if necessary ; Dealing with the critical section flags................ ; DO NOT TOUCH !!!! mov word ptr[Critical], 0 ; exit crit. sect. ; this way DoUpdate can't change to 1 anymore cmp word ptr[DoUpdate], 0 ; IRQ happened ? je NoUpdate ; if DopUpdate change to 0 now, we are in deep ; shit anyway because we missed one round! ; The program won't crash but we'll ear the old ; content of half a buffer and also miss half a buffer ; of new data... :-( mov word ptr[Critical], 1 ; yes, crit. again, so we don't update twice ; because UpdateBuffer is not reentrant ; and we don't want to take a chance on crashing! pushad ; if DoUpdate change to 1 HERE ; it means again that we missed one round! ; So we play the buffer we are updating! (funny noise :-( ) ; and then will ear half buffer of old data! call UpdateBuffer ; do the update popad mov word ptr[Critical], 0 ; exit crit. sect ; this way DoUpdate can't change to 1 anymore mov word ptr[DoUpdate], 0 ; Update done, so DoUpdate = 0 NoUpDate: ; ALL THOSE NASTY THING SHOULD NOT HAPPEN :-) !!!! ; BECAUSE IT WOULD MEAN THAT THE UPDATE OF THE BUFFER ; TAKES MORE THAN 46000 microsec! ; (at 33 Mhz one cycle = .03 microsec so 4600 microsec = 1.5 million cycle) ENDM ;*--------------------------------------------------------------------------* GetDMAAddr PROC USES EBX xor eax, eax ifndef NOIRQ mov ebx, dword ptr[DMA] cli mov dx, word ptr[ebx + PAGE_REG] in al, dx shl eax, 16 mov dx, word ptr[ebx + FF_REG] out dx, al ; Flip-Flop mov dx, word ptr[ebx + ADDX_REG] ; to get offset in al, dx mov ah, al in al, dx sti xchg al, ah cmp word ptr[DMA_number], 3 jbe noadjust lve eax, eax*2 noadjust: endif ret GetDMAAddr ENDP ;*--------------------------------------------------------------------------* ifndef NOIRQ NewIRQ PROC pushad push ds push es cld ; DAMN IT !! :-o local_DS equ $+2 mov ax, 1234h mov ds, ax ; restore DS mov es, ax ; and ES !!! call AckIrq pushf ifdef SINGLE_DMA jc notransfert call BlockTransfert ; call Ackirq ; security notransfert: endif mov al, 20h ; allows for new int cmp byte ptr[IRQ_number], 7 jbe short NoSecondCtrl out 0A0h, al NoSecondCtrl: out 20h, al popf jc short FinIRQ ; not a DMA IRQ mov eax, dword ptr[BufferHalf] xor al, 4 ; switch half mov byte ptr[BufferHalf], al ifdef RAM_CARD mov eax, dword ptr[R_BUFFER_CARD+eax]; get current card buffer address mov dword ptr[CURRENT_R_BUFFER_CARD], eax; update CURRENT_BUFFER_CARD else mov eax, dword ptr[BUFFER_DMA+eax] ; get current buffer address mov dword ptr[CURRENT_BUFFER], eax ; update CURRENT_BUFFER endif mov word ptr[DoUpdate], 1 ; Time to do the update cmp word ptr[Critical], 0 ; crit. sect ? jne FinIRQ ; yes, don't update yet! mov word ptr[Critical], 1 ; just to make jure it case the interrupt call UpdateBuffer ; happen again before its finished mov word ptr[Critical], 0 mov word ptr[DoUpdate], 0 ; Update done FinIRQ: pop es pop ds popad iretd NewIRQ ENDP endif ;*--------------------------------------------------------------------------* ifdef GUS PUBLIC Nolanguage UpdateBuffer PUBLIC Nolanguage DoUpdate PUBLIC Nolanguage Critical endif ;*--------------------------------------------------------------------------* UpdateBuffer PROC ifdef GUS push es pushf cld mov ax, ds mov es, ax endif mov eax, BUFFER_SIZE ifdef RAM_CARD mov edi, dword ptr[BUFFER_DMA] ; Buffer else mov edi, dword ptr[CURRENT_BUFFER] ; Buffer endif cmp byte ptr[FlagPause], 1 je short dopause lea ebx, CurrentList ; Point to List of samples mov esi, dword ptr[ebx] ; Current Source or esi, esi ; if 0 then empty list jnz process_1st dopause: mov ecx, (BUFFER_SIZE * SSIZE) / 4 MIDPOINT rep stosd mov al, byte ptr[FlagPause] and al, 1 mov byte ptr[FlagPause], al ifdef GUS popf pop es endif ret exit: mov al, byte ptr[FlagPause] dec al js reallyexit ifdef RAM_CARD mov edi, dword ptr[BUFFER_DMA] ; Buffer else mov edi, dword ptr[CURRENT_BUFFER] ; Buffer endif mov esi, ( BUFFER_SIZE * SSIZE ) / 4 bsr cx, si dec si ; no need to fade first/last sample ; since it will be multiplied by 1 dec al jnz short fadeout mov ebx, 1 ; skip 0 ifdef SAMPLE16BIT loopfadein: mov edx, dword ptr[edi] movsx eax, dx imul eax, ebx sar eax, cl sar edx, 16 imul edx, ebx sar edx, cl shl edx, 16 mov dx, ax mov dword ptr[edi], edx add edi, 4 inc bx dec si jnz short loopfadein else loopfadein: mov edx, dword ptr[edi] xor edx, 80808080h ; convert to signed REPT 2 movsx eax, dl imul eax, ebx sar eax, cl mov dl, al movsx eax, dh imul eax, ebx sar eax, cl mov dh, al rol edx, 16 ENDM xor edx, 80808080h ; back to unsigned mov dword ptr[edi], edx add edi, 4 inc bx dec si jnz short loopfadein endif xor al, al jmp short endfade fadeout: add edi, 4 ; skip first ifdef SAMPLE16BIT loopfadeout: mov edx, dword ptr[edi] movsx eax, dx imul eax, esi sar eax, cl sar edx, 16 imul edx, esi sar edx, cl shl edx, 16 mov dx, ax mov dword ptr[edi], edx add edi, 4 dec si jnz short loopfadeout else loopfadeout: mov edx, dword ptr[edi] xor edx, 80808080h ; convert to signed REPT 2 movsx eax, dl imul eax, esi sar eax, cl mov dl, al movsx eax, dh imul eax, esi sar eax, cl mov dh, al rol edx, 16 ENDM xor edx, 80808080h ; back to unsigned mov dword ptr[edi], edx add edi, 4 dec si jnz short loopfadeout endif mov al, 1 endfade: mov byte ptr[FlagPause], al reallyexit: ifdef GUS popf pop es endif ret FinishFill0: or ax, ax ; still some room in the buffer? jz Finish2 process_1st: mov cx, ax shl eax, 16 mov ax, cx ; eax = BUFFER_SIZE:BUFFER_SIZE mov dx, word ptr[ebx+FRACT] ; fractionnal Source mov bp, word ptr[ebx+INCR] ; fractionnal inc mov ecx, dword ptr[ebx+LEFT] ; length left cmp ecx, 0FFFFh ; length left to fill after sample ja Longer0 ; 64K or +, then more than the buffer sub ax, cx jae short NotLonger0 ; some left? Longer0: shr eax, 16 mov ecx, eax ; length = buffer_size sub dword ptr[ebx+LEFT], ecx ; reduce length left mov word ptr[save_4], 0 ; no room left jmp short StartMix0 NotLonger0: inc ax ; length + 1 (in case left = 0) mov word ptr[save_4], ax StartMix0: shl edx, 16 or ecx, edx ; hecx = FRACT shl ebp, 16 ; hebp = INCR ifdef SAMPLE16BIT mov edx, dword ptr[ebx+VOL_LEFT] ; read left & right volume ifdef STEREO cmp byte ptr[ebx+INTERPOL], 0 je nofilter mov dword ptr[save_3], ebx movsx eax, dx mov [TheVolumeL], eax sar edx, 16 mov [TheVolumeR], edx shr ebp, 16 ; BP = fract inc mov edx, ecx shr edx, 16 ; DX = fract rol ecx, 8 mov cl, [ebx+LAST_SAMPLE] ror ecx, 8 jmp short next0 start0: rol ecx, 8 mov cl, [esi] inc esi ror ecx, 8 next0: mov eax, ecx mov al, [esi] ; read data rol eax, 8 xor ax, 8080h ; 8 bit signed movsx ebx, al movsx eax, ah ; sign extension to 32 bit not dx inc edx imul ebx, edx dec edx not dx imul eax, edx add ebx, eax mov eax, ebx imul ebx, [TheVolumeR] ; Right imul eax, [TheVolumeL] ; Left sar eax, 16 mov bx, ax mov [edi], ebx ; store buffer content add edi, 4 ; next location add dx, bp ; update fractional part of address dec cx ; length-1, doesn't touch C but set Z ;-) ja short next0 ; if (not C) and (not Z) next jnz short start0 ; if some left, read a new one mov ebx, dword ptr[save_3] pushf rol ecx, 8 mov [ebx+LAST_SAMPLE], cl shl edx, 16 mov ecx, edx inc esi popf jmp short end16 nofilter: mov dword ptr[save_3], ebx start01: lodsb ; read new data xor al, 80h ; 8 bit signed movsx eax, al ; sign extension to 32 bit mov ebx, eax ; copy into ebx imul ax, dx ; ax = left imul ebx, edx mov bx, ax next01: mov dword ptr[edi], ebx ; write data add edi, 4 ; next location add ecx, ebp ; update fractional part of address dec cx ; length-1, doesn't touch C but set Z ;-) ja short next01 ; if (not C) and (not Z) next jnz short start01 ; if some left, read a new one mov ebx, dword ptr[save_3] end16: else start0: lodsb ; read new data xor al, 80h ; 8 bit signed movsx ax, al ; sign extension to 16 bit imul ax, dx ; ax = "volumed" sample next0: mov word ptr[edi], ax ; write data add edi, 2 ; next location add ecx, ebp ; update fractional part of address dec cx ; length-1, doesn't touch C but set Z ;-) ja short next0 ; if (not C) and (not Z) next jnz short start0 ; if some left, read a new one endif else ifdef STEREO mov dl, byte ptr[ebx+VOL_LEFT] or dl, dl jz short middle0 dec dl jz short left0 mov al, 80h ; "0" -> left r_start0: mov ah, byte ptr[esi] ; read new data -> right inc esi r_next0: mov word ptr[edi], ax ; write data add edi, 2 ; next location add ecx, ebp ; update fractional part of address dec cx ; length-1, doesn't touch C but set Z ;-) ja short r_next0 ; if (not C) and (not Z) next jnz short r_start0 ; if some left, read a new one jmp short end0 left0: mov ah, 80h ; "0" -> right l_start0: lodsb ; read new data -> left l_next0: mov word ptr[edi], ax ; write data add edi, 2 ; next location add ecx, ebp ; update fractional part of address dec cx ; length-1, doesn't touch C but set Z ;-) ja short l_next0 ; if (not C) and (not Z) next jnz short l_start0 ; if some left, read a new one jmp short end0 middle0: m_start0: lodsb ; read new data -> left mov ah, al ; data -> right m_next0: mov word ptr[edi], ax ; write data add edi, 2 ; next location add ecx, ebp ; update fractional part of address dec cx ; length-1, doesn't touch C but set Z ;-) ja short m_next0 ; if (not C) and (not Z) next jnz short m_start0 ; if some left, read a new one end0: else start0: lodsb ; read new data next0: mov byte ptr[edi], al ; write data inc edi ; next location add ecx, ebp ; update fractional part of address dec cx ; length-1, doesn't touch C but set Z ;-) ja short next0 ; if (not C) and (not Z) next jnz short start0 ; if some left, read a new one endif endif jc noadjust0 ; was a new data going to be read? dec esi ; no, last data will be read again noadjust0: mov ax, word ptr[save_4] ; left to copy or ax, ax jz Finish ; 0 normal end dec ax ; readjust size dec word ptr[ebx+C_REPEAT] ; repeat again? jnz Reset0 ; yes, then reset mov edx, dword ptr[ebx+SON] ; no, got a son? or edx, edx js short NoSon0 ; no, remove the sample lea esi, SonList ; yes, then find it KeepLooking0: cmp dword ptr[esi], 0 ; the end ? je short NoSon0 ; yes, then no son cmp edx, dword ptr[esi+HANDLE] ; this one? je short FoundSon0 ; yes, found! add esi, STRUCT_SIZE ; no, keep looking jmp short KeepLooking0 NoSon0: or ax, ax jz noclear xor ecx, ecx mov cx, ax ; clear rest of the buffer MIDPOINT IFDEF SCHAR mov edx, ecx and ecx, 3 ; up to 3 by byte rep stosb mov ecx, edx shr ecx, 2 ; the rest by dword ELSEIFDEF SUWORD shr ecx, 1 jnc short NoAdjustByOne stosw NoAdjustByOne: ENDIF rep stosd noclear: mov esi, ebx ; point where it is mov edi, ebx ; idem add esi, STRUCT_SIZE ; source one further LoopRemove0: cmp dword ptr[esi], 0 ; end ? je short EndRemove0 ; yes, exit mov ecx, STRUCT_SIZE / 4 ; trasnfert one struct rep movsd ; transfer jmp short LoopRemove0 EndRemove0: mov dword ptr[edi], 0 ; write 0 to mark the end jmp NextSample FoundSon0: mov ebp, esi ; save esi mov edx, edi ; save edi mov edi, ebx ; transfert at the location of the father mov ecx, STRUCT_SIZE / 4 ; count in dword rep movsd ; transfert mov esi, ebp ; remove son from SonList mov edi, ebp ; so, point to it add esi, STRUCT_SIZE ; source one further LoopSon0: cmp dword ptr[esi], 0 je short EndSon0 mov ecx, STRUCT_SIZE / 4 rep movsd ; transfer while not 0 jmp short LoopSon0 EndSon0: mov dword ptr[edi], 0 ; write 0 to mark the end mov edi, edx ; restore edi in the buffer mov esi, dword ptr[ebx+START] ; restore source, no need to write it jmp FinishFill0 Reset0: mov esi, dword ptr[ebx+START] ; restore source, no need to write it mov ebp, dword ptr[ebx+DLENGTH] ; restore length mov dword ptr[ebx+LEFT], ebp mov word ptr[ebx+FRACT], 0 jmp FinishFill0 NextSample: mov esi, dword ptr[ebx] ; Current Source or esi, esi ; if 0 then end of the list jz exit ifdef RAM_CARD mov edi, dword ptr[BUFFER_DMA] ; Buffer else mov edi, dword ptr[CURRENT_BUFFER] ; Buffer endif mov ax, BUFFER_SIZE FinishFill: or ax, ax ; still some room in the buffer? jz Finish2 mov cx, ax shl eax, 16 mov ax, cx ; eax = BUFFER_SIZE:BUFFER_SIZE mov dx, word ptr[ebx+FRACT] ; fractionnal Source mov bp, word ptr[ebx+INCR] ; fractionnal inc mov ecx, dword ptr[ebx+LEFT] ; length left cmp ecx, 0FFFFh ; length left to fill after sample ja Longer ; 64K or +, then more than the buffer sub ax, cx jae short NotLonger ; some left? Longer: shr eax, 16 ; no, restore buffer_size in ax mov ecx, eax ; length = buffer_size sub dword ptr[ebx+LEFT], ecx ; reduce length left mov word ptr[save_4], 0 ; no room left jmp short startMix00 NotLonger: inc ax ; length + 1 (in case left = 0) mov word ptr[save_4], ax StartMix00: shl edx, 16 or ecx, edx ; hecx = FRACT shl ebp, 16 ; hebp = INCR ifdef SAMPLE16BIT mov edx, dword ptr[ebx+VOL_LEFT] ifdef STEREO cmp byte ptr[ebx+INTERPOL], 0 je nofilter00 mov dword ptr[save_3], ebx movsx eax, dx mov [TheVolumeL], eax sar edx, 16 mov [TheVolumeR], edx shr ebp, 16 ; BP = fract inc mov edx, ecx shr edx, 16 ; DX = fract rol ecx, 8 mov cl, [ebx+LAST_SAMPLE] ror ecx, 8 jmp short next00 start00: rol ecx, 8 mov cl, [esi] inc esi ror ecx, 8 next00: mov eax, ecx mov al, [esi] ; read data rol eax, 8 xor ax, 8080h ; 8 bit signed movsx ebx, al movsx eax, ah ; sign extension to 32 bit not dx inc edx imul ebx, edx dec edx not dx imul eax, edx add ebx, eax mov eax, ebx imul ebx, [TheVolumeR] ; Right imul eax, [TheVolumeL] ; Left sar eax, 16 mov bx, ax add [edi], ebx ; store buffer content add edi, 4 ; next location add dx, bp ; update fractional part of address dec cx ; length-1, doesn't touch C but set Z ;-) ja short next00 ; if (not C) and (not Z) next jnz short start00 ; if some left, read a new one mov ebx, dword ptr[save_3] pushf rol ecx, 8 mov [ebx+LAST_SAMPLE], cl shl edx, 16 mov ecx, edx inc esi popf jmp short end016 nofilter00: mov dword ptr[save_3], ebx start001: lodsb ; read new data xor al, 80h ; 8 bit signed movsx eax, al ; sign extension to 32 bit mov ebx, eax ; copy into ebx imul ax, dx ; ax = left imul ebx, edx mov bx, ax next001: add dword ptr[edi], ebx ; write data add edi, 4 ; next location add ecx, ebp ; update fractional part of address dec cx ; length-1, doesn't touch C but set Z ;-) ja short next001 ; if (not C) and (not Z) next jnz short start001 ; if some left, read a new one mov ebx, dword ptr[save_3] end016: else start00: lodsb ; read new data xor al, 80h ; 8 bit signed movsx ax, al ; sign extension to 16 bit imul ax, dx ; ax = "volumed" sample next00: add word ptr[edi], ax ; add with buffer content add edi, 2 ; next location add ecx, ebp ; update fractional part of address dec cx ; length-1, doesn't touch C but set Z ;-) ja short next00 ; if (not C) and (not Z) next jnz short start00 ; if some left, read a new one endif else ifdef STEREO mov dl, byte ptr[ebx+VOL_LEFT] or dl, dl jz short middle00 dec dl jz short left00 inc edi ; go right r_start00: lodsb ; read new data mov ah, al ; save it in ah r_next00: add al, byte ptr[edi] ; add with buffer content rcr al, 1 ; average mov byte ptr[edi], al ; write result back add edi, 2 ; next location mov al, ah ; restore data add ecx, ebp ; update fractional part of address dec cx ; length-1, doesn't touch C but set Z ;-) ja short r_next00 ; if (not C) and (not Z) next jnz short r_start00 ; if some left, read a new one dec edi ; go back left jmp short end00 left00: l_start00: lodsb ; read new data mov ah, al ; save it in ah l_next00: add al, byte ptr[edi] ; add with buffer content rcr al, 1 ; average mov byte ptr[edi], al ; write result back add edi, 2 ; next location mov al, ah ; restore data add ecx, ebp ; update fractional part of address dec cx ; length-1, doesn't touch C but set Z ;-) ja short l_next00 ; if (not C) and (not Z) next jnz short l_start00 ; if some left, read a new one jmp short end00 middle00: m_start00: lodsb ; read new data m_next00: mov dx, word ptr[edi] ; read buffer, left & right add dl, al ; average with left rcr dl, 1 add dh, al ; average with right rcr dh, 1 mov word ptr[edi], dx ; write result back add edi, 2 ; next location add ecx, ebp ; update fractional part of address dec cx ; length-1, doesn't touch C but set Z ;-) ja short m_next00 ; if (not C) and (not Z) next jnz short m_start00 ; if some left, read a new one end00: else start00: lodsb ; read new data mov ah, al ; save it in ah next00: add al, byte ptr[edi] ; add with buffer content rcr al, 1 ; average adc al, 0 mov byte ptr[edi], al ; write result back inc edi ; next location mov al, ah ; restore data add ecx, ebp ; update fractional part of address dec cx ; length-1, doesn't touch C but set Z ;-) ja short next00 ; if (not C) and (not Z) next jnz short start00 ; if some left, read a new one endif endif jc noadjust ; was a new data going to be read? dec esi ; no, last data will be read again noadjust: mov ax, word ptr[save_4] ; left to copy or ax, ax jz short Finish ; 0 normal end dec ax ; readjust size dec word ptr[ebx+C_REPEAT] ; repeat again? jnz short Reset ; yes, then reset mov edx, dword ptr[ebx+SON] ; no, got a son? or edx, edx js short NoSon ; no, remove the sample lea esi, SonList ; yes, then find it KeepLooking: cmp dword ptr[esi], 0 ; the end ? je short NoSon ; yes, then no son cmp edx, dword ptr[esi+HANDLE] ; this one? je short FoundSon ; yes, found! add esi, STRUCT_SIZE ; no, keep looking jmp short KeepLooking NoSon: ; remove it mov esi, ebx ; point where it is mov edi, ebx ; idem add esi, STRUCT_SIZE ; source one further LoopRemove: cmp dword ptr[esi], 0 ; end ? je short EndRemove ; yes, exit mov ecx, STRUCT_SIZE / 4 ; trasnfert one struct rep movsd ; transfer jmp short LoopRemove EndRemove: mov dword ptr[edi], 0 ; write 0 to mark the end jmp NextSample FoundSon: mov ebp, esi ; save esi mov edx, edi ; save edi mov edi, ebx ; transfert at the location of the father mov ecx, STRUCT_SIZE / 4 ; count in dword rep movsd ; transfert mov esi, ebp ; remove son from SonList mov edi, ebp ; so, point to it add esi, STRUCT_SIZE ; source one further LoopSon: cmp dword ptr[esi], 0 je short EndSon mov ecx, STRUCT_SIZE / 4 rep movsd ; transfer while not 0 jmp short LoopSon EndSon: mov dword ptr[edi], 0 ; write 0 to mark the end mov edi, edx ; restore edi in the buffer mov esi, dword ptr[ebx+START] ; restore source, no need to write it jmp FinishFill Finish: shr ecx, 16 mov word ptr[ebx+FRACT], cx ; save fractional part Finish2: mov dword ptr[ebx], esi ; save current address add ebx, STRUCT_SIZE ; point to next sample jmp NextSample Reset: mov esi, dword ptr[ebx+START] ; restore source, no need to write it mov ebp, dword ptr[ebx+DLENGTH] ; restore length mov dword ptr[ebx+LEFT], ebp mov word ptr[ebx+FRACT], 0 jmp FinishFill UpdateBuffer ENDP ;*--------------------------------------------------------------------------* StopSample PROC CRIT_SECT xor eax, eax mov dword ptr[CurrentList], eax mov dword ptr[SonList], eax mov byte ptr[FlagPause], al dec eax mov dword ptr[follow], eax ; -1 mov dword ptr[weirdcount], 10000h END_CRIT_SECT ret StopSample ENDP ;*--------------------------------------------------------------------------* StopOneSample PROC USES EBX ESI EDI,\ thehandle:DWORD push -1 ; end of recursion mov eax, thehandle lea edx, CurrentList mov ebx, edx CRIT_SECT keeplooking: cmp dword ptr[ebx], 0 je short exit cmp ax, word ptr[ebx+HANDLE] je short found add ebx, STRUCT_SIZE jmp short keeplooking exit: lea ebx, SonList cmp edx, ebx mov edx, ebx jne short keeplooking pop eax ; get "son" or eax, eax jns short keeplooking ; less than #2 billions samples ! END_CRIT_SECT ret found: mov ecx, dword ptr[ebx+SON] or ecx, ecx js short noson push ecx ; "son" to be removed noson: mov esi, ebx mov edi, ebx add esi, STRUCT_SIZE LoopRemove: cmp dword ptr[esi], 0 je short EndRemove mov ecx, STRUCT_SIZE / 4 rep movsd jmp short LoopRemove EndRemove: mov dword ptr[edi], 0 jmp short keeplooking StopOneSample ENDP ;---------------------------------------------------------------------------- ShiftSamples PROC USES ESI EDI EBX,\ DestAddr:DWORD, SrcAddr:DWORD, SizeByte:DWORD lea edx, CurrentList mov esi, SrcAddr ; Source mov eax, esi ; save Source for comparison mov edi, DestAddr ; Destination mov ecx, SizeByte ; number of bytes to move mov bl, cl ; compute counters shr ecx, 2 and bl, 3 CRIT_SECT rep movsd ; move the data mov cl, bl rep movsb sub edi, esi ; shift (delta addr) mov ebx, edx keeplooking: cmp dword ptr[ebx], 0 je short exit cmp eax, [ebx+START] ja short notfound add [ebx+START], edi add [ebx], edi notfound: add ebx, STRUCT_SIZE jmp short keeplooking exit: lea ebx, SonList cmp edx, ebx mov edx, ebx jne short keeplooking END_CRIT_SECT ret ShiftSamples ENDP ;---------------------------------------------------------------------------- StopOneSampleLong PROC USES ESI EDI,\ LongHandle:DWORD mov eax, LongHandle CRIT_SECT call SearchLongHandle or edx, edx jz short notfound mov esi, edx mov edi, edx add esi, STRUCT_SIZE LoopRemove: cmp dword ptr[esi], 0 je short EndRemove mov ecx, STRUCT_SIZE / 4 rep movsd jmp short LoopRemove EndRemove: mov dword ptr[edi], 0 notfound: END_CRIT_SECT ret StopOneSampleLong ENDP ;*--------------------------------------------------------------------------* SampleInList PROC USES EBX,\ thehandle:DWORD CRIT_SECT mov edx, thehandle mov eax, 1 ; True lea ecx, CurrentList mov ebx, ecx keeplooking: cmp dword ptr[ebx], 0 je short exit cmp dx, word ptr[ebx+HANDLE] je short found add ebx, STRUCT_SIZE jmp short keeplooking exit: lea ebx, SonList cmp ecx, ebx mov ecx, ebx jne keeplooking xor eax, eax ; False found: END_CRIT_SECT ret SampleInList ENDP ;*--------------------------------------------------------------------------* SearchLongHandle PROC lea edx, CurrentList lea ecx, SonList keeplooking: cmp dword ptr[edx], 0 je short exit cmp eax, dword ptr[edx+HANDLE] je short found add edx, STRUCT_SIZE jmp short keeplooking exit: cmp edx, ecx mov edx, ecx jne keeplooking xor edx, edx found: ret SearchLongHandle ENDP ;*--------------------------------------------------------------------------* ChangeVolume PROC \ LongHandle:DWORD, volleft:DWORD, volright:DWORD ifdef STEREO ifdef SAMPLE16BIT mov eax, LongHandle CRIT_SECT call SearchLongHandle or edx, edx jz short notfound mov eax, volleft shr eax, SHIFT_SAMPLE - 1 ; Preshift according to number of channels mov word ptr[edx+VOL_LEFT], ax mov eax, volright shr eax, SHIFT_SAMPLE - 1 ; Preshift according to number of channels ifdef SURROUND neg eax endif mov word ptr[edx+VOL_RIGHT], ax notfound: END_CRIT_SECT else mov eax, LongHandle CRIT_SECT call SearchLongHandle or edx, edx jz short notfound push edi mov edi, edx mov cx, word ptr[volleft] or cx, cx jnz short okleft mov cx, 2 ; if volleft = 0 then right jmp short storepos okleft: mov ax, word ptr[volright] shl ax, 7 ; * 128 xor dx, dx div cx mov cx, 2 ; right cmp ax, 74 ; .577 (= tan 30) * 128 jb short storepos dec cx ; left cmp ax, 222 ; 1.732 (= tan 60) * 128 jae short storepos dec cx ; middle storepos: mov word ptr[edi+VOL_LEFT], cx ; Store position (0:middle, 1:left, 2:right) pop edi notfound: END_CRIT_SECT endif else ifdef SAMPLE16BIT mov eax, LongHandle CRIT_SECT call SearchLongHandle or edx, edx jz short notfound push edi push ebx mov edi, edx mov eax, volleft imul eax, eax mov ecx, volright imul ecx, ecx add eax, ecx call sqr2 shr eax, SHIFT_SAMPLE - 1 ; Preshift according to number of channels mov word ptr[edi+VOL_LEFT], ax ; VOL_LEFT = sqr(volleft^2 + volright^2) pop ebx pop esi notfound: END_CRIT_SECT endif endif ret ChangeVolume ENDP ifdef SAMPLE16BIT ifndef STEREO ;*--------------------------------------------------------------------------* ; EAX = Sqr(EAX) Sqr2 PROC cmp eax, 3 ; if eax <= 3 then jbe short asqr_0_1 ; square root is 0 or 1 xor edx, edx ; clear edx mov ebx, eax ; copy eax into ebx so that ; edx:ebx are used "like" a 64 bit ; register bsr eax, ebx ; position of last 1 of ebx in eax mov cl, 33 ; compute how many left shift sub cl, al ; are needed in order to have the and cl, 11111110b ; most significant 2 bit pair at the ; leftmost position of edx shld edx, ebx, cl ; shift edx:ebx by the number shl ebx, cl ; computed above mov ecx, eax ; compute in ecx how many pairs of shr ecx, 1 ; 2 bit are left to be processed mov eax, 1 ; eax = 1 dec edx ; edx = edx - 1 asqr_loop: shld edx, ebx, 2 ; edx:ebx << 2 shl ebx, 2 ; lve eax, eax*2 ; eax * 2 cmp edx, eax ; compare edx and eax jb short asqr_neg ; if edx> 1 dec ecx ; one less pair to process jnz short asqr_loop ; if there is some left then go asqr_loop ret ; return to caller asqr_0_1: or eax, eax ; if eax = 0 jz short asqr_00 ; then return to caller mov eax, 1 ; else eax = 1 asqr_00: ret ; return to caller Sqr2 ENDP endif endif ;*--------------------------------------------------------------------------* MixSample PROC USES ESI EDI EBX,\ thehandle:DWORD, pitchbend:DWORD, therepeat:DWORD,\ plug:DWORD, volleft:DWORD, volright:DWORD,\ buffer:DWORD; buffer with .VOC mov esi, buffer xor eax, eax mov al, [esi] inc al cmp al, 10 jb okfilter xor eax, eax okfilter: push eax movzx eax, word ptr[esi+14h] add esi, eax ; skip header cmp byte ptr[esi], 1 ; only 1 bloc type allowed jne typeunknown cmp byte ptr[esi + 5], 0 ; pack method jne typeunknown ; This crap should be removed by using a file format containing the ; real sampling frequency instead of that stupid sr number in .VOC ! ; :-( mov dx, 0Fh mov ax, 4240h ; dx:ax = 1000000 xor ebx, ebx mov bl, byte ptr[esi + 4] ; bl = sr neg bl ; bl = 256 - sr div bx shl dx, 1 adc ax, 0 ; round to nearest mov bx, ax ; ebx = real sampling rate ; up to here ! and then avoid this ^ div ! mov eax, dword ptr[esi + 1] ; size sample and eax, 0FFFFFFh ; 24 significant bits sub eax, 2 ; -2 header add esi, 6 ; esi->data mov dword ptr[save_1], esi ; save it mov edx, pitchbend shl edx, 4 imul ebx, edx shr ebx, 16 adc bx, 0 ; ebx = scaled sampling rate xor edx, edx xchg eax, ebx ; edx = 0, eax = sr, ebx = size xchg edx, eax ; edx = sr, eax = 0, ebx = size div word ptr[PlayRate] ; dx:ax / PlayRate; ax = INCR cmp eax, 0FFFFh jbe okincr mov eax, 0FFFFh okincr: mov dword ptr[save_2], eax ; save_2 = INCR mov ecx, ebx ; ecx = size mov esi, ebx shr esi, 16 ; esi = hi(size) mov edx, esi xchg eax, ebx ; eax = size, ebx = INCR dec eax ; A TRY !!!! (will make loop around next longer...) shl eax, 16 div ebx ; div 64 bits !!! sub eax, esi ; sub max roundoff error mov esi, eax ; esi = eax = new size mul ebx ; remultiply mov bx, ax ; FRACT in bx shrd eax, edx, 16 ; size in eax mov dx, word ptr[save_2] ; INCR in dx sub ecx, eax ; how much am I off? jbe typeunknown ; security, should not happen! next: inc esi ; length + 1 add bx, dx ; update fractional part of address jnc short next ; if (not C) next dec cx jnz short next ; not right yet, loop mov eax, dword ptr[follow] lea ebx, CurrentList mov edi, ebx mov cx, word ptr[thehandle] IFNDEF SAMPLE16BIT cmp cx, VOICE_HANDLE jne ok_handle push eax push ecx push edx call StopSample pop edx pop ecx pop eax ok_handle: ENDIF or ecx, dword ptr[weirdcount] ; why not ? inc word ptr[weirdcount+2] CRIT_SECT cmp plug, 0 je NoPlug lea edi, SonList keeplooking0: cmp dword ptr[ebx], 0 je short SearchSonList cmp eax, dword ptr[ebx+HANDLE] ; look for the "father" sample je short found add ebx, STRUCT_SIZE jmp short keeplooking0 SearchSonList: lea ebx, SonList keeplooking1: cmp dword ptr[ebx], 0 je short Exit cmp eax, dword ptr[ebx+HANDLE] ; look for the "father" sample je short found add ebx, STRUCT_SIZE jmp short keeplooking1 exit: xor eax, eax jmp endcritical found: mov dword ptr[ebx+SON], ecx ; connect it to ist "son" NoPlug: lea ebx, [edi+STRUCT_SIZE*LIST_SIZE] xor eax, eax sub edi, STRUCT_SIZE SearchEnd: add edi, STRUCT_SIZE cmp eax, dword ptr[edi] jne short SearchEnd cmp edi, ebx jae typeunknown mov dword ptr[follow], ecx ; update follow mov dword ptr[edi+HANDLE], ecx ; sample handle mov cx, word ptr[therepeat] mov word ptr[edi+C_REPEAT], cx ; Repeat mov dword ptr[edi+LEFT], esi ; length mov dword ptr[edi+DLENGTH], esi ; length mov eax, dword ptr[save_1] mov dword ptr[edi], eax ; Start mov dword ptr[edi+START], eax ; Start mov eax, dword ptr[save_2] mov word ptr[edi+INCR], ax ; increment mov dword ptr[edi+FRACT], 10000h ; fractional (with 1 above so != 0) mov dword ptr[edi+SON], -1 ; son mov dword ptr[edi+INFO0], -1 ; info0 pop eax mov [edi+INTERPOL], al ; filter on/off mov byte ptr[edi+LAST_SAMPLE], 80h ; 80h ( 0 ) ifdef STEREO ifdef SAMPLE16BIT mov eax, volleft shr eax, SHIFT_SAMPLE - 1 ; Preshift according to number of channels mov word ptr[edi+VOL_LEFT], ax mov eax, volright shr eax, SHIFT_SAMPLE - 1 ; Preshift according to number of channels ifdef SURROUND neg eax endif mov word ptr[edi+VOL_RIGHT], ax else mov si, 2 ; right mov ecx, volleft or ecx, ecx jz short storepos okleft: mov eax, volright shl eax, 7 ; * 128 xor edx, edx div ecx cmp eax, 74 ; 1.732 (= tan 60) * 128 jb short storepos dec si ; left cmp eax, 222 ; .577 (= tan 30) * 128 jae short storepos dec si ; middle storepos: mov word ptr[edi+VOL_LEFT], si ; Store position (0:middle, 1:left, 2:right) mov word ptr[edi+VOL_RIGHT], 1 ; to fill with non 0 endif else ifdef SAMPLE16BIT mov eax, volleft imul eax, eax mov ecx, volright imul ecx, ecx add eax, ecx call sqr2 shr eax, SHIFT_SAMPLE - 1 ; Preshift according to number of channels mov word ptr[edi+VOL_LEFT], ax ; VOL_LEFT = sqr(volleft^2 + volright^2) mov word ptr[edi+VOL_RIGHT], 1 ; to fill with non 0 else mov dword ptr[edi+VOL_LEFT], 1 ; to fill with non 0 endif endif mov dword ptr[edi+STRUCT_SIZE], 0 ; mark end of List mov eax, dword ptr[follow] endcritical: END_CRIT_SECT ret typeunknown: pop eax xor eax, eax ret MixSample ENDP ;*--------------------------------------------------------------------------* ifdef SINGLE_DMA BlockTransfert PROC push ebx mov ecx, BUFFER_SIZE * SSIZE cmp word ptr[DMA_number], 3 jbe noLengthAdj shr ecx, 1 NoLengthAdj: dec ecx ; buffer size - 1 mov ebx, dword ptr[DMA] ; Point to DMAx mov dx, word ptr[ebx + MASK_REG] mov al, byte ptr[ebx + MASK2] ; mask channel out dx, al mov dx, word ptr[ebx + FF_REG] out dx, al ; flip-flop mov dx, word ptr[ebx + COUNT_REG] mov al, cl ; buffer size - 1 out dx, al mov al, ch out dx, al mov dx, word ptr[ebx + ADDX_REG] mov eax, dword ptr[BufferHalf] mov eax, dword ptr[BUFFER_DMA+eax] ; start offset cmp word ptr[DMA_number], 3 jbe noAddrAdj shr eax, 1 NoAddrAdj: out dx, al shr eax, 8 out dx, al mov dx, word ptr[ebx + PAGE_REG] shr eax, 8 ; page of DMA transfert out dx, al mov dx, word ptr[ebx + MODE_REG] mov al, byte ptr[ebx + VOICE_OUT] ; output sample out dx, al mov dx, word ptr[ebx + MASK_REG] mov al, byte ptr[ebx + MASK1] ; channel OK out dx, al pop ebx jmp StartDMACard BlockTransfert ENDP endif ;*--------------------------------------------------------------------------* PauseSample PROC xor eax, eax CRIT_SECT mov al, byte ptr[FlagPause] dec al and al, 10b or al, 01b ; 0->3, 1->1, 2->1, 3->3 mov byte ptr[FlagPause], al shr eax, 1 xor al, 1 END_CRIT_SECT ret PauseSample ENDP ;*--------------------------------------------------------------------------* ContinueSample PROC xor eax, eax CRIT_SECT mov al, byte ptr[FlagPause] inc al and al, 10b ; 0->0, 1->2, 2->2, 3->0 mov byte ptr[FlagPause], al shr eax, 1 xor al, 1 END_CRIT_SECT ret ContinueSample ENDP ;---------------------------------------------------------------------------- ifndef NOIRQ InstallISR PROC push edx mov bl, byte ptr[INT_number] ; plug ISR on user INT mov cx, cs SET_PROT_VECT pop edx cmp dword ptr[IRQ_number], 7 ; if IRQ > 7 jbe nobi mov bl, 18h ; plug as well on int 18h mov cx, cs SET_PROT_VECT mov bl, byte ptr[INT_number] ; plug into real usr INT mov ecx, offset Redirector mov dx, cx ; compute real-mode xor cx, cx ; seg:ofs shr ecx, 4 SET_REAL_VECT nobi: ret InstallISR ENDP endif ;---------------------------------------------------------------------------- InitCard PROC USES EBX EDI ESI EBP,\ Buffer:DWORD ifndef NOIRQ mov word ptr[local_DS], ds endif mov eax, Buffer mov dword ptr[BUFFER_DMA], eax ifndef SBPRO call ResetCard endif ifndef NOIRQ xor eax, eax mov ax, word ptr[DMA_number] cmp ax, 7 ja short ErrorDMA mov eax, dword ptr[TAB_DMA+eax*4] or eax, eax jnz short DMAFound ErrorDMA: xor eax, eax ret DMAFound: mov dword ptr[DMA], eax mov eax, dword ptr[IRQ_number] cmp al, 7 ja short Second add al, 8 jmp short gotvect Second: add al, 70h - 8 gotvect: mov dword ptr[INT_number], eax ; save user int mov bl, al GET_PROT_VECT mov word ptr[Old_PIRQ_Sel], cx mov dword ptr[Old_PIRQ_Off], edx cmp dword ptr[IRQ_number], 7 jbe nobi mov bl, byte ptr[INT_number] ; if IRQ>7 save real vect GET_REAL_VECT mov word ptr[Old_RIRQ_Seg], cx mov word ptr[Old_RIRQ_Off], dx mov bl, 18h ; if IRQ>7 save int 18h GET_PROT_VECT mov word ptr[Old_18_Sel], cx mov dword ptr[Old_18_Off], edx nobi: mov dx, 21h ; IRQ mask reg mov cx, word ptr[IRQ_number] cmp cx, 7 jbe short Ok21 mov dx, 0A1h ; reg A1h, 2nd ctrl Ok21: in al, dx mov byte ptr[IRQ_mask], al ; save mask and cl, 7 mov bl, 1 shl bl, cl not bl and al, bl ; unmask IRQ out dx, al ; write new mask ifdef SBPRO call ResetCard endif mov edx, offset NewIRQ call InstallISR endif call StopSample ; to reset everything xor eax, eax mov dword ptr[BackCurrentList], eax mov dword ptr[BackSonList], eax mov edi, dword ptr[BUFFER_DMA] mov eax, edi add eax, BUFFER_SIZE * SSIZE mov dword ptr[MID_BUFFER_DMA], eax ; init pointer mov dword ptr[CURRENT_BUFFER], eax ; init pointer mov dword ptr[BufferHalf], 4 ; point on second half mov ecx, (BUFFER_SIZE * 2 * SSIZE) / 4; clear all buffer MIDPOINT rep stosd ifndef NOIRQ ifdef AUTO_DMA mov ecx, BUFFER_SIZE * 2 * SSIZE cmp word ptr[DMA_number], 3 jbe noLengthAdj shr ecx, 1 NoLengthAdj: dec ecx mov ebx, dword ptr[DMA] ; Point to DMAx mov dx, word ptr[ebx + MASK_REG] mov al, byte ptr[ebx + MASK2] ; mask channel out dx, al mov dx, word ptr[ebx + FF_REG] out dx, al ; flip-flop mov dx, word ptr[ebx + COUNT_REG] mov al, cl ; buffer size - 1 out dx, al mov al, ch out dx, al mov dx, word ptr[ebx + ADDX_REG] mov eax, dword ptr[BUFFER_DMA] ; start offset cmp word ptr[DMA_number], 3 jbe noAddrAdj shr eax, 1 mov di, ax xor ax, ax shl eax, 1 mov ax, di NoAddrAdj: out dx, al shr eax, 8 out dx, al mov dx, word ptr[ebx + PAGE_REG] shr eax, 8 ; page of DMA transfert out dx, al mov dx, word ptr[ebx + MODE_REG] mov al, byte ptr[ebx + AUTO_OUT] ; output sample out dx, al mov dx, word ptr[ebx + MASK_REG] mov al, byte ptr[ebx + MASK1] ; channel OK out dx, al endif endif ifdef AUTO_DMA call StartDMACard elseifdef SINGLE_DMA call BlockTransfert ; Start DMA transfert endif mov eax, 1 ret InitCard ENDP ;---------------------------------------------------------------------------- ClearCard PROC USES EBX ESI EDI EBP call StopSample ; just in case something was playing... call CloseCard ifndef NOIRQ mov dx, 21h ; read IRQ mask cmp word ptr[IRQ_number], 7 jbe short Ok21 add dx, 80h ; reg 0A1h Ok21: mov al, byte ptr[IRQ_mask] ; get old mask out dx, al ; write old IRQ mask mov bl, byte ptr[INT_number] mov cx, word ptr[Old_PIRQ_sel] mov edx, dword ptr[Old_PIRQ_off] SET_PROT_VECT cmp dword ptr[IRQ_number], 7 jbe nobi mov bl, byte ptr[INT_number] mov cx, word ptr[Old_RIRQ_seg] mov dx, word ptr[Old_RIRQ_off] SET_REAL_VECT mov bl, 18h mov cx, word ptr[Old_18_sel] mov edx, dword ptr[Old_18_off] SET_PROT_VECT nobi: endif ret ClearCard ENDP ;---------------------------------------------------------------------------- AskVars PROC ,\ pListNames:DWORD, pListVars:DWORD mov eax, offset ListNames mov ecx, pListNames mov dword ptr[ecx], eax mov eax, offset ListVars mov ecx, pListVars mov dword ptr[ecx], eax ret AskVars ENDP ;---------------------------------------------------------------------------- GetBufferSize PROC mov eax, BUFFER_SIZE * 2 * SSIZE ret GetBufferSize ENDP ;---------------------------------------------------------------------------- GiveSampleInfo0 PROC \ LongHandle:DWORD, Info:DWORD mov eax, LongHandle CRIT_SECT call SearchLongHandle or edx, edx jz short notfound mov eax, Info mov dword ptr[edx+INFO0], eax notfound: END_CRIT_SECT ret GiveSampleInfo0 ENDP ;---------------------------------------------------------------------------- GetSnapSample PROC USES EBX,\ pList:DWORD lea eax, SnapList mov edx, pList mov dword ptr[edx], eax lea edx, CurrentList lea ecx, SonList CRIT_SECT keeplooking: cmp dword ptr[edx], 0 je short exit mov ebx, dword ptr[edx+HANDLE] mov dword ptr[eax], ebx mov ebx, dword ptr[edx+INFO0] mov dword ptr[eax+4], ebx mov ebx, dword ptr[edx] sub ebx, dword ptr[edx+START] mov dword ptr[eax+8], ebx add eax, 12 add edx, STRUCT_SIZE jmp short keeplooking exit: cmp ecx, edx mov edx, ecx jne keeplooking END_CRIT_SECT sub eax, offset SnapList shr eax, 3 ret GetSnapSample ENDP ;---------------------------------------------------------------------------- CopyList PROC keepcopying: cmp dword ptr[esi], 0 je short endcopy mov ecx, STRUCT_SIZE / 4 rep movsd jmp short keepcopying endcopy: mov dword ptr[edi], 0 ret CopyList ENDP ;---------------------------------------------------------------------------- SAveStateSample PROC USES ESI EDI call PauseSample waitpause: cmp byte ptr[FlagPause], 1 jne short waitpause CRIT_SECT lea esi, CurrentList ; backup CurrentList lea edi, BackCurrentList call CopyList lea esi, SonList ; backup SonList lea edi, BackSonList call CopyList mov eax, dword ptr[follow] ; Backup follow mov dword ptr[backfollow], eax mov eax, dword ptr[weirdcount] ; Backup weirdcount mov dword ptr[backweirdcount], eax xor eax, eax ; empty both lists mov dword ptr[CurrentList], eax mov dword ptr[SonList], eax mov byte ptr[FlagPause], 0 END_CRIT_SECT ret SAveStateSample ENDP ;---------------------------------------------------------------------------- RestoreStateSample PROC USES ESI EDI call PauseSample waitpause: cmp byte ptr[FlagPause], 1 jne short waitpause CRIT_SECT lea esi, BackCurrentList ; restore CurrentList lea edi, CurrentList call CopyList lea edi, BackSonList ; restore SonList lea edi, SonList call CopyList mov eax, dword ptr[backfollow] ; restore follow mov dword ptr[follow], eax mov eax, dword ptr[backweirdcount] ; restore weirdcount mov eax, dword ptr[weirdcount] END_CRIT_SECT call ContinueSample waitcontinue: cmp byte ptr[FlagPause], 0 jne short waitcontinue ret RestoreStateSample ENDP ;---------------------------------------------------------------------------- ;---------------------------------------------------------------------------- ifdef PAS INT2F PROC\ ;Perform DPMI call to real-mode INT 2F USES esi edi\ ;for Pro Audio Spectrum driver access ,regAX,regBX mov ax,WORD PTR [regAX] mov int_AX,ax mov ax,WORD PTR [regBX] mov int_BX,ax mov int_DS,0 mov int_ES,0 pushf pop ax mov int_flags,ax mov eax,0300h mov ebx,002fh mov ecx,0 mov edi,OFFSET DPMI_real_int int 31h mov ax,int_AX mov bx,int_BX mov cx,int_CX mov dx,int_DX ret INT2F ENDP ;---------------------------------------------------------------------------- ResetCard PROC USES EBX mov eax,0bc04h ;get current DMA and IRQ settings invoke INT2F,eax,eax and ebx,0ffh and ecx,0ffh mov [DMA_number],ebx mov [IRQ_number],ecx mov eax,0bc07h ;get state table entries invoke INT2F,eax,eax xor eax,eax ;update local state table mov al,bh mov MV_xchannel,eax mov al,ch mov MV_filter,eax mov eax, MV_xchannel mov edx, CROSSCHANNEL ;disable DRQs from PAS IFDEF SAMPLE16BIT and eax, 00110000b ;and disable PCM state machine or eax, 00001001b ELSE and eax, 00110000b ;and disable PCM state machine or eax, 00000110b ENDIF out dx, al mov MV_xchannel, eax mov edx, PCMDATA ;silence PCM output mov al, 80h out dx, al mov edx, SYSCONF in al, dx IFDEF SAMPLE16BIT or al, 100b ELSE and al, 11111011b ENDIF out dx, al mov ecx, [PlayRate] shl ecx, 1 xor edx, edx mov eax, 1193180 div ecx mov ecx, eax mov al, 00110110b ;timer 0, square wave, binary mode mov edx, TMRCTLR out dx, al mov edx, SAMPLERATE mov al, cl out dx, al jmp $+2 mov al, ch out dx, al mov edx,INTRCTLRST ;enable IRQs on sample buffer empty out dx,al jmp $+2 in al,dx mov edx,INTRCTLR in al,dx or eax,00001000b out dx,al ret ResetCard ENDP ;---------------------------------------------------------------------------- CloseCard PROC mov eax,MV_xchannel mov edx,CROSSCHANNEL ;disable DRQs from PAS and eax,00111111b ;and disable PCM state machine out dx,al mov MV_xchannel,eax ret CloseCard ENDP ;---------------------------------------------------------------------------- StartDMACard PROC mov eax,MV_xchannel mov edx,CROSSCHANNEL or eax,10000000b ;secure the DMA channel out dx,al mov MV_xchannel,eax mov cx, BUFFER_SIZE * SSIZE mov eax,01110100b ;program sample buffer counter mov edx,TMRCTLR out dx,al mov edx,SAMPLECNT mov al,cl out dx,al jmp $+2 mov al,ch out dx,al mov al,BYTE PTR MV_xchannel and al,00001111b ;reset PCM state machine or al,10010000b mov edx,CROSSCHANNEL out dx,al jmp $+2 or al,01000000b out dx,al mov BYTE PTR MV_xchannel,al ; mov eax,MV_filter ; or eax,11000000b mov eax,11100000b mov edx,AUDIOFILT out dx,al ;start the transfer mov MV_filter,eax ret StartDMACard ENDP ;---------------------------------------------------------------------------- AckIrq PROC mov edx,INTRCTLRST in al,dx ;acknowledge the interrupt test eax,00001000b jz error ;it wasn't caused by our board, exit out dx,al clc ret error: stc ret AckIrq ENDP endif ;---------------------------------------------------------------------------- ;---------------------------------------------------------------------------- ifdef MWSS ResetCard PROC USES EBX mov ax, word ptr[PlayRate] cmp ax, 44100 jae short Freq44 lea edx, MWSSFreq SearchFreq: cmp ax, word ptr[edx] jb short FoundFreq add edx, 4 jmp short SearchFreq Freq44: mov ax, 44100 mov cl, 0Bh jmp short WBack FoundFreq: mov ax, word ptr[edx] ; closest faster speed mov cl, byte ptr[edx+2] ; clock select WBack: mov word ptr[PlayRate], ax or cl, 01010000b ; 16 bit linear, Stereo mov edx, [IRQ_number] ; IRQ mov al, [MWSSIrq+edx] mov edx, [DMA_number] ; DMA or al, [MWSSDma+edx] mov dx, word ptr[BASE_ADDR] add dl, 3 ; offset 3 out dx, al ; program IRQ & DMA inc dl ; offset 4 mov al, 6 ; left vol out dx, al inc dl ; offset 5 mov al, 80h ; mute out dx, al dec dl ; offset 4 mov al, 7 ; right vol out dx, al inc dl ; offset 5 mov al, 80h ; mute out dx, al dec dl ; offset 4 mov al, 13 ; digital mix out dx, al inc dl ; offset 5 xor al, al ; mute out dx, al dec dl ; offset 4 mov al, 2 ; left aux1 out dx, al inc dl ; offset 5 mov al, 80h ; mute out dx, al dec dl ; offset 4 mov al, 3 ; right aux1 out dx, al inc dl ; offset 5 mov al, 80h ; mute out dx, al dec dl ; offset 4 mov al, 4 ; left aux2 out dx, al inc dl ; offset 5 mov al, 80h ; mute out dx, al dec dl ; offset 4 mov al, 5 ; right aux2 out dx, al inc dl ; offset 5 mov al, 80h ; mute out dx, al dec dl ; offset 4 mov al, 49h ; enter MCE, Interface Ctrl out dx, al inc dl ; offset 5 mov al, 08h ; auto-calibrate out dx, al dec dl ; offset 4 mov al, 48h ; MCE, Interface Ctrl out dx, al inc dl ; offset 5 mov al, cl ; 16 bit linear, stereo, speed out dx, al dec dl ; offset 4 wait_init: in al, dx and al, 80h jnz wait_init xor al, al out dx, al ; clear MCE xor bx, bx ; at least 6 millisec. wait0: in al, dx dec bx jnz short wait0 wait_cal: mov al, 0Bh ; Test & Init Reg out dx, al inc dl ; offset 5 in al, dx dec dl ; offset 4 and al, 20h jnz wait_cal mov al, 6 ; left vol out dx, al inc dl ; offset 5 xor al, al ; max vol out dx, al dec dl ; offset 4 mov al, 7 ; right vol out dx, al inc dl ; offset 5 xor al, al ; max vol out dx, al ret ResetCard ENDP ;*--------------------------------------------------------------------------* CloseCard PROC mov dx, word ptr[BASE_ADDR] ; DSP add dl, 4 ; offset 4 mov al, 0Ah ; Pin Ctrl reg out dx, al inc dx ; offset 5 xor al, al ; turn off interrupts out dx, al inc dx ; offset 6 out dx, al ; Ack outstanding interrupts sub dl, 2 ; offset 4 mov al, 9 ; Interface Config reg out dx, al inc dx ; offset 5 xor al, al ; turn off codec DMA out dx, al sub dl, 2 out dx, al ; deselect IRQ and DMA ret CloseCard ENDP ;---------------------------------------------------------------------------- AckIrq PROC mov dx, word ptr[BASE_ADDR] ; DSP add dl, 6 in al, dx shr al, 1 ; get int flag in C cmc ; complement C in order to return error if 0 out dx, al ; Ack anyway ret AckIrq ENDP ;---------------------------------------------------------------------------- StartDMACard PROC mov cx, BUFFER_SIZE - 1 mov dx, word ptr[BASE_ADDR] ; DSP add dl, 6 out dx, al ; clear any pending IRQ sub dl, 2 ; offset 4 mov al, 15 ; DMA Count Lower out dx, al inc dl ; offset 5 mov al, cl out dx, al dec dl ; offset 4 mov al, 14 ; DMA Count Upper out dx, al inc dl ; offset 5 mov al, ch out dx, al dec dl ; offset 4 mov al, 9 ; Interface config out dx, al inc dl ; offset 5 mov al, 00000101b ; DMA Playback out dx, al dec dl ; offset 4 mov al, 0Ah ; Pin Ctrl Reg out dx, al inc dx ; offset 5 mov al, 00000010b ; Turn on Interrupts out dx, al ret StartDMACard ENDP endif ;---------------------------------------------------------------------------- ;---------------------------------------------------------------------------- ifdef SBLASTER WRITE_DSP MACRO VAL ; write to DSP whithout timeout local wait_dsp wait_dsp: in al, dx or al, al js wait_dsp mov al, VAL out dx, al ENDM WRITE_MIXER MACRO REG, VAL ; write to MIXER chip mov al, REG out dx, al inc dx mov al, VAL out dx, al dec dx ENDM READ_MIXER MACRO REG ; read from MIXER chip mov al, REG out dx, al inc dx in al, dx dec dx ENDM ifdef SBPRO InitIRQ PROC pushad push ds mov ax, cs:word ptr[local_DS] ; restore DS mov ds, ax mov al, 20h ; allows for new int cmp byte ptr[IRQ_number], 7 jbe short NoSecondCtrl out 0A0h, al NoSecondCtrl: out 20h, al call AckIrq jc short FinIRQ ; not a DMA IRQ mov byte ptr[OkIRQ], 1 FinIRQ: pop ds popad iretd InitIRQ ENDP endif ResetCard PROC cmp dword ptr[PlayRate], 12000 jae OkRateLow mov dword ptr[PlayRate], 12000 OkRateLow: cmp dword ptr[PlayRate], 22000 jbe OkRateHigh mov dword ptr[PlayRate], 22000 OkRateHigh: ifndef SB16 ifdef SBPRO mov dx, 07A1h mov ax, 2000h ; dx:ax = 128000000 else mov dx, 0F42h mov ax, 4000h ; dx:ax = 256000000 endif div word ptr[PlayRate] ; divide by PlayRate neg ax shr ax, 8 mov cx, ax ; cl = "Magic" push ecx ifdef SBPRO mov dx, 07h mov ax, 0A120h ; dx:ax = 500000 else mov dx, 0Fh mov ax, 4240h ; dx:ax = 1000000 endif neg cl div cx ; divide by "-Magic" mov word ptr[PlayRate], ax ; write back PlayRate endif mov dx, word ptr[BASE_ADDR] add dl, 6 ; reset port (offset 6) mov al, 1 ; write 1 out dx, al mov ah, 8 * 3 ; 4 * "in al, dx" = 1 microsec on std ISA bus (8 Mhz) wait_io: in al, dx ; so 8 to be sure if 16 MHz ! dec ah ; kill the cat ! jnz short wait_io xor al, al out dx, al ; write 0 ; now reset should be done.. add dl, 4 ; offset 0Ah Next: add dl, 4 ; offset 0Eh Wait_s: in al, dx or al, al jns Wait_s sub dl, 4 ; offset 0Ah in al, dx ; read if reset terminated cmp al, RESET_TEST_CODE ; should be... jne Next ifdef SB16 sub dl, 6 ; offset 04h mov al, 80h out dx, al inc dx ; offset 05h xor eax, eax in al, dx and al, 0Fh ; mask reserved bit bsf ax, ax mov al, byte ptr[SB16_IRQ+eax] mov dword ptr[IRQ_number], eax dec dx ; offset 04h mov al, 81h out dx, al inc dx ; offset 05h in al, dx and al, 11101011b ; mask reserved bit ifdef SAMPLE16BIT bsr ax, ax else bsf ax, ax endif mov dword ptr[DMA_number], eax add dl, 7 ; offset 0Ch WRITE_DSP DSP_RATE_CMD ; rate mov cx, word ptr[PlayRate] WRITE_DSP ch ; WRITE_DSP cl ; else add dl, 02h ; offset 0Ch WRITE_DSP DSP_ONSPK_CMD ; Turn speaker on ifdef SBPRO mov edx, offset InitIRQ ; Temporary IRQ handler call InstallISR mov dx, word ptr[BASE_ADDR] add dl, 4 ; offset 4 mov al, 0Eh ; stereo switch & filter out dx, al inc dx ; offset 5 in al, dx or al, 2 ; enable stereo out dx, al mov ecx, dword ptr[DMA] ; Point to DMAx mov dx, word ptr[ecx + MASK_REG] mov al, byte ptr[ecx + MASK2] ; mask channel out dx, al mov dx, word ptr[ecx + FF_REG] out dx, al ; flip-flop mov dx, word ptr[ecx + COUNT_REG] xor al, al out dx, al out dx, al mov eax, dword ptr[BUFFER_DMA] ; start offset mov byte ptr[eax], 80h ; write a "0" into the buffer mov dx, word ptr[ecx + ADDX_REG] out dx, al shr eax, 8 out dx, al mov dx, word ptr[ecx + PAGE_REG] shr eax, 8 ; page of DMA transfert out dx, al mov dx, word ptr[ecx + MODE_REG] mov al, byte ptr[ecx + VOICE_OUT] ; output sample out dx, al mov dx, word ptr[ecx + MASK_REG] mov al, byte ptr[ecx + MASK1] ; channel OK out dx, al mov dx, word ptr[BASE_ADDR] add dl, 0Ch ; offset 0Ch mov byte ptr[OkIRQ], 0 WRITE_DSP DSP_VO8S_CMD WRITE_DSP 0 WRITE_DSP 0 WaitIRQ: cmp byte ptr[OkIRQ], 1 jne short WaitIRQ sub dl, 8 ; offset 4 mov al, 0Eh ; stereo switch & filter out dx, al inc dx ; offset 5 in al, dx mov byte ptr[Filter], al or al, 20h ; disable filter out dx, al add dl, 7 ; offset 0Ch endif pop ecx WRITE_DSP DSP_TIME_CMD ; "rate" WRITE_DSP cl ; magic number ! endif ret ResetCard ENDP ;*--------------------------------------------------------------------------* CloseCard PROC mov dx, word ptr[BASE_ADDR] ; point to DSP ifdef SB16 add dl, 0CH ifdef SAMPLE16BIT WRITE_DSP DSP_VO16S_CMD ; single-cycle 16 bit DMA ifdef STEREO WRITE_DSP DSP_16STEREO_MODE ; 16 bit stereo else WRITE_DSP DSP_16MONO_MODE ; 16 bit mono endif else WRITE_DSP DSP_VO8S_4_CMD ; single-cycle 8 bit DMA ifdef STEREO WRITE_DSP DSP_8STEREO_MODE ; 8 bit stereo else WRITE_DSP DSP_8MONO_MODE ; 8 bit mono endif endif WRITE_DSP 0 ; length of 1 to finish WRITE_DSP 0 else ifdef SBPRO add dl, 6 ; reset port (offset 6) mov al, 1 ; write 1 out dx, al mov ah, 8 * 3 ; 4 * "in al, dx" = 1 microsec on std ISA bus (8 Mhz) wait_io: in al, dx ; so 8 to be sure if 16 MHz ! dec ah ; kill the cat ! jnz wait_io xor al, al out dx, al ; write 0 ; now reset should be done.. add dl, 4 ; offset 0Ah Next: add dl, 4 ; offset 0Eh Wait_s: in al, dx or al, al jns Wait_s sub dl, 4 ; offset 0Ah in al, dx ; read if reset terminated cmp al, RESET_TEST_CODE ; should be... jne Next sub dl, 6 ; offset 4 mov al, 0Eh out dx, al inc dx ; offset 5 mov al, byte ptr[Filter] ; restore filter out dx, al dec dx mov al, 0Eh out dx, al inc dx ; offset 5 in al, dx and al, 11111101b ; turn off stereo out dx, al add dl, 7 ; offset 0Ch WRITE_DSP DSP_OFFSPK_CMD ; Turn speaker off else add dl, 0CH WRITE_DSP DSP_OFFSPK_CMD ; Turn speaker off WRITE_DSP DSP_VO8S_CMD ; single-cycle 8 bit DMA WRITE_DSP 0 ; length of 1 to finish WRITE_DSP 0 endif endif ret CloseCard ENDP ;---------------------------------------------------------------------------- AckIrq PROC mov dx, word ptr[BASE_ADDR] ; DSP IRQ ACK ifdef SB16 add dl, 4 ; offset 4 mov al, 82h out dx, al inc dx ; offset 5 in al, dx ifdef SAMPLE16BIT and al, 2 jz NoDMAIRQ add dl, 10 ; offset Fh else and al, 1 jz NoDMAIRQ add dl, 9 ; offset Eh endif in al, dx ret NoDMAIRQ: stc ret else irq_ok: add dl, 0Eh ; 8 bit Samples ACK in al, dx not_real: ret endif AckIrq ENDP ;---------------------------------------------------------------------------- StartDMACard PROC mov dx, word ptr[BASE_ADDR] ; DSP add dl, 0Ch ifdef STEREO mov cx, BUFFER_SIZE * 2 - 1 ; half-buffer size - 1 for DMA else mov cx, BUFFER_SIZE - 1 ; half-buffer size - 1 for DMA endif ifdef SB16 ifdef SAMPLE16BIT WRITE_DSP DSP_VO16_CMD ; auto-init 16 bit DMA ifdef STEREO WRITE_DSP DSP_16STEREO_MODE ; 16 bit stereo else WRITE_DSP DSP_16MONO_MODE ; 16 bit mono endif else WRITE_DSP DSP_VO8_4_CMD ; auto-init 8 bit DMA ifdef STEREO WRITE_DSP DSP_8STEREO_MODE ; 8 bit stereo else WRITE_DSP DSP_8MONO_MODE ; 8 bit mono endif endif WRITE_DSP cl WRITE_DSP ch elseifdef SBLASTER1 WRITE_DSP DSP_VO8S_CMD ; single-cycle 8 bit DMA WRITE_DSP cl WRITE_DSP ch else WRITE_DSP DSP_BSIZE_CMD ; Set block size WRITE_DSP cl WRITE_DSP ch ifdef SBPRO WRITE_DSP DSP_VO8H_CMD ; auto-init 8 bit high-speed DMA else WRITE_DSP DSP_VO8_CMD ; auto-init 8 bit DMA endif endif ret StartDMACard ENDP endif ;---------------------------------------------------------------------------- ;---------------------------------------------------------------------------- ifdef GOLD SELECT_MIXER MACRO local wait cli mov al, 0FFh out dx, al out dx, al wait: in al, dx and al, 11000000b jnz wait ENDM LEAVE_MIXER MACRO local wait wait: in al, dx and al, 11000000b jnz wait mov al, 0FEh out dx, al out dx, al sti ENDM WRITE_MIXER MACRO PORT, VAL local wait1, wait2 cli mov al, PORT out dx, al wait1: in al, dx and al, 11000000b jnz wait1 inc dx mov al, VAL out dx, al dec dx wait2: in al, dx and al, 11000000b jnz wait2 sti ENDM READ_MIXER MACRO PORT local wait1, wait2 cli mov al, PORT out dx, al wait1: in al, dx and al, 11000000b jnz wait1 inc dx in al, dx dec dx mov ah, al wait2: in al, dx and al, 11000000b jnz wait2 mov al, ah sti ENDM WRITE_MMA0 MACRO PORT, VAL cli mov al, PORT out dx, al inc dx mov al, VAL out dx, al dec dx in al, dx in al, dx sti ENDM READ_MMA0 MACRO PORT cli mov al, PORT out dx, al inc dx in al, dx dec dx mov ah, al in al, dx in al, dx mov al, ah sti ENDM WRITE_MMA1 MACRO PORT, VAL cli mov al, PORT out dx, al add dx, 3 mov al, VAL out dx, al sub dx, 3 in al, dx in al, dx sti ENDM READ_MMA1 MACRO PORT cli mov al, PORT out dx, al add dx, 3 in al, dx sub dx, 3 mov ah, al in al, dx in al, dx mov al, ah sti ENDM ;*--------------------------------------------------------------------------* ResetCard PROC mov dx, word ptr[BASE_ADDR] add dx, 2 ; MIXER SELECT_MIXER WRITE_MIXER 8h, 11001110b ; STEREO mode WRITE_MIXER 11h, 00001000b ; filter on output, no mic input, no PC-speaker input READ_MIXER 13h mov byte ptr[Mixer_13], al mov cl, al and eax, 3 lea ebx, Gold_IRQ mov al, byte ptr[ebx+eax] mov dword ptr[IRQ_number], eax mov al, cl shr al, 4 and al, 3 mov dword ptr[DMA_number], eax or cl, 10001000b ; enable DMA0, enable IRQ WRITE_MIXER 13h, cl READ_MIXER 14h mov byte ptr[Mixer_14], al mov cl, al and cl, 01111111b WRITE_MIXER 14h, cl LEAVE_MIXER add dx, 2 ; MMA WRITE_MMA0 9, 80h ; reset channel 0 WRITE_MMA1 9, 80h ; reset channel 1 mov cx, 4 fillFIFO0: WRITE_MMA0 0Bh, 0 dec cx jnz FillFIFO0 mov cx, 4 fillFIFO1: WRITE_MMA1 0Bh, 0 dec cx jnz FillFIFO1 WRITE_MMA0 9, 00101110b ; 22.05 Khz, PCM, L, Play WRITE_MMA1 9, 01001110b ; 22.05 Khz, PCM, R, Play mov word ptr[PlayRate], 22050 ; 22.05 Khz WRITE_MMA0 0Ch, 11000101b ; Interleave, 16 bit, 96 byte FIFO, DMA WRITE_MMA1 0Ch, 01000011b ; 16 bit, no FIFO (use other channel), DMA WRITE_MMA0 0Ah, 0FFh ; Maximum volume (volume will be controlled by mixer) WRITE_MMA1 0Ah, 0FFh mov cx, 100 fillFIFO: WRITE_MMA0 0Bh, 0 dec cx jnz FillFIFO ret ResetCard ENDP ;*--------------------------------------------------------------------------* CloseCard PROC mov dx, word ptr[BASE_ADDR] add dx, 4 ; MMA WRITE_MMA1 0Ch, 01000010b ; 16 bit, no FIFO, no DMA WRITE_MMA0 0Ch, 01000010b ; 16 bit, no FIFO, no DMA WRITE_MMA0 9, 80h ; reset channel 0 WRITE_MMA1 9, 80h ; reset channel 1 sub dx, 2 ; MIXER SELECT_MIXER WRITE_MIXER 13h, Mixer_13 WRITE_MIXER 14h, Mixer_14 LEAVE_MIXER ret CloseCard ENDP ;---------------------------------------------------------------------------- AckIrq PROC mov dx, word ptr[BASE_ADDR] add dx, 4 ; MMA in al, dx and al, 1 jz short noDMA mov ebx, dword ptr[DMA] ; Point to DMAx mov dx, word ptr[ebx + FF_REG] out dx, al ; flip-flop mov dx, word ptr[ebx + COUNT_REG] in al, dx mov ah, al in al, dx xchg al, ah or ax, ax jz short OkDMA inc ax jnz short noDMA OkDMA: clc ret NoDMA: stc not_real: ret AckIrq ENDP ;---------------------------------------------------------------------------- StartDMACard PROC mov dx, word ptr[BASE_ADDR] add dx, 4 ; MMA WRITE_MMA0 9, 00101111b ; 22.05 Khz, PCM, L, Play, GO ret StartDMACard ENDP endif ;---------------------------------------------------------------------------- ;---------------------------------------------------------------------------- ifdef GUS extrn Nolanguage resetcard:PROC ;*--------------------------------------------------------------------------* extrn Nolanguage CloseCard:PROC ;*--------------------------------------------------------------------------* extrn Nolanguage StartDMACard:PROC endif ;---------------------------------------------------------------------------- ;---------------------------------------------------------------------------- END