;Struct used in sound for Infantry 401

WaveHdr STRUC

format db 'RIFF'

filelen dd ?

wavefmt db 'WAVEfmt_'

fmt_len dd ?

fmt_tag dw ?

channel dw ?

samples dd ?

bytesps dd ?

bkalign dw ?

bitsps dw ?

data db 'data'

datalen dd ?

WaveHdr Ends

 

 

 

 

;Sound segments used for Infantry 401

 

;====== MIDI Segment ==================================

MIDISeg segment public

midibuffer db 65535 dup(?)

MIDISeg ends

 

;======= WAV Segment===================================_

SNDSEG SEGMENT

sndbuf db 2048 dup (10,20,50,80,90,80,50,20) ; 16k of sine wave

SNDSEG ENDS

 

 

 

;Sound Constants used for midi

Gremlins db 'kashmirx.xmi',0

PUBLIC Gremlins

Psycho db 'Psychox.xmi', 0

public Psycho

moby db 'mobyx.xmi', 0

public moby

mission db 'Misionx.xmi', 0

public mission

kashmir db 'Kashmirx.xmi', 0

public kashmir

puppet db 'Puppetsx.xmi', 0

Public puppet

 

MIDISize dd 02

PUBLIC MIDISize

 

; Sound Constants used for wav

sbuf_page db ?

sbuf_offset dw ?

sbuf_length dw 8192 ; 8 k - all that is guaranteed to not

; cross a DMA Page.

Pbuf db 7 dup (?)

finalbuffersize dw ?

mycounter dw -1

needrefill dw 0

loadbuf WaveHdr < >

GunShot db 'gun.wav',0 ; null terminated file names

Grenade db 'bomb.wav',0

Missle db 'missle.wav',0

Dies db 'dies.wav',0

IntroSound db 'intro.wav',0

ExitSound db 'exit.wav',0

MenuSelected db 'menu.wav',0

Blockage db 'oof.wav',0

Pain db 'ouch.wav',0

powerup db 'pickup.wav',0

fileno dw ?

wavremaining dd 0

wavlength dd 0

wavdone db 0

 

 

;procedures for Sound Written by Ray O'Connell

; input dx= offset of midi file to play (filename null term.)

; output none

; purpose: procedure open, writes, and closes a .xmi file into midi

; segment for playing

;

LoadMIDI PROC NEAR

push ax

push bx ;save registers

push cx

push dx

push ds

mov ax, cs

mov ds, ax

mov ah, 03dh

mov al, 0

int 21h ;open file call

jc erroropenMIDI

mov bx, ax

mov ah, 03fh

mov cx, 25000

mov dx, seg midibuffer

mov ds, dx

mov dx, 0

int 21h ;write file call

jc errorreadMIDI

mov cx, cs

mov ds, cx

mov MIDISize, eax

mov ah, 03eh

int 21h ;close file

jc errorcloseMIDI

jmp endmidiload

;extensive error checking follows

erroropenMIDI: ;handle open errors

TMODE

cmp ax, 2

jne notFNFmidi

mov dx, offset FileNotFound ;testing ax for error code

call DSPMSG ;and calling DSPMSG then exiting

call dosXit

notFNFmidi:

cmp ax, 4

jne notTMOFmidi

mov dx, offset TooMany

call DSPMSG

call dosxit

notTMOFmidi:

cmp ax, 5

jne notADOmidi

mov dx, offset DeniedAccessOpen

call DSPMSG

call dosXit

notADOmidi:

mov dx, offset InvalidAccess

call DSPMSG

call dosXit

 

errorreadMIDI: ;handling read errors

TMODE

cmp ax, 5 ;testing ax for error code

jne notDARmidi

mov dx, offset DeniedAccessRead

call DSPMSG ;and calling DSPMSG then exiting

call dosxit

notDARmidi:

mov dx, offset InvalidHandleRead

call DSPMSG

call dosxit

 

errorcloseMIDI:

TMODE ;handling close errors

mov dx, offset InvalidHandleCl

call DSPMSG ;and calling DSPMSG then exiting

call dosxit

endmidiload:

pop ds

pop dx

pop cx ;restore registers

pop bx

pop ax

RET

LoadMIDI ENDP

;Written by Ray A. O'Connell

 

 

; Input dx= offset of midi file to register with midpak

