Rem File: Playwav.bas - for Dndbbs modules.
Rem $Include: 'dndbbs.inc'

COMMON SHARED BasePort%
COMMON SHARED Channel%

CONST PlayBuffer = 32767 ' maxint

COMMON SHARED WavBuffer() AS STRING * PlayBuffer

DIM SHARED SpeakerVolume AS INTEGER

REM Plays .wav files for blind or sight impaired people.

SUB Playwav(Tmp1)
 On Local Error Goto Play.Error

 ' Parse BLASTER environment variable
 Call GetBLASTER

 ' get playwav config variables
 Gosub Get.Config1

 If Option3 Then
    BasePort% = Option3
 Endif
 If Option4 Then
    Channel% = Option4
 Endif

 ' check disabled config variable
 If Option1=False Then
    Exit Sub
 Endif

 ' check command line
 If Left$(Ltrim$(Command$),1)="@" Then
    If Tmp1>=1 And Tmp1<=13 Then
       Sound Option21, Option22
    Endif
    Exit Sub
 Endif

 ' select .wav file
 Tmp1$ = Nul
 Select Case Tmp1
 Case 1
    Tmp1$="LASER.WAV"
 Case 2
    Tmp1$="RINGIN.WAV"
 Case 3
    Tmp1$="CARRIER.WAV"
 Case 4
    Tmp1$="BOING.WAV"
 Case 5
    Tmp1$="BANG.WAV"
 Case 6
    Tmp1$="CONNECT.WAV"
 Case 7
    Tmp1$="COMPLETE.WAV"
 Case 8
    Tmp1$="GUNSHOT.WAV"
 Case 9
    Tmp1$="RICOCHET.WAV"
 Case 10 ' a
    Tmp1$="WHOOSH.WAV"
 Case 11 ' b
    Tmp1$="GLASS.WAV"
 Case 12 ' c
    Tmp1$="CASHREG.WAV"
 Case 13 ' d
    Sound Option21, Option22
    Exit Sub
 Case 14 ' e
    If Disable.Play=-2 Then
       Exit Sub
    Endif
    Disable.Play=True
    Exit Sub
 Case 15 ' f
    If Disable.Play=-2 Then
       Exit Sub
    Endif
    Disable.Play=False
    Exit Sub
 Case Else
    Exit Sub
 End Select

 ' check playing turned off
 If Disable.Play Then
    Exit Sub
 Endif

 ' locate file
 IF Tmp1$ = Nul THEN
    EXIT SUB
 END IF
 Tmp2$ = DND.Path + Tmp1$
 IF DIR$(Tmp2$) = Nul THEN
    EXIT SUB
 END IF

 ' check blaster
 If BasePort% = 0% Then
    Exit Sub
 Endif

 ' open input file
 X = FREEFILE
 OPEN Tmp2$ FOR BINARY AS #X

 ' store length of buffer.
 REDIM WavBuffer(1 TO 1) AS STRING * PlayBuffer

 ' turn on speaker and adjust volume.
 Call AdjustVolume(SpeakerVolume)

 ' get buffer from file skipping header.
 GET #X, 44, WavBuffer(1)

 ' store memory address of sound buffer.
 Segment& = VARSEG(WavBuffer(1))
 Offset& = VARPTR(WavBuffer(1))

 ' store length of sound file minus header.
 Length& = LOF(X) - 44
 IF Length& > 32767 THEN Length& = 32767 'Adjust length if needed to 32k

 ' call the sound buffer player.
 CALL DMAPlay(Segment&, Offset&, Length&)

 ' wait for buffer to clear.
 T!=Timeit!
 Do
    If Time.Elapsed(T!,Option5!) Then
       Exit Do
    Endif
 Loop
 Close #X
 Erase WavBuffer
 EXIT SUB

Get.Config1:
 ' default blaster settings
 SpeakerVolume=13
 Option1=True
 Option2=13
 Option3=0
 Option4=0
 Option5!=1!
 ' sound frequency
 Option21 = 900
 ' sound duration
 Option22 = 6
 VarX=0
 Do
    VarX=VarX+1
    If VarX>Options.Lines Then
       Exit Do
    Endif
    Var$=Ltrim$(Rtrim$(Options.Array(VarX)))
    If Ucase$(Var$)="[EQUATE]" Then
       Do
          VarX=VarX+1
          If VarX>Options.Lines Then
             Return
          Endif
          Var$=Ltrim$(Rtrim$(Options.Array(VarX)))
          If Ucase$(Var$)="[END]" Then
             Return
          Endif
          Var=Instr(Var$,"=")
          If Var Then
             Var2$=Ltrim$(Rtrim$(Left$(Var$,Var-1)))
             Var3$=Ltrim$(Rtrim$(Mid$(Var$,Var+1)))
             Var4=Int(Val(Var3$)+.5)
             Select Case Lcase$(Var2$)
             Case "playwav"
                Select Case Lcase$(Var3$)
                Case "0", "false", "off"
                   Option1=0
                End Select
             Case "volume"
                If Var4>=1 And Var4<=15 Then
                   SpeakerVolume=Var4
                   Option2=Var4
                Endif
             Case "baseport"
                Option3=Int(Val("&H"+Var3$)+.5)
             Case "dmachannel"
                If Var4>=0 And Var4<=3 Then
                   Option4=Var4
                Endif
             Case "wavepause"
                If Var4>=1 And Var4<=9 Then
                   Option5!=Csng(Var4)
                Endif
             Case "sound.frequency"
                If Var4>=37 And Var4<=32767 Then
                   option21=Var4
                Endif
             Case "sound.duration"
                If Var4>=1 And Var4<=32767 Then
                   option22=Var4
                Endif
             End Select
          Endif
       Loop
    Endif
 Loop
 Return
