Programming the Sound Blaster for

NET_PHONE

 (Sound.asm)  lines 1,997
(Sound.inc) lines 97
(Record Play Test) lines 292
(Scope Test) lines 172
(Wave Test) lines 220
2,778 lines of total code for project
 
 
 

Program Implementation
  1. Two Buffers Were used
    1. Used a FIFO / Queue for buffering data between a data stream (from network, microphone, or file)
    2. Used a Page aligned double buffer for DMA transfers to the Sound Card
  2. Program Flow Directed by Interrupts and SoundService
    1. Interrupts were used to x-fer data between FIFO and DMA-Buffer
    2. Service routines were used to direct data from other sources to FIFO, and to start, stop, and reconfigure initial playing and recording
    3. Other sources could also directly write/read from FIFO independently from the DMA x-fers

Challenges
Program Functionality
Structures
DMA_Type STRUCT 
  PageAddr     db ? 
  OffsetAddr   db ? 
  CountAddr    db ? 
  Reserved     db ?   ; used to align by 4 bytes 
DMA_Type ENDS
 Structure to hold information 
for DMA addresses the structure 
if filled in with a table below 
see DMA_Table
WavHdrStruct STRUC 
 format db 'RIFF' 
 filelen dd ? 
 wavefmt db 'WAVEfmt_' 
 fmt_len dd ? 
 fmt_tag dw ? 
 channel dw ? 
 samprt dd ?               ; sampeling rate 
 bytesps dd ?              ; bytes per second 
 bkalign dw ? 
 bitsps dw ?               ; bits per sample 
 data db 'data' 
 datalen dd ? 
WavHdrStruct Ends
 taken from Sbtest.asm

 
Procedures and Macros
SBP_MixerRead  Reads from the mixer data port on the sound card 
 al -> data read
SBP_MixerWrite  Writes to the mixer data port on the sound card 
 bl <- data to write
SBP_WaitRead  Polls the sound card to see if it is ready to be Read from
SBP_WaitWrite  polls the Sound Cards status register to see if it is ready 
 to be written to
SoundBuffer FIFO routines
BufGetSndReadAddr  This returns the offset address that can be read from 
 (used for playing by SBP routiens) 
 (used for recording or saving to disk or net by others) 
si -> returned with offset 
cx -> amount of data in the buffer that can be read 
 
BufGetSndWriteAddr  This returns the offset address that can be written to 
 (used for recording by SBP routiens) 
 (used for moving data that is going to be played by other routiens) 
di -> returned with offset 
cx -> max amount you can write 
 
BufReadSndData   Reads Sound data from SBP_buf to SoundBuf, 
 (used for recording by SBP routiens) 
 (used for moving data that is going to be played by other routiens) 

 ax <- number bytes to xfer 
 dx:[si] <- Start Of SBP_Buf or other location, 
    offset of location to read from 
    must be one continuous block (cannot overflow) 

 es:[di] == Start of SoundBuf, offset of WriteAddr 

 ax -> total data in buffer 
 bl -> 0 if not over flow, 1 if overflow 
 

BufWriteSndData   Reads Sound data from SoundBuf to SBP_buf or someplace else, 
 (used for playing by SBP routiens) 
   (used for recording or saving to disk or net by others) 

 ax <- number bytes to xfer 
 es:[di] <- Start Of SBP_Buf or other location, 
    offset of location to read from 
    must be one continuous block (cannot overflow) 

 ds:[si] == Start of SoundBuf, offset of ReadAddr 

 ax -> total data in buffer 
 bl -> 0 if not over flow, 1 if overflow 
 

BufSetup  Sets up the two buffers used to set up sound x-fers 
  ie. (SoundBuf, and SBP_Buf) 
 
BufReset  Resets the Sound Buffer to an intially empty state 
 
BufferMode  Used for finding out what mode SoundBuf is in 
 al <- BufMode STOP 0, PLAY 1, REC 2
DMA_Setup  Sets up a DMA transfer for a specifed DMA 

 Heavily adapted and reprogrammed from GPE {dma_vla.txt} 
   basically new code 
 

SBP_ResetDSP  Resets the DSP on the Sound Blaster Pro/16 
 note : mic is set to zero volume to kill feedback
SBP_GetSettings  Polls SBP16 PnP settings,  
 if SB16 isn't there default setting are used 
 later can change config for different settings 
 
SBP_InstallINT  Installs the Sound Card's interrupt handeler 
 
SBP_INThandler  The Sound Card's interrupt handeler 
 
SBP_UninstallINT  UnInstalls the Sound Card's interrupt handeler 
 
