
SoundBlaster.Installed: db 0xFF

SoundBlaster.IsInstalled.ParamsSize: equ 0
SoundBlaster.IsInstalled.Locals.Installed: equ 1 ; 1 byte
SoundBlaster.IsInstalled.LocalsSize: equ 1
SoundBlaster.IsInstalled:
	; Prologue
	enter SoundBlaster.IsInstalled.LocalsSize, 0
	pushad
	push es
	call Memory.ClearGeneralRegisters
	
	xor al, al
	mov [ebp - SoundBlaster.IsInstalled.Locals.Installed], byte al
	
	cmp [SoundBlaster.Installed], byte 0xFF
	je SoundBlaster.IsInstalled.__CheckHardware
	
	xor al, byte [SoundBlaster.Installed]
	mov [ebp - SoundBlaster.IsInstalled.Locals.Installed], byte al
	jmp SoundBlaster.IsInstalled.End
	
SoundBlaster.IsInstalled.__CheckHardware:
	
	call SoundBlaster.IsInstalled.__Reset_DSP	    ; reset it
	jc SoundBlaster.IsInstalled.__RstError ; if carry then error
	
	mov al, 1
	mov [ebp - SoundBlaster.IsInstalled.Locals.Installed], byte al
	
	xor  al,al ; no error   ERRORLEVEL = 0

	jmp   SoundBlaster.IsInstalled.Done
	
SoundBlaster.IsInstalled.__RstError:  
	xor  al,al ; there was an error
	dec  al	 ; ERRORLEVEL = 0FFh
SoundBlaster.IsInstalled.Done:
	
	mov al, byte [ebp - SoundBlaster.IsInstalled.Locals.Installed]
	mov [SoundBlaster.Installed], byte al
	
	; Epilogue
SoundBlaster.IsInstalled.End:
	pop es
	popad
	mov al, byte [ebp - SoundBlaster.IsInstalled.Locals.Installed]
	leave
	ret Main.ParamsSize

SoundBlaster.IsInstalled.__Reset_DSP:
	;  Write a 1 to the reset port
	mov  dx,226h
	mov  al,1 ; al = 1
	out  dx,al ; start DSP reset
	
;  Wait
	in   al,dx ; wait for slow ports
	in   al,dx ;  .
	in   al,dx ;  .
	in   al,dx ;  .
	
;  Write a 0 to the reset port
	xor  al,al
	out  dx,al ; end DSP Reset
	
;  Poll the read-buffer status port until bit 7 is set
	mov  dx,22Eh        ; dx = DSP data available
	call SoundBlaster.IsInstalled.__WaitRead
	
;  Poll the read data port until you receive an AA
	mov  dx,22Ah        ; dx = DSP Read Data
	in   al,dx
	cmp  al,0AAh        ; if there is a SB then it returns 0AAh
	je   SoundBlaster.IsInstalled.__SBthere
	stc
	ret
SoundBlaster.IsInstalled.__SBthere:
	clc
	ret

; The DSP usually takes about 100 microseconds to initialized itself.  After
; this period of time, if the return value is not AA or there is no data at
; all, then the SB card may not be installed or an incorrect I/O address is
; being used.


SoundBlaster.IsInstalled.__WaitRead:
	push cx
	xor  cx,cx ; need that for slow SBs !
SoundBlaster.IsInstalled.__loopWaitR:
	dec  cx
	jz    SoundBlaster.IsInstalled.__endloopR
	in   al,dx ; al = data available status
	or   al,al
	jns   SoundBlaster.IsInstalled.__loopWaitR         ; jump if bit7=0 - no data available
SoundBlaster.IsInstalled.__endloopR:  pop  cx
	ret

SoundBlaster.IsInstalled.__WaitWrite:
	push cx
	xor  cx,cx ; need that for slow SBs !
SoundBlaster.IsInstalled.__loopWaitW:
	dec  cx
	jz    SoundBlaster.IsInstalled.__endloopW
	in   al,dx ; al = write command status
	or   al,al
	js    SoundBlaster.IsInstalled.__loopWaitW         ; jump if bit7=1 - writing not allowed
SoundBlaster.IsInstalled.__endloopW:
	pop  cx
	ret

SoundBlaster.__Play.__Length1:    dw  00h
SoundBlaster.__Play.__MemLoc:     dd  0000h
SoundBlaster.__Play.__Page1:      db  00h