Play.Resume:
 Exit Sub
Play.Error:
 Resume Play.Resume
END SUB

' plays the contents of the buffer.
SUB DMAPlay(Segment&, Offset&, Length&)
 Freq& = 10000
 Length& = Length& - 1
 Page% = 0
 MemLoc& = Segment& * 16 + Offset&
 SELECT CASE Channel%
 CASE 0
    PgPort% = &H87
    AddPort% = &H0
    LenPort% = &H1
    ModeReg% = &H48
 CASE 1
    PgPort% = &H83
    AddPort% = &H2
    LenPort% = &H3
    ModeReg% = &H49
 CASE 2
    PgPort% = &H81
    AddPort% = &H4
    LenPort% = &H5
    ModeReg% = &H4A
 CASE 3
    PgPort% = &H82
    AddPort% = &H6
    LenPort% = &H7
    ModeReg% = &H4B
 CASE ELSE
    EXIT SUB
 END SELECT
 OUT &HA, &H4 + Channel%
 OUT &HC, &H0
 OUT &HB, ModeReg%
 OUT AddPort%, MemLoc& AND &HFF
 OUT AddPort%,(MemLoc& AND &HFFFF&) \ &H100
 IF MemLoc& AND 65536 THEN
    Page% = Page% + 1
 END IF
 IF MemLoc& AND 131072 THEN
    Page% = Page% + 2
 END IF
 IF MemLoc& AND 262144 THEN
    Page% = Page% + 4
 END IF
 IF MemLoc& AND 524288 THEN
    Page% = Page% + 8
 END IF
 OUT PgPort%, Page%
 OUT LenPort%, Length& AND &HFF
 OUT LenPort%, (Length& AND &HFFFF&) \ &H100
 OUT &HA, Channel%

 TimeConst% = 256 - 1000000 \ Freq&
 V% = &H40
 Call WriteDSP(V%)

 V% = TimeConst%
 Call WriteDSP(V%)

 V% = &H14
 Call WriteDSP(V%)

 V% = Cint(Length& AND &HFF)
 Call WriteDSP(V%)

 V% = Cint((Length& AND &HFFFF&) \ &H100)
 Call WriteDSP(V%)
END SUB

' parse the BLASTER environment string and return settings.
SUB GetBlaster
 REM SET BLASTER=A220 I5 D1 H5 P330 T3 V9
 Var$ = Environ$("BLASTER")
 IF Var$ = "" THEN ' default values
    BasePort% = &H220
    Channel% = &H1
    SpeakerVolume = 13
    EXIT SUB
 END IF
 Var% = INSTR(Var$, "A") ' base IO port
 If Var% Then ' A220
    BasePort% = VAL("&H" + MID$(Var$, Var% + 1, 3))
 Endif
 Var% = INSTR(Var$, "D") ' 8-bit DMA channel
 If Var% Then ' D1
    Channel% = VAL(MID$(Var$, Var% + 1, 1))
 Endif
 SpeakerVolume=13
 Var% = INSTR(Var$, "V") ' speaker volume
 If Var% Then ' V1
    SpeakerVolume = VAL(MID$(Var$, Var% + 1))
 Endif
 Var$ = Environ$("BLASTERVOLUME")
 IF Len(Var$) THEN ' default volume
    SpeakerVolume=Int(Val(Var$)+.5)
 Endif

REM Gets the DSP version.
 ' Writes version request byte to the DSP
 Call WriteDSP (&HE1%)

 ' Reads version bytes from the DSP
 Call ReadDSP(Temp%)
 Call ReadDSP(Temp2%)

 DSPVersion! = VAL(STR$(Temp%) + "." + STR$(Temp2%))

 ' check blaster not found.
 If DSPVersion! = 255.255 Then
    BasePort% = 0%
 Endif
END SUB

' turn on speaker and adjust volume.
SUB AdjustVolume(Loudness%)
 ' Turn on speaker.
 V% = &HD1
 Call WriteDSP(V%)
 ' Adjust the volume.
 V% = Loudness% + Loudness% * 16 ' right/left
 OUT BasePort% + 4, &H22
 OUT BasePort% + 5, V% AND &HFF
END SUB

' writes a byte to the DSP (digital signal processor)
SUB WriteDSP (byte2%)
 DO
    VarX=VarX+1
    If VarX>1024 Then
       Exit Do
    Endif
 LOOP WHILE INP(BasePort% + 12) AND &H80
 OUT BasePort% + 12, byte2%
END SUB

' reads a byte from the DSP (digital signal processor)
SUB ReadDSP (byte2%)
 DO
    VarX=VarX+1
    If VarX>1024 Then
       Exit Do
    Endif
 LOOP WHILE INP(BasePort% + 14) AND &H80
 byte2% = INP(BasePort% + 10)
END SUB