SBP_SetSampleRate  Sets or Resets the sound cards sample rate which is held 
 in the Variable SBP_RATE 
 SBP_RATE <- rate to play at or time const (if not SB16 
 
SBP_WriteDSPCmd  writes at byte (Low, High) to DSP 
 al <- command 
 bx <- data 
 
{SoundSetup}  Initalized the sound card and sets up the ISR proc 
 
{SoundDestroy}  Cleans up after the sound card when the program exits 
 
{SoundService}  This should be called fairlly frequently so buffers 
 can be updtated if needed, needed for playing WAVs 
 or for starting new SoundPlays from other programs 
 
{SoundPlayFlag}  Used to tell SoundService Routien that main program 
 would like to start playing as soon as the SoundBuf 
 has enough data in it 
 
{SoundPlay}  starts outputting sound for avialable data in SoundBuff 
 sound stops when output buffer is empty 
 
SoundPlayCont  called by Sound Interrupt to continue outputting sound 
 sound stopps when output buffer is empty 
 
SoundPlayEnd  Outputs sound of last part of SoundBuffer via the interrupt 
 
{SoundPlayWav}  Starts playing a WAVE file. to continue playing the file 
 SoundService must be called enough to reload the buffer 
 ds:[dx] <- pointer to ASCIIZ string 
 
SoundPlayWavCont  called only from SoundService when a wave file is in the 
 process of being played, copies new data to buffer 
 
{SoundRec}  Inputs sound via the interrupt until SoundBuffer is full 
 or a SoundRecStop is called 
 
SoundRecCont  Called by Interrupt to continue REC 
 
{SoundScope}  Shows a nifty sound scope, write to a block of memory 
 asummes video mode is in 8 bits/pix mode 
 ax <- ah = background color, al = forground color 
 bx <- cols (horizontal) 
 dx <- rows (vertical) 
 es:[di] <- start location 
 
{SoundSetInVol}  Set the mixers volume for 8-bit mono 
 bl <- Volume level  bits 2-3 = mic Volume SPB, 1-3 SB 16 
 
{SoundSetOutVol}  Set the mixers volume for 8-bit mono 
 bl <- Volume level  bits 0-3 = right Volume, 4-7 = left Volume 
 
{SoundTest}  outputs a tone directly to card to see if 
 it will do anything at all ( no interrupts needed ) 
 
{SoundStop}  Stops a Sound Transer and Halts DMA Interrupts 
 
ScreenDebug  Called whenever there is an error messege to print 
si <- offset of error message 
 

VARIABLES

; Sound Blaster Pro I/O port definition
SBP_Port        dw 0220h      ; 220 - 22F Default
SBP_INT         db 0Dh        ; INT 5h Default
SBP_INTMask     db 00100000b
SBP_INTInst     db 0          ; zero = not installed
SBP_DMA         db 5h
SBP_oldV        dd ?          ; saved interrupt vector
SBP_Rate        dw SPB_DEFAULT_SAMPLE_RATE
SBP_PICOffMask  db ?          ; PIC mask to restore when exiting
SBP_PICOnMask   db ?          ; PIC mask to turn on Interrupt

; DMA register locations
DMA_Table   DMA_Type  {87h,   0h,   1h},     ; DMA 0
                      {83h,   2h,   3h},     ; DMA 1
                      {81h,   4h,   5h},     ; DMA 2
                      {82h,   6h,   7h},     ; DMA 3
                      {8Fh, 0C0h, 0C2h},     ; DMA 4
                      {8Bh, 0C4h, 0C6h},     ; DMA 5
                      {89h, 0C8h, 0CAh},     ; DMA 6
                      {8Ah, 0CCh, 0CEh}      ; DMA 7

; Sound Buffer Tracking Vars
ReadAddr        dw ?              ; Offset for soundBuff
WriteAddr       dw ?              ; Offset for soundBuff
BufDataLength   dw ?              ; amount of new data in buffer
BufMode         db 0              ; 0 - none, 1 - Play, 2 - Rec

SBP_BufOffsetTP dw ?              ; top half of offset
SBP_BufOffsetBT dw ?              ; bottom half of offset
SBP_BufLen      dw ?              ; length of sound card buffer
SBP_DMAPage     db ?
SBP_DMAOffset   dw ?
SBP_Side        db 0              ; SBP is read/writing to 0 = top, 1 = bottom
SBP_SingleLen   dw ?              ; lenght of last single cycle xfer

; Wave file vars
WavRIFFstring   db 'RIFF'
WavFMTstring    db 'WAVEfmt '
WavDATAString   db 'data'
WavHeader       WavHdrStruct < >
WavOldRate      dw ?        ; old sampling rate
WavLengthLeft   dd ?

; File buffer vars
fileMode        db ?            ; WAV, NONE
fileBuffer      db 1024 dup (?) ;1024 dup (?)
fileHandle      dw ?

; Messages mostly errors                        ;
WriteTimeOutE_Msg db '00 ER: SB Write Timeout ','$'         ; write timeout {SBP_WaitWrite}
ReadTimeOutE_Msg  db '01 ER: SB Read Timeout','$'           ;SB Card Read Timeout {SBP_WaitRead}','$'
DPS_ResetE_Msg    db '02 ER: SB DSP not Reset ','$'
BufWOFlowE_Msg    db '03 ER: SB Write Buf OF', '$'          ; write buffer overflow
BufROFlowE_Msg    db '04 ER: SB Read Buffer OF',  '$'       ; read buffer overflow
SBP_IRQE_Msg      db '05 ER: SB IRQ Not Detected', '$'
SBP_DMAE_Msg      db '06 ER: SB DMA Not Detected', '$'
SBP_WavE_Msg      db '07 ER: WAV  Not Readable',  '$'
SBP_WavFileE_Msg  db '08 ER: {WAV} File in use',  '$'

; Sound Buffer for double buffered SBP data
SoundBuf          db 55000 dup (?)    ; sound buffer number 2