; Channel 1
SoundBlaster.__Play.__PgPort:     equ 83h
SoundBlaster.__Play.__AddPort:    equ 02h
SoundBlaster.__Play.__LenPort:    equ 03h
SoundBlaster.__Play.__ModeReg:    equ 49h
SoundBlaster.__Play.__Channel:    equ 01h
SoundBlaster.__Play.__BasePort:   equ 220h

SoundBlaster.__Play.__HdrSize:       equ 0
SoundBlaster.__Play.__Freq: dd 8000

SoundBlaster.__Play.Params.Segment: equ 8 ; 2 bytes
SoundBlaster.__Play.Params.Address: equ 6 ; 2 bytes
SoundBlaster.__Play.Params.Length: equ 4 ; 2 bytes
SoundBlaster.__Play.ParamsSize: equ 6
SoundBlaster.__Play.Locals.Success: equ 1 ; 1 byte
SoundBlaster.__Play.LocalsSize: equ 1
SoundBlaster.__Play:
	; Prologue
	enter SoundBlaster.__Play.LocalsSize, 0
	pushad
	call Memory.ClearGeneralRegisters
	
	; Default return value
	xor al, al
	mov [SoundBlaster.__Play.Locals.Success], byte al
	
	; Verify that the SoundBlaster is installed
	call SoundBlaster.IsInstalled
	cmp al, 0
	je SoundBlaster.__Play.End
	
SoundBlaster.__Play.__File1OK:
	xor eax, eax
	
	mov word [SoundBlaster.__Play.__Length1], word 0
	
	; save len of file
	mov word ax, word [ebp + SoundBlaster.__Play.Params.Length]
	sub word ax, word SoundBlaster.__Play.__HdrSize
	mov [SoundBlaster.__Play.__Length1], ax
	mov word ax, word [ebp + SoundBlaster.__Play.Params.Address]
	add word ax, word SoundBlaster.__Play.__HdrSize
	mov word [ebp + SoundBlaster.__Play.Params.Address], word ax
SoundBlaster.__Play.SkipBufferCalc:
	
	call SoundBlaster.__Play.__ResetDSP
	or   ax,ax
	jz  SoundBlaster.__Play.__RstOK
	jmp SoundBlaster.__Play.__RstOK1
SoundBlaster.__Play.__RstOK:  
SoundBlaster.__Play.__RstOK1:    ;mov  ah,09
	
	mov byte al, byte [SoundBlaster.LeftVolume]
	shl byte al, byte 4
	or byte al, byte [SoundBlaster.RightVolume]
	call SoundBlaster.__Play.__MstrVol	      ; L = Hi Nibble, R = Lo Nibble

	mov  al,0D1h	      ; turn speaker(s) on
	call SoundBlaster.__Play.__WriteDSP

	xor  eax,eax
	xor  edx,edx
	mov ax, word [ebp + SoundBlaster.__Play.Params.Segment]
	mov dx, word [ebp + SoundBlaster.__Play.Params.Address]
	shl  eax,04h
	add  eax,edx
	mov  [SoundBlaster.__Play.__MemLoc],eax
	call SoundBlaster.__Play.__DMAPlay
	
SoundBlaster.__Play.__Done:
	
	mov al, 1
	mov [SoundBlaster.__Play.Locals.Success], byte al
	

	; Epilogue
SoundBlaster.__Play.End:
	popad
	xor dword eax, dword eax
	mov al, byte [SoundBlaster.__Play.Locals.Success]
	leave
	ret SoundBlaster.__Play.ParamsSize


SoundBlaster.__Play.__DMAPlay:    ;proc near uses eax ebx edx

	dec  word [SoundBlaster.__Play.__Length1]
	mov  byte [SoundBlaster.__Play.__Page1],00h

	mov  al,(SoundBlaster.__Play.__Channel+4)
	mov  dx,0Ah
	out  dx,al
	xor  al,al
	mov  dx,0Ch
	out  dx,al
	mov  al, SoundBlaster.__Play.__ModeReg
	mov  dx,0Bh
	out  dx,al
	mov  eax, dword [SoundBlaster.__Play.__MemLoc]
	mov  dx, SoundBlaster.__Play.__AddPort
	out  dx,al
	xchg al,ah
	out  dx,al
	mov  eax, dword [SoundBlaster.__Play.__MemLoc]
	mov  edx,eax
	and  eax,65536
	jz  SoundBlaster.__Play.__MemLocN1
	inc  byte [SoundBlaster.__Play.__Page1]