; output none (music file registered )

; purpose register file with midpak to play

RegisterMIDI PROC NEAR

push ax

push bx

push cx ;save used registers

push dx

push ds

mov bx, cs

mov ds, bx

mov bx, offset midibuffer

mov eax, MIDISize

mov di, ax ;setup so midpak knows length

mov cl, 16

shr eax, cl

mov si, ax

mov cx, seg midibuffer

mov ax, 0704h

int 66h ;interrupt call

cmp ax, 0

jne endreg

call dosxit ;exit if error

endreg:

pop ds

pop dx

pop cx ;restore registers

pop bx

pop ax

RET

RegisterMIDI ENDP

;Written by Ray A. O'Connell

 

 

;input- dx offset of midi variable

;output- none(no variables nor registers)

;purpose self explainatory

PlayMIDI PROC NEAR

push ax

push bx

mov ax, 0702h

mov bx, 0 ;setup call to midpak

int 66h

cmp ax, 0

jne endplay

call dosxit

endplay:

pop bx

pop ax

RET

PlayMIDI ENDP

;Written by Ray A. O'Connell

 

;input- none

;output- none

;purpose if pause, unpause the midi

ResumeMIDI PROC NEAR

push ax

mov ax, 070bh

int 66h

pop ax

RET

 

ResumeMIDI ENDP

;Written by Ray A. O'Connell

 

;input -None

;output -none

;purpose stop or at least pause the midi

StopMIDI PROC NEAR

push ax

mov ax, 0705h

int 66h

pop ax

RET

StopMIDI ENDP

;Written by Ray A. O'Connell

 

 

; This one combines three previous ones

; Now, instead of calling loadMIDI, RegisterMIDI, and PlayMIDI

; Just call GoMIDI

; Input: dx = offset of midi variable to play

; example mov dx, offset Kashmir

; output: midi music

; If playing one file, you can start another song by just calling

; GoMIDI with another file, it will just switch songs

;Written by Ray O'Connell

GoMIDI PROC NEAR

push dx

call LoadMIDI

call RegisterMIDI

call PlayMIDI

pop dx

RET

GoMIDI ENDP

;Written by Ray A. O'Connell

 

;; next one is LoopMIDI

; This function plays the song again when it ends. We probably

; won't need this in our demo but if someone is playing the

; game longer, this function will repeat the current song

; It needs to be called at some point on a regular basis

; (some sort of loop) since

; checks the status of MIDPAK to see if the song is finished

; if it is, it starts the song again

; I would suggest trying to find a loop that doesn't go too fast

; otherwise we would be wasting time with the proccessor trying

; every so often if the song finished

;

;Written by Ray O'Connell

LoopMIDI PROC NEAR

push ax

push dx

mov ax, 070ch

int 66h

cmp ax, 2

jne goons

call PlayMIDI

goons:

pop dx

pop ax

RET

LoopMIDI ENDP

;Written by Ray A. O'Connell

 

 

;sound procedures for WAV playing

 

 

;this is the interrupt function set as call back by WAVPlay

;which controls the loading of buffers and switching of modes

;when reaching the last buffer (based on Snd Lib 291)

SoundHandler proc far uses ax ds dx bx es di

mov ax, cs

mov ds, ax

inc mycounter ; so outside program can know where DMA is.

inc needrefill

mov ax, mycounter

and ax, 1

call LoadHalfBuffer ; fills buffer half ax (0 or 1)

dec needrefill

cmp wavdone, 1 ; one for current buffer, one for last

jne shdone

mov cx, finalbuffersize

call SB_SingleCycle ; last buffer read, so switch to SC

call SB_Stop

shdone:

ret

SoundHandler endp

;Written by Ray A. O'Connell

 

 

; Input: dx = offset of file to play (filename, null terminated)

; Output: eax = data length = bytes of Sound Data.

; (based on Sound Library 291)

OpenWav proc near

call rsave

mov ax, 03D00h

int 21h ; open file

jc wavfail

mov fileno, ax

mov ah, 03Fh

mov bx, fileno

mov cx, sizeof WaveHdr

mov dx, offset loadbuf

int 21h ; read the header into loadbuf

mov bx, dx

cmp byte ptr [bx+3] , 'd'

mov eax, loadbuf.datalen

mov wavlength, eax

