Final Project: Zelda 291: Sound and Music
by Kevin Moore
Theory: MIDI file playback as handled through John Ratcliff's (somewhat) reliable MIDPAK interface. The WAV playback
is handled by setting the DMA for an auto transfer and using the sound blaster to initiate it. The actual Data files are WAV's
stripped of the headers and renamed PCM's.
From the "Give Credit where credit is due" department: This game uses John Ratcliff's Midpak interrupt handler to do all MIDI functions. The procedures I wrote are an interface to other programmers in the group. The MIDI repeat feature, which is not implemented by MIDPAK, is entirely original. The Wave functions are more direct in the way that they interface with the hardware. Plavcan wrote two macros that are used to send bytes to and from the SB read/write port. Plavcan's source was also the base for my ResetDSP function. The ProgDMA function is based on source code provided by Draeden in the PC-GPE, the DSPFindPageOffset function is also based on his source. All other functions are brand spanking new.
WAV Playback
Internal Structures:
- PCMStartTable - stores the offset in the SoundSeg of each PCM file in the game.
- PCMLengthTable - stores the length of each PCM file in the game.
- SB Data - stores information about the soundcard that a detection routine provides
Functions
- PlayWAV
- PlayWav PROTO near C WaveID:byte
- Purpose: this function plays a certain wav, stopping any previous playback.
- Inputs: WaveID - the constant of the WAV to play
- Outputs: the function plays the WAV file
- Notes: this function is just a handler to call other parts of the digital sound process.
- DSPFindPageOffset
- DSPFindPageOffset PROTO near C InputSeg:word, InputOff:word
- Purpose: this function calculates the page:offset of a certain segment:offset.
- Inputs: InputSeg:InputOffset the segment and offset of the location to convert.
- Outputs: DH - Page Number (0..F), AX - Offset (relative to page boundry)
- Notes: this info is needed to properly set the DMA chip.
- ResetDSP
- ResetDSP PROTO near C
- Purpose: this function sends bytes to the DSP to reset it in preparation to do another transfer.
- Inputs: none
- Outputs: AL - AAh if reset was successful
- Notes: after this function we are ready to send commands to the DSP
- ProgDMA
- ProgDMA PROTO near C, Mode:byte, PageNum:byte, Address:word, TransLength:word, DMAChannel:byte, DMABaseAddr:word, DMAPageReg:word, DMALengthReg:word
- Purpose: This function sets up the DMA to do a transfer
- Inputs:
- Mode:byte - usually 48h for auto transfer
- PageNum:byte - returned from DSPFindPageOffset
- Address:word - returned from DSPFindPageOffset
- TransLength:word - from the LengthTable
- DMAChannel:byte - from ENVIRONMENT string
- DMABaseAddr:word - from DMA lookup tables
- DMAPageReg:word - from DMA lookup tables
- DMALengthReg:word - from DMA lookup tables
- Outputs: none
- Notes: after this function we only need to go and set the go command from the SB DSP
- ResetMixerChip
- ResetMixerChip PROTO near C
- Purpose: This function sets the SB Mixer values where we want them.
- Inputs: None
- Outputs: none
- Notes: this should correct volume changes brought on by ResetDSP
- InitSoundHardwareData
- ResetMixerChip PROTO near C
- Purpose: This function scans the Environment variable and finds the soundcard values, it uses the dma channel to lookup port addresses.
- Inputs: pspseg:wrod - this is the segment of the psp
- Outputs: none
- Notes: this function was designed to return the values in registers, but had been modified to write to the games variables directly.
- LoadFile
- LoadFile PROTO near C, FileNameSeg:word, FileNameOffset:word, MemorySeg:word, MemoryOffset:word
- Purpose: This function scans the Environment variable and finds the soundcard values, it uses the dma channel to lookup port addresses.
- Inputs:
- FileNameSeg:FileNameOffset - the location of the FileName
- MemorySeg:MemoryOffset - the location in memory to write to
- Outputs: none
- Notes: this function was designed to return the values in registers, but had been modified to write to the games variables directly.
- InitPCMFiles
- InitPCMFiles PROTO near C
- Purpose: this function loads the PCM files into memory and updates their data tables (Start and Length)
- Inputs: none
- Outputs: none
- Notes: this will set up the WAVs for proper playback.
MIDI Playback
Internal Structures:
- Present Track Data - stores information about the current track, it's number, it's length, and how long it's been going.
Functions
- PlayMIDI
- PlayMidi PROTO near C Track:word
- Purpose: This function plays a sequence from the registered XMI variable and updates the state variables accordingly.
- Inputs: Track - the track constant to play
- Outputs: The function will begin playing the correct track, and set LastPlayedTrack=Track, CurrPlayTime=0, and PlayingOrStopped=SEQ_Playing. It will also load a correct stopping value into TotalPlayTime
- Notes: This function sets up variables that are used by repeat handler to determine if it is time to repeat.
- RepeatHandler
- RepeatHandler PROTO near C
- Purpose: This function will determine if the MIDI Track needs to repeat.
- Inputs: none
- Outputs: the status variable CurrPlayTime will be updated if need be.
- Notes: This function was coded in a general way to handle any track. Be we decided that it only needed to handle the dungeon track, so we added a line to only repeat that one.
- MIDRegister
- MIDRegister PROTO near C FileNameSeg:word, FileNameOffset:word
- Purpose: This function registers an XMI file for playback.
- Inputs: The Segment and Offset of the file name to load.
- Outputs: none
- Notes: the file is loaded with DOS calls, and registered with a MIDPAK call.
- CheckTrack
- CheckTrack PROTO near
- Purpose: This function checks the status of the currently playing track.
- Inputs: none
- Outputs: Status in AX
SEQ_STOPPED EQU 0
SEQ_PLAYING EQU 1
SEQ_DONE EQU 2
- Notes: this is primarily a MIDPAK call
- SetVolume
- SetVolume PROTO near C, Volume: word
- Purpose: This function checks the status of the currently playing track.
- Inputs: Volume - a value from 0 to 100 to play the track at
- Outputs: a new volume level
- Notes: this is primarily a MIDPAK call
- Stop
- Stop PROTO near C
- Purpose: This function stops the playback of the current track.
- Inputs: none
- Outputs: updates variable PlayingOrStopped
- Notes: this is primarily a MIDPAK call
Back to the main project page