SoundBlaster.__Play.__MemLocN1:  mov  eax,edx
	and  eax,131072
	jz  SoundBlaster.__Play.__MemLocN2
	add  byte [SoundBlaster.__Play.__Page1],02
SoundBlaster.__Play.__MemLocN2:  mov  eax,edx
	and  eax,262144
	jz  SoundBlaster.__Play.__MemLocN3
	add  byte [SoundBlaster.__Play.__Page1],04
SoundBlaster.__Play.__MemLocN3:  mov  eax,edx
	and  eax,524288
	jz  SoundBlaster.__Play.__MemLocN4
	add  byte [SoundBlaster.__Play.__Page1],08
SoundBlaster.__Play.__MemLocN4:  mov  eax,edx
	and  eax,1048576
	jz  SoundBlaster.__Play.__MemLocN5
	add  byte [SoundBlaster.__Play.__Page1],16
SoundBlaster.__Play.__MemLocN5:  mov  dx,SoundBlaster.__Play.__PgPort
	mov  al,[SoundBlaster.__Play.__Page1]
	out  dx,al
	mov  dx,SoundBlaster.__Play.__LenPort
	mov  ax,[SoundBlaster.__Play.__Length1]
	out  dx,al
	xchg al,ah
	out  dx,al
	mov  dx,0Ah
	mov  al,SoundBlaster.__Play.__Channel
	out  dx,al

	mov  al,40h
	call SoundBlaster.__Play.__WriteDSP
	xor  edx,edx
	mov  eax,1000000
	mov dword ebx, dword [SoundBlaster.__Play.__Freq]
	div  ebx
	mov  ebx,eax
	mov  eax,256
	sub  eax,ebx
	call SoundBlaster.__Play.__WriteDSP
	mov  al,14h
	call SoundBlaster.__Play.__WriteDSP
	mov  ax, word [SoundBlaster.__Play.__Length1]
	call SoundBlaster.__Play.__WriteDSP
	xchg al,ah
	call SoundBlaster.__Play.__WriteDSP

	ret

SoundBlaster.__Play.__MstrVol:    ;proc near uses ax dx
	push ax
	mov  dx,(SoundBlaster.__Play.__BasePort+4)
	mov  al,22h
	out  dx,al
	pop  ax
	inc  dx
	out  dx,al
	ret

SoundBlaster.__Play.__ResetDSP:   ;proc near uses cx dx

	mov  dx,(SoundBlaster.__Play.__BasePort+6)
	mov  al,01
	out  dx,al
	mov  cx,50
SoundBlaster.__Play.__SoundBlaster.__Play.__WaitIt1:   in   al,dx
	loop SoundBlaster.__Play.__SoundBlaster.__Play.__WaitIt1
	xor  al,al
	out  dx,al
	mov  cx,50
SoundBlaster.__Play.__SoundBlaster.__Play.__WaitIt2:   in   al,dx
	loop SoundBlaster.__Play.__SoundBlaster.__Play.__WaitIt2
	mov  ah,0FFh	      ; part of Return Code
	mov  dx,(SoundBlaster.__Play.__BasePort+14)
	in   al,dx
	and  al,80h
	cmp  al,80h
	jne SoundBlaster.__Play.__ResetErr
	mov  dx,(SoundBlaster.__Play.__BasePort+10)
	in   al,dx
	cmp  al,0AAh
	jne SoundBlaster.__Play.__ResetErr
SoundBlaster.__Play.__ResetOK:   xor  ax,ax	        ; return ax = 0 if reset ok
SoundBlaster.__Play.__ResetErr:  ret

SoundBlaster.__Play.__WriteDSP:   ;proc near uses ax dx
	push ax
	mov  dx,(SoundBlaster.__Play.__BasePort+12)
SoundBlaster.__Play.__WaitIt:    in   al,dx
	and  al,80h
	jnz SoundBlaster.__Play.__WaitIt
	pop  ax
	out  dx,al
	ret

SoundBlaster.LeftVolume: db 0x0F
SoundBlaster.RightVolume: db 0x0F