mov wavremaining, eax

wavfail:

call rrest

ret

OpenWav endp

;Written by Ray A. O'Connell

 

 

; LoadHalfBuffer takes a 1 or 0 in ax, and reads from the file into the

; appropriate half of sndbuf.

; Input ax = secondhalf

; Output: CF = 1 if just loaded last buffer

; ax = number of bytes read

; (as is from Sound Library 291)

LoadHalfBuffer proc near uses bx cx dx es di

xor bx, bx

mov bh, sbuf_page

shl bh, 4 ; segment

mov es, bx

mov bx, sbuf_offset

;add bx, 048 ; FIXME

cmp ax, 0

je LoadingFirstBuffer

mov ax, sbuf_length

shr ax, 1

add bx, ax ; half buffer in, or not

LoadingFirstBuffer:

mov di, bx

push ds

mov bx, fileno

mov cx, sbuf_length

shr cx, 1 ; half buffer length

xor eax, eax

mov ah, 3Fh

mov dx, es

mov ds, dx

mov dx, di

int 021h ; read from file

pop ds

;cmp ax, cx ; did i read a full buffer?

cmp wavremaining, 0 ; Is there any more to be read?

jg wavenotdone

mov finalbuffersize, ax ; if not, it's the last buffer.

inc wavdone

WaveNotDone:

sub wavremaining, eax

ret

LoadHalfBuffer endp

;Written by Ray A. O'Connell

 

 

;calls SB_Play with single cycle mode

; was originally in WAVPlay but was moved out as seperate proc

; input none

; output sound

SingleCycle PROC NEAR

mov ecx, wavlength

mov edx, wavlength

mov ax, sbuf_offset

mov bh, 0 ; single cycle

mov bl, sbuf_page

call SB_Play ; just play one cycle.

mov wavdone, 2

RET

SingleCycle ENDP

;Written by Ray A. O'Connell

 

 

;function called when sound needed for modularity

; inputs dx = offset of sound to play (null terminated filename)

; ouputs sound!

;calls OpenWav, Single Cycle, LoadHalfBuffer and

;functions from SBLib291

 

WAVPlay PROC NEAR

call rsave

mov ax, cseg

mov ds, ax

call SB_Clean

mov wavdone, 0

; find all on one page 32k of 64k buffer

xor eax, eax

mov ax, seg sndbuf ; put linear address of buffer into eax

mov bx, offset sndbuf

shl eax, 4

add eax, offset sndbuf

push eax

dec ax

add ax, sbuf_length ; check if moving to end of buffer

pop eax ; crosses to next page.

jnc NotCrossPageBoundary

xor ebx, ebx

mov bx, sbuf_length

add eax, ebx ; new bottom of buffer

NotCrossPageBoundary:

mov sbuf_offset, ax ; offset composed of the lower 16 bits

shr eax, 8

mov sbuf_page, ah ; and page of the upper 4 bits as LSBs.

 

; set up and run the DMA transfer.

call SB_Init

jc failedinstall

mov ax, seg SoundHandler

mov es, ax

mov bx, offset SoundHandler

call SB_SetCallback

call OpenWav ; open file

mov ax, 0 ; load first half buffer

call LoadHalfBuffer

cmp wavdone, 1

je singlecycle1buf ; SC if it fits in one half buffer..

mov ax, 1 ; load second half buffer

call LoadHalfBuffer

cmp wavdone, 1

je singlecycle1buf ; or in the first and second halves..

mov ax, sbuf_offset

mov bh, 1 ; AutoInit

mov bl, sbuf_page

mov cx, sbuf_length ; Set DMA to traverse full buffer

mov dx, sbuf_length

shr dx, 1 ; Have DSP read HALF buffer before INT

call SB_Play

; Here's the hard part. We want to loop, waiting for the interrupt

; to trigger and tell us to fill the half of the buffer that the DMA

; had just read. And if while we were waiting the sound finished,

; we also want to exit the loop. And most importantly, if we are on

; the last (less than or equal to a) buffer worth of data, we want

; to switch the DSP to Single Cycle so it will stop playing at the

; end of our wav.

jmp DonePlaying

 

singlecycle1buf:

call SingleCycle

 

DonePlaying:

failedinstall:

call rrest

RET

WAVPlay ENDP

;Written by Ray A. O'Connell