Contra Wars Sound Routines

by Brandon Miller

What's in this document

Short Description
The sound for Contra Wars used a polled version of Midpak for background midi music, and an alterred version of the 291 Sound Library for playing sound effects.  There are no procedures for midi, but pmidpak.com must be run before starting the game.  For sound effects, there are four procedures.

 
SoundHandler -  This procedure is called whenever the DSP generates an interrupt and updates variables to indicate whether the sound is done processing or not.
OpenWav-  This opens a wav file and advances to the beginning of data.
LoadHalfBuffer - Reads the sound file into the sound buffer.
PlayWav - This procedure calls the above procedures and starts the DSP playing sound from the sound buffer.
The midi used in the game was obtained from the Video Game Music Archive and sound effects were taken directly from the game Contra for Nintendo.  Midpak can be found at http://www.ece.uiuc.edu/~ece291/class-resources/sound/dmkit.zip, and the 291 sound library can be found at http://www.ece.uiuc.edu/~ece291/class-resources/sound_lib_291.zip

 
 
 
 
Dependant Constants From Other Source Files
No constants from other source files are necessary.

 
 
Dependant Variables From Other Source Files
No variables from other files are necessary.

 
 
Defined Structures
Structures used by sound.
This is a structure used to process wav file headers.
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

 
 
Declared Varaiables
Variables declared by the sound rouintes.
 
midifile db 'contra-1.xmi', 0
  •  The dos name of the midi file, null terminated
wavfile  db 13 dup(0)
  • This will hold the dos name of the wav
shotsnd db 'shot.wav', 0
  • The dos name of the shot wav, null terminated
deathsnd db 'death.wav', 0
  • The dos name of the death wav, null terminated
fileno dw ?
  • The dos file number
wavremaining dd 0
  • Length of wav reamaining
wavlength dd 0
  • Total length of wav
wavdone db 0
  • Tells if the wav is done
sbuf_page db ?
  • The page of the sound buffer
sbuf_offset dw ?
  • The offset of the sound buffer
sbuf_length dw 16384
  • 16 k - all that is guaranteed to not to cross a DMA page
Pbuf db 7 dup (?)
  • For lib291 calls
finalbuffersize dw ?
  • Length of the final buffer size
mycounter dw -1
  • Counter for DMA
needrefill dw 0
  • Tells if the sound buffer needs to be refilled
loadbuf WaveHdr < >
  • The buffer containing the wav header information

 
 
Declared Constants
The following are all constants used by the networking routines.
The following constants are used to determine the wav file to be opened:
SHOT_WAV equ 1
DEATH_WAV equ 2
The following constants are used by the 291 sound library:
DMA_BUF_SIZE    EQU     8192
DMA8_FF_REG     EQU     0Ch
DMA8_MASK_REG   EQU     0Ah
DMA8_MODE_REG   EQU     0Bh
DMA16_FF_REG    EQU     0D8h
DMA16_MASK_REG  EQU     0D4h
DMA16_MODE_REG  EQU     0D6h

DMA0_ADDR       EQU     0
DMA0_COUNT      EQU     1
DMA0_PAGE       EQU     87h
DMA1_ADDR       EQU     2
DMA1_COUNT      EQU     3
DMA1_PAGE       EQU     83h
DMA3_ADDR       EQU     6
DMA3_COUNT      EQU     7
DMA3_PAGE       EQU     82h
DMA5_ADDR       EQU     0C4h
DMA5_COUNT      EQU     0C6h
DMA5_PAGE       EQU     8Bh
DMA6_ADDR       EQU     0C8h
DMA6_COUNT      EQU     0CAh
DMA6_PAGE       EQU     89h
DMA7_ADDR       EQU     0CCh
DMA7_COUNT      EQU     0CEh
DMA7_PAGE       EQU     8Ah

DSP_BLOCK_SIZE                  EQU     0048h
DSP_DATA_AVAIL                  EQU     000Eh
DSP_HALT_SINGLE_CYCLE_DMA       EQU     00D0h
DSP_READ_PORT                   EQU     000Ah
DSP_READY                       EQU     00AAh
DSP_RESET                       EQU     0006h
DSP_TIME_CONSTANT               EQU     0040h
DSP_WRITE_PORT                  EQU     000Ch
DSP_VERSION                     EQU     00E1h