SoundBlaster.PlayAsync: db 0
SoundBlaster.IsPlaying: db 0

SoundBlaster.OLDInterruptSEG: dw 0
SoundBlaster.OLDInterruptOFS: dw 0
SoundBlaster.BASEADDR:           EQU 0220h       ;SoundBlaster base address
SoundBlaster.IRQ:               EQU 13          ;SoundBlaster IRQ5
SoundBlaster.PICANDMASK:         EQU 11011111b   ;'AND' PIC mask for clear IRQ5
SoundBlaster.PICORMASK:          EQU 00100000b   ;'OR' PIC mask for set IRQ5
SoundBlaster.ChunkSize: equ 0x00000DFF

SoundBlaster.__Length: dd 0
SoundBlaster.__Size: dd 0
SoundBlaster.__ChunkSize: dw 0
SoundBlaster.__BytesRemaining: dd 0
SoundBlaster.__FreqDivisor: dd 0
SoundBlaster.__BufferOffset: dd 0
SoundBlaster.__Buffer: dd 0

SoundBlaster.Play.Params.Buffer: equ 4 ; 4 bytes
SoundBlaster.Play.ParamsSize: equ 4
SoundBlaster.Play.Locals.Success: equ 1 ; 1 byte
SoundBlaster.Play.LocalsSize: equ 1
SoundBlaster.Play:
	; Prologue
	enter SoundBlaster.Play.LocalsSize, 0
	pushad
	call Memory.ClearGeneralRegisters
	
	; Default value
	mov byte [ebp - SoundBlaster.Play.Locals.Success], byte 0
	mov word [SoundBlaster.__ChunkSize], word 0
	mov dword [SoundBlaster.__Length], dword 0
	mov dword [SoundBlaster.__Size], dword 0
	mov dword [SoundBlaster.__FreqDivisor], dword 0
	mov dword [SoundBlaster.__BufferOffset], dword 0
	
	mov dword eax, dword [ebp + SoundBlaster.Play.Params.Buffer]
	mov dword [SoundBlaster.__Buffer], dword eax
	
	cmp dword [SoundBlaster.__Buffer], dword 0
	je SoundBlaster.Play.Done
	
	push dword [SoundBlaster.__Buffer]
	call Memory.GetSize
	mov dword [SoundBlaster.__Size], dword eax
	mov dword [SoundBlaster.__BytesRemaining], dword eax
	
	; Populate the wave header information
	push dword [SoundBlaster.__Buffer]
	call Wav.ReadInfoHeader
	cmp byte al, byte 0
	je SoundBlaster.Play.Done
	
	call SoundBlaster.__SetInterrupt
	
	; Copy the frequency from the wave header
	mov dword eax, dword [WAVEFORMATCHUNK.SamplesPerSec]
	mov dword [SoundBlaster.__Play.__Freq], dword eax
	
	; Multiple the number of channels
	xor dword ebx, dword ebx
	movzx dword eax, word [WAVEFORMATCHUNK.Channels]
	imul dword eax, dword [SoundBlaster.__Play.__Freq]
	mov dword [SoundBlaster.__Play.__Freq], dword eax
	
	; Determine divisor that will be used later to determine the length of the audio
	mov dword ebx, dword 1000
	xor dword edx, dword edx
	mov dword eax, dword [SoundBlaster.__Play.__Freq]
	idiv dword ebx
	mov dword [SoundBlaster.__FreqDivisor], dword eax
	
	mov word [SoundBlaster.__ChunkSize], word SoundBlaster.ChunkSize
	
	mov byte [SoundBlaster.IsPlaying], byte 1
	
SoundBlaster.Play.PlayFile:
	
	; Determine the chunk size
	cmp dword [SoundBlaster.__BytesRemaining], dword SoundBlaster.ChunkSize
	jae SoundBlaster.Play.SkipSetChunkSize
	mov dword eax, dword [SoundBlaster.__BytesRemaining]
	mov word [SoundBlaster.__ChunkSize], word ax
SoundBlaster.Play.SkipSetChunkSize:
	
	; Load the file into memory
	mov dword eax, dword [SoundBlaster.__Buffer]
	add dword eax, dword [SoundBlaster.__BufferOffset]
	push dword eax
	push word Memory.AudioSegment
	push word 0
	push word [SoundBlaster.__ChunkSize]
	call Memory.CopyBytesToFar
	
	; Figure out how long this sound is
	; Length = Size / 8000 (In Seconds)
	; Length = Size / 8 (In MilliSeonds)
	;  [8000 Hz X 8 bit (1 byte)]
	xor dword edx, dword edx
	;movzx dword eax, word [SoundBlaster.__ChunkSize]
	mov dword eax, dword [SoundBlaster.__Size]
	mov dword ebx, dword [SoundBlaster.__FreqDivisor]
	idiv ebx ; EAX now contains the milliseconds
	mov [SoundBlaster.__Length], dword eax
	
	; Play the sound
	push word Memory.AudioSegment
	push word 0
	push word [SoundBlaster.__ChunkSize]
	call SoundBlaster.__Play
	cmp al, 0
	je SoundBlaster.Play.Done
	
	cmp byte [SoundBlaster.PlayAsync], byte 0
	jne SoundBlaster.Play.PlayDone
	
	; Wait for the sound to finish
	push dword [SoundBlaster.__Length]
	call System.Wait
	
SoundBlaster.Play.PlayDone:
	
	; Assign return value
	mov al, 1
	mov [ebp - SoundBlaster.Play.Locals.Success], byte al
	
SoundBlaster.Play.Done:
	
	; Epilogue
SoundBlaster.Play.End:
	popad
	xor eax, eax
	mov al, byte [ebp - SoundBlaster.Play.Locals.Success]
	leave
	ret SoundBlaster.Play.ParamsSize

SoundBlaster.__SetInterrupt.ParamsSize: equ 0
SoundBlaster.__SetInterrupt.LocalsSize: equ 0
SoundBlaster.__SetInterrupt:
	; Prologue
	enter SoundBlaster.__SetInterrupt.LocalsSize, 0
	pushad
	call Memory.ClearGeneralRegisters
	
	cmp word [SoundBlaster.OLDInterruptSEG], word 0
	jne SoundBlaster.__SetInterrupt.End
	
           ; SETUP IRQ :
           xor     ax,ax
           mov     es,ax                       ; es to page 0 (Interrupt table)
           mov     si,SoundBlaster.IRQ*4                   ; si = position in interrupt table
		   ; See http://wiki.osdev.org/Interrupt_Vector_Table#Default_Hardware_Interrupt_Layout

           ; DISABLE IRQ (if it was enabled somehow)
           in      al,021h
           ;and     al,SoundBlaster.PICANDMASK               ; SET MASK REGISTER BIT TO DISABLE INTERRUPT
		   or     al,SoundBlaster.PICORMASK               ; SET MASK REGISTER BIT TO DISABLE INTERRUPT
           out     021h,al

           ; CHANGE POINTER IN INTERRUPT TABLE
           mov     ax,[es:si]
           mov     [SoundBlaster.OLDInterruptOFS],ax        ; save offset of old interupt vector for restoring
           mov     ax,SoundBlaster.OWN_IRQ
           mov     [es:si],ax                  ; set offset of new interrupt routine
           mov     ax,[es:si+2]
           mov     [SoundBlaster.OLDInterruptSEG],ax        ; save segment of old interupt vector for restoring
           mov     ax,cs
           mov     [es:si+2],ax                ; set segment of new interrupt routine

           ; CHANGE PIC MASK :
           in      al,021h
           and     al,SoundBlaster.PICANDMASK   ; CLEAR MASK REGISTER BIT TO ENABLE INTERRUPT
           out     021h,al

	; Epilogue
SoundBlaster.__SetInterrupt.End:
	popad
	leave
	ret SoundBlaster.__SetInterrupt.ParamsSize

SoundBlaster.__UnsetInterrupt.ParamsSize: equ 0
SoundBlaster.__UnsetInterrupt.LocalsSize: equ 0
SoundBlaster.__UnsetInterrupt:
	; Prologue
	enter SoundBlaster.__UnsetInterrupt.LocalsSize, 0
	pushad
	call Memory.ClearGeneralRegisters
	
	cmp word [SoundBlaster.OLDInterruptSEG], word 0
	je SoundBlaster.__SetInterrupt.End
	
           ; RESTORE PIC MASK
           in      al,021h
           or      al,SoundBlaster.PICORMASK                ;<-- SET REGISTER MASK BITS TO DISABLE
           out     021h,al

           ; RESTORE IRQ :
           xor     ax,ax
           mov     es,ax                       ; es to page 0 (Interrupt table)
           mov     si,SoundBlaster.IRQ*4
           mov     ax,[SoundBlaster.OLDInterruptOFS]
           mov     [es:si],ax                  ; set old interrupt routine
           mov     ax,[SoundBlaster.OLDInterruptSEG]
           mov     [es:si+2],ax
	
	mov word [SoundBlaster.OLDInterruptSEG], word 0
	mov word [SoundBlaster.OLDInterruptOFS], word 0
	
	
	; Epilogue