AUTO_INIT       EQU     1
FAIL            EQU     0
FALSE           EQU     0
MASTER_VOLUME   EQU     22h
MIC_VOLUME      EQU     0Ah
MIXER_ADDR      EQU     04h
MIXER_DATA      EQU     05h
MONO            EQU     0
PIC_END_OF_INT  EQU     20h
PIC_MASK        EQU     21h
PIC_MODE        EQU     20h
SUCCESS         EQU     1
SINGLE_CYCLE    EQU     0
STEREO          EQU     1
TRUE            EQU     1
VOICE_VOLUME    EQU     04h

;time constant calculated as follows:
;       256-(1,000,000/sampling rate)
LONGTIMECONS    EQU     210     ;22050 hz    210 - use higher sound quality
SHORTTIMECONS   EQU     165     ;11025 hz    165 - use lower sound qualit 

 
 
Macros
Macros defined and used by networking routines.

 
MIDISTART MACRO
; Input: None
; Output: None
; Calls: LoadFile - Loads the midi file into memory
; Purpose: This macro should be called when a midi file is to be played.
;       It will open it, dump the file into memory, registers the file with
;       Midpak by calling an int66h interrupt, and then calls Midpak's
;       int 66h again to begin playing the file.

        push    ax
        push    bx
        push    cx
        push    dx
        push  si
        push  di
        mov     dx, OFFSET midifile     ; Open and read midi file
        mov     ax, SEG SNDSEG
        mov     bx, OFFSET midisong
        mov     cx, 15448
        call    LoadFile

        mov     cx, SEG SNDSEG  ; Register midi filename with midpak
        mov     bx, OFFSET midisong
        mov     si, 15448
        mov     di, 0
        mov     ax, 704h
        int     66h

        xor     bx, bx
        mov     ax, 702h        ; Play midi
        int     66h

        pop   di
        pop   si
        pop     dx
        pop     cx
        pop     bx
        pop     ax
ENDM
STOPMIDI MACRO
; Input: None
; Output: None
; Calls: None
; Purpose: This simply stops any currently playing midi.

        push    ax
        mov     ax, 705h
        int     66h
        pop     ax
ENDM
WAVPLAY MACRO   SoundNum
; Input: SoundNum - the number indicating which wav file is to be played
; Output: None
; Calls: PlayWav - This function plays the wav file
;        SB_Stop - This function stops any wav file playing beforehand
; Purpose: This macro calls SB_Stop to kill any currently playing wav, and then
;       plays the wave indicated by SoundNum.

        push    dx
        call    SB_Stop
        mov     dx, SoundNum
        call    PlayWav
        pop     dx
ENDM
WAVEND  MACRO
; Input: Variable needrefill - Tells if we're on teh final cycle
; Output: None
; Calls: SB_SingleCycle - Puts the DSP in single cycle mode. 
;        LoadHalfBuffer - Fills the sound buffer.
; Purpose: This macro is called within a main loop of a program.  If a sound
;       is playing and it is on the final cycle, this will load the sound
;       buffer, change the soundblaster from auto mode to single cycle mode to
;       play the last cycle, and then the wav file in question will be closed.
        local   WaitContinue

        push    ax
        push    bx
        push    cx

        cmp     needrefill, 1           ; Check if we're on the final cycle
        jae     WaitContinue

        mov     ax, mycounter
        and     ax, 1
        call    LoadHalfBuffer          ; fills buffer half ax (0 or 1)
        dec     needrefill
        cmp     wavdone, 2              ; one for current buffer, one for last
        jne     WaitContinue

        mov     cx, finalbuffersize
        call    SB_SingleCycle
        
        mov     ah, 3Eh                 ; Close wav file
        mov     bx, fileno
        int     21h
        
WaitContinue:
        pop     cx
        pop     bx
        pop     ax
ENDM

 
Procedures
    PlayWav is the only procedure that differs from the 291 sound library.
PlayWav PROC NEAR
  • Reg In: 
    • None.
  • Reg Out: 
    • AL - contains the player number
  • Variables read: 
    • sbuf_legth - length of the sound buffer
    • wavdone - tells if the wav is done playing
    • fileno - the number of the dos file to close
  • Variables updated: 
    • sbuf_offset - the offset of the larger part of the sound buffer
  • calls: 
    • LoadHalfBuffer - Fills the sound buffer
    • SB_SetCallback - Sets the callback for the sound handler
    • SB_Play - plays the sound
  • description: 
    • Plays a sound by loading the sound buffer with a file, and then having the DSP play the file using DMA.