SoundBlaster.__UnsetInterrupt.End:
	popad
	leave
	ret SoundBlaster.__UnsetInterrupt.ParamsSize

SoundBlaster.InterruptMsg: db "Interrupt called.", 0
;ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ
; Our own IRQ for detecting buffer half SB currently plays
; It's generated by the SoundBlaster hardware
;ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ
SoundBlaster.OWN_IRQ:
	pushad
	call Memory.ClearGeneralRegisters
	
	mov     dx,SoundBlaster.BASEADDR+00Fh            ;DX = IRQ ACKNOWLEDGE 16Bit
	in      al,dx

	cmp byte [SoundBlaster.IsPlaying], byte 0
	je SoundBlaster.OWN_IRQ.End

	
	mov ax, cs
	mov dx, ax

	; Determine if there are more bytes that need to be written
	cmp dword [SoundBlaster.__BytesRemaining], dword SoundBlaster.ChunkSize
	jbe SoundBlaster.OWN_IRQ.PlayDone
	
	; Update the BytesRemaining
	mov dword eax, dword [SoundBlaster.__BytesRemaining]
	movzx dword ebx, word [SoundBlaster.__ChunkSize]
	sub dword eax, dword ebx
	mov dword [SoundBlaster.__BytesRemaining], dword eax
	
	; Update the BufferOffset
	mov dword eax, dword [SoundBlaster.__BufferOffset]
	movzx dword ebx, word [SoundBlaster.__ChunkSize]
	add dword eax, dword ebx
	mov dword [SoundBlaster.__BufferOffset], dword eax
	
;	jmp SoundBlaster.Play.PlayFile

	; Determine the chunk size
	cmp dword [SoundBlaster.__BytesRemaining], dword SoundBlaster.ChunkSize
	jae SoundBlaster.OWN_IRQ.SkipSetChunkSize
	mov dword eax, dword [SoundBlaster.__BytesRemaining]
	mov word [SoundBlaster.__ChunkSize], word ax
SoundBlaster.OWN_IRQ.SkipSetChunkSize:
	
	; Load the file into memory
	mov dword eax, dword [SoundBlaster.__Buffer]
	add dword eax, dword [SoundBlaster.__BufferOffset]
	push dword eax
	push word Memory.AudioSegment
	push word 0
	push word [SoundBlaster.__ChunkSize]
	call Memory.CopyBytesToFar
	
	; Play the sound
	push word Memory.AudioSegment
	push word 0
	push word [SoundBlaster.__ChunkSize]
	call SoundBlaster.__Play
	jmp SoundBlaster.OWN_IRQ.End
	
SoundBlaster.OWN_IRQ.PlayDone:
	call SoundBlaster.Stop
	
SoundBlaster.OWN_IRQ.End:
	mov     al,020h
	out     020h,al                     ;ACKNOWLEDGE HARDWARE INTERRUPT
	popad
	iret

SoundBlaster.Stop.ParamsSize: equ 0
SoundBlaster.Stop.LocalsSize: equ 0
SoundBlaster.Stop:
	; Prologue
	enter SoundBlaster.Stop.LocalsSize, 0
	pushad
	call Memory.ClearGeneralRegisters
	
	cmp byte [SoundBlaster.IsPlaying], byte 0
	je SoundBlaster.Stop.End
	
	mov  al,0d3h	      ; turn speaker(s) off
	call SoundBlaster.__Play.__WriteDSP
	
	call SoundBlaster.__UnsetInterrupt
	
	mov byte [SoundBlaster.IsPlaying], byte 0
	; Epilogue
SoundBlaster.Stop.End:
	popad
	leave
	ret SoundBlaster.Stop.ParamsSize
