 Rem File: Cmd202.bas
 Rem Sub: Display.Memory
 Rem $Include: 'dndbbs.inc'
 Rem $Include: 'fat32.bi'

 On Error Goto Main.Error
 If Chained<>-2 Then
    Color 15,0
    Print "DNDBBS Command 202 -- Display.Memory."
    Color 7,0
    End
 Endif
 Call Display.Memory
Main.Resume:
 Chain DND.Path+"DNDBBS.EXE"
 End
Main.Error:
 Resume Main.Resume

Sub Display.Memory
 On Local Error Goto ErrorTrp40
 Gosub Get.Config1
 Graphics.Off=False
 Call System.Type
 Strng="System: "+Strng
 Call IO.O
 Call Get.Machine.Name(Var$)
 If Var$=Nul Then
    Var$="<none>"
 Endif
 Graphics.Off=True
 Strng="Machine: "+Rtrim$(Var$)
 Call IO.O
 Strng="Program: "+ProgramName$+" v"+Version$+" r"+Release$+" t"+Tweak$
 Call IO.O
 Strng="Task Mode: "+OSbit$
 Call IO.O
 Strng="Task Node: "
 If Rtrim$(NodeX)=Nul Then
    Strng=Strng+"-"
 Else
    Strng=Strng+NodeX
 Endif
 Call IO.O
 If BBS.Mode Then
    Strng="Door node: "
    If BBS.Mode=-2 Then
       Strng=Strng+"<telnet>"
    Else
       If Rtrim$(Door.Node)=Nul Then
          Strng=Strng+"-"
       Else
          Strng=Strng+Rtrim$(Door.Node)
       Endif
    Endif
    Call IO.O
    Strng=Rtrim$(Door.Name)
    If Len(Strng) Then
       Strng=Lcase$(Strng)
       Mid$(Strng,1,1)=Ucase$(Mid$(Strng,1,1))
       Strng="Door name: "+Strng
       Call IO.O
    Endif
 Endif
 Strng="Publish date: 01/01/2023"
 Call IO.O
 Call More.Prompt
 If No Or Quit Then
    Exit Sub
 Endif
 If Option1 Then
 Graphics.Off=False
 Strng="File system:"
 Call IO.O
 Graphics.Off=True
 Strng="Dnddat="+Config3(11) ' \dnddat
 Call IO.O
 Strng="Dnddoc="+Config3(52) ' \dnddoc
 Call IO.O
 ' \dndtemp (ram drive)
 If Drive.Override Then
    Strng="Dndtemp(RAM drive)="+Ucase$(Chr$(Drive.Override))+":\"
 Else
    Strng="Dndtemp(RAM drive)="+Config3(53)
 Endif
 Call IO.O
 Strng="Dndmess="+Config3(54) ' \dndmess
 Call IO.O
 Strng="Dnddoor="+Config3(84) ' \rbbs
 Call IO.O
 If Continuous=False Then
    Call More.Prompt
    If No Or Quit Then
       Exit Sub
    Endif
 Endif
 Endif
 If Option2 Then
 Graphics.Off=False
 Strng="Available system resources:"
 Call IO.O
 Graphics.Off=True
 If OS2.Detected=False Then
    Out2=Format$(Fre(-2),"#,##0;;")
    Strng="Stack space: "+Out2+" B."
    Call IO.O
 Endif
 If OS2.Detected Then
    Strng="OS/2 free memory."
    Call IO.O
 Else
    Call Get.Free.Memory
    Strng="Data space: "+Strng+"."
    Call IO.O
 Endif

 ' added 09/05/2021
 Call FreeSpace (1%, T2#)
 Call Make.Format(T2#)

 Strng="Total disk space: "+Strng+"."
 Call IO.O

 Call FreeSpace (2%, T1#)
 Call Make.Format(T1#)

 Strng="Free disk space: "+Strng+"."
 Call IO.O

 T3# = T2# - T1#
 Call Make.Format(T3#)

 Strng="Used disk space: "+Strng+"."
 Call IO.O

 If Continuous=False Then
    Call More.Prompt
    If No Or Quit Then
       Exit Sub
    Endif
 Endif
 Endif
 If Option3 Then
 Graphics.Off=False
 Strng="System settings:"
 Call IO.O
 Graphics.Off=True
 If Mouse.Present Then
    Strng="Mouse detected."
    Call IO.O
 Else
    Strng="Mouse not detected."
    Call IO.O
 Endif
 If Share.Installed Then
    Strng="Share installed."
    Call IO.O
 Else
    Call Plex.Function(16)
    If (OutregsX.AX And &HFF)=&HFF Then
       Strng="Share disabled."
       Call IO.O
    Else
       Strng="Share not installed."
       Call IO.O
    Endif
 Endif
 If Low.Mem.Use Then
    Strng="Low memory usage on."
 Else
    Strng="Low memory usage off.
 Endif
 Call IO.O
 If Supported.Call=False Then
    Strng="Windows timer installed."
    Call IO.O
 Endif
 If Equate.Debug Then
    Strng="Equate debug enabled."
    Call IO.O
 Endif
 If Config2(63) Then
    Strng="Equation parser on."
 Else
    Strng="Equation parser off."
 Endif
 Call IO.O
 Strng="Screen:"+Str$(Max.Row)+"x"+Mid$(Str$(User.LineLength),2)
 Call IO.O
 If Local.ANSI.Color Then
    Strng="Local ANSI color."
    Call IO.O
 Endif
 If Local.Avatar.Color Then
    Strng="Local Avatar color."
    Call IO.O
 Endif
 If Remote.ANSI.Color Then
    Strng="Remote ANSI color."
    Call IO.O
 Endif
 If Remote.Avatar.Color Then
    Strng="Remote Avatar color."
    Call IO.O
 Endif
 If Debug.Mode Then
    Strng="Debug mode on."
    Call IO.O
 Endif

 Call StdinInt(62,0)
 PSP.Segment=OutregsX.BX
 Def Seg=PSP.Segment
 X=Peek(&H32)
 Def Seg
 Strng="File handles:"+Str$(X-4)
 Call IO.O

 If Config2(55) Then
    Strng="Offline user fights on."
 Else
    Strng="Offline user fights off."
 Endif
 Call IO.O

 If Continuous=False Then
    Call More.Prompt
    If No Or Quit Then
       Exit Sub
    Endif
 Endif
 Endif

 If Local.Mode=False Then
    If Option4 Then
    Graphics.Off=False
    Strng="Modem comm info:"
    Call IO.O
    Graphics.Off=True
    Strng=" Comm:"+Str$(Port+1)+" (port:"+Str$(Port)+")"
    Call IO.O
    Strng=" Base: 0x"+Hex$(Base.Address)
    Call IO.O
    Strng=" Computer to modem:"+Str$(Modem.Baud)
    Call IO.O
    If BBS.Mode=False Then
       Strng=" Modem to modem: "+Modem.Return
       Call IO.O
    Endif
    If BBS.Mode = -1 Then
       Strng=" Modem: (door)"
       Call IO.O
    Endif
    If BBS.Mode = -2 Then
       Strng=" Modem: (telnet)"
       Call IO.O
    Endif
    Strng="No"
    If Fossil.Active Then
       Strng="Yes"
       If Fossil.Active=1 Then
          Strng=Strng+": X00"
       Endif
    Endif
    Strng=" Fossil active: "+Strng+"."
    Call IO.O

    If Continuous=False Then
       Call More.Prompt
       If No Or Quit Then
          Exit Sub
      Endif
    Endif
    Endif
 Endif

 If Option5 Then
 Call GetBlaster (BasePort%, Channel%, SpeakerVolume, DSPVersion!, IRQ%, CardType)
 ' check blaster not found.
 If DSPVersion!=255.255 Then
    BasePort% = 0%
 Endif
 If BasePort% > 0% Then
    Graphics.Off=False
    Strng="Blaster info:"
    Call IO.O
    Graphics.Off=True
    Select Case CardType
    Case 1
       Strng="Sound Blaster 1.5"
    Case 2
       Strng="Sound Blaster Pro I"
    Case 3
       Strng="Sound Blaster 2.0"
    Case 4
       Strng="Sound Blaster Pro II"
    Case 5
       Strng="Sound Blaster Pro II/FM"
    Case 6
       Strng="Sound Blaster 16/AWE 32/32/64"
    Case Else
       Strng="Sound Blaster 2.0"
    End Select
    Strng="Card type: "+Strng
    Call IO.O

    Strng="DSP version:"+Str$(DSPVersion!)
    Call IO.O
    Strng="Baseport: 0x"+Hex$(BasePort%)
    Call IO.O
    Strng="Channel:"+Str$(Channel%)
    Call IO.O
    Strng="IRQ:"+Str$(IRQ%)
    Call IO.O
    Strng="Volume:"+Str$(SpeakerVolume)
    Call IO.O

    If Continuous=False Then
       Call More.Prompt
       If No Or Quit Then
          Exit Sub
       Endif
    Endif
 Endif
 Endif

 If Option6 Then
 Graphics.Off=False
 Strng="Environment info:"
 Call IO.O
 Graphics.Off=True
 TempC=1
 TempD=False
 VarQ=0
 Store.LineLength=User.LineLength
 Do
    VarQ=VarQ+1
    VarQ$ = ENVIRON$(VarQ)
    IF VarQ$ = "" THEN EXIT DO
    Strng=VarQ$
    If Len(Strng) Then
       If Len(Strng)>Store.LineLength Then
          User.LineLength=Len(Strng)+1
       Else
          User.LineLength=Store.LineLength
       Endif
       LengthX=Int(Len(Strng) \ 80)
       Graphics.Off=True
       Call IO.O
       If Continuous=False Then
          TempC=TempC+LengthX+1
          If TempC>=User.Pagelength-2 Then
             TempC=False
             Call More.Prompt
             If No Or Quit Then
                Exit Do
             Endif
          Endif
       Endif
    Endif
 Loop
 User.LineLength=Store.LineLength
 If Continuous=False Then
    Call More.Prompt
    If No Or Quit Then
       Exit Sub
    Endif
 Endif
 Endif

 If Option7 Then
 If Debug.Mode Then
    Graphics.Off=False
    Strng="Debug info:"
    Call IO.O
    Graphics.Off=True
    Strng="Inline.filename1="+Inline.Filename1
    Call IO.O
    Strng="Inline.filename2="+Inline.Filename2
    Call IO.O
    Strng="Video page="+Right$("0000"+Hex$(Video.Page),4)+"H"
    Call IO.O
    Call VideoInt(15,0)
    Var=OutregsX.AX And &HFF
    Strng="Video mode="+Right$("0000"+Hex$(Var),4)+"H"
    Call IO.O
    If Continuous=False Then
       Call More.Prompt
    Endif
 Endif
 Endif
 Graphics.Off=True
 Exit Sub
Get.Config1:
 VarX=0
 Gosub Reset.Options
 Do
    VarX=VarX+1
    If VarX>Options.Lines Then
       Goto Next.Read
       Exit Do
    Endif
    Var$=Ltrim$(Rtrim$(Options.Array(VarX)))
    If Ucase$(Var$)="[CMD202]" Then
       Do
          VarX=VarX+1
          If VarX>Options.Lines Then
             Goto Next.Read
             Return
          Endif
          Var$=Ltrim$(Rtrim$(Options.Array(VarX)))
          If Ucase$(Var$)="[END]" Then
             Goto Next.Read
             Return
          Endif
          Var=Instr(Var$,"=")
          If Var Then
             Var2$=Ltrim$(Rtrim$(Left$(Var$,Var-1)))
             Var3$=Ltrim$(Rtrim$(Mid$(Var$,Var+1)))
             Gosub Parse.Options
          Endif
       Loop
    Endif
 Loop
 Return
Next.Read:
 Close #TempFile1
 Filename$=DND.Path+"CMD202.CFG"
 If Dir$(Filename$)="" Then
    Return
 Endif
 Open Filename$ For Input As #TempFile1
 Do
    If Eof(TempFile1) Then
       Exit Do
    Endif
    Line Input #TempFile1, Var$
    Var$=Ltrim$(Rtrim$(Var$))
    If Left$(Var$,1)<>";" Then
       VarX$=UserRecord.CodeName
       VarX$=Rtrim$(VarX$)
       VarX$=Ucase$(VarX$)
       If Ucase$(Var$)="["+VarX$+"]" Then
          VarZ=0
          Gosub Reset.Options
          Do
             If Eof(TempFile1) Then
                Exit Do
             Endif
             Line Input #TempFile1, Var$
             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)))
                Gosub Parse.Options
             Endif
          Loop
       Endif
    Endif
 Loop
 Return
Parse.Options:
 Select Case Lcase$(Var2$)
 Case "display.file.system"
    Select Case Lcase$(Var3$)
    Case "0", "false", "off"
       Option1=0
    End Select
 Case "display.system.resources"
    Select Case Lcase$(Var3$)
    Case "0", "false", "off"
       Option2=0
    End Select
 Case "display.system.settings"
    Select Case Lcase$(Var3$)
    Case "0", "false", "off"
       Option3=0
    End Select
 Case "display.comm.info"
    Select Case Lcase$(Var3$)
    Case "0", "false", "off"
       Option4=0
    End Select
 Case "display.blaster.info"
    Select Case Lcase$(Var3$)
    Case "0", "false", "off"
       Option5=0
    End Select
 Case "display.environment.info"
    Select Case Lcase$(Var3$)
    Case "0", "false", "off"
       Option6=0
    End Select
 Case "display.debug.info"
    Select Case Lcase$(Var3$)
    Case "0", "false", "off"
       Option7=0
    End Select
 End Select
 Return
Reset.Options:
 Option1=-1
 Option2=-1
 Option3=-1
 Option4=-1
 Option5=-1
 Option6=-1
 Option7=-1
 Return
ErrorRsm40:
 Exit Sub
ErrorTrp40:
 Resume ErrorRsm40
End Sub

Sub System.Type
 On Local Error Goto ErrTrap11
 If Windows.Detected Then
    If Win.Major=4 Then
       If Win.Minor>10 Then
          Strng="Win ME"
       Else
          If Win.Minor=10 Then
             Strng="Win 98"
          Else
             If Win.Minor=3 Then
                Strng="Win 95B"
             Else
                Strng="Win 95"
             Endif
          Endif
       Endif
    Else
       If Win.Major>4 Then
          Strng="WinX" ' OS past 98
       Else
          If Win.Major=0 And Win.Minor=0 Then
             Win.Major=3 : Win.Minor=1
          Endif
          Strng="Win"+Str$(Win.Major)+"."+Ltrim$(Str$(Win.Minor))
       Endif
    Endif
    Exit Sub
 Endif
 Select Case DOS.Major
 Case 10
    Strng="OS/2 v1.0"
 Case 20
    Strng="OS/2 v2.0"
    Select Case DOS.Minor
    Case 30
       Strng="OS/2 v3.0"
    Case 40
       Strng="OS/2 v4.0"
    End Select
 Case 30
    Strng="Mac OSX"
 Case 40
    Strng="Linux"
 Case 50
    Strng="SunOS"
 Case Else
    Strng="DOS"+Str$(DOS.Major)+"."+Ltrim$(Str$(DOS.Minor))
 End Select
ErrResume11:
 Exit Sub
ErrTrap11:
 Resume ErrResume11
End Sub

' store default server name
Sub Get.Machine.Name(VarX$)
 On Local Error Goto ErrorTrap19z
 DIM Default.Net AS STRING * 16
 VarX$ = Nul
 Default.Net = Nul
 InregsX.AX = &H5E00
 InregsX.DS = VARSEG(Default.Net)
 InregsX.DX = VARPTR(Default.Net)
 CALL InterruptX(&H21, InregsX, OutregsX)
 ' check error flag.
 IF (OutregsX.Flags AND &H1) = &H0 THEN
    ' read CH
    VarS = (OutregsX.CX AND &HFF00) / 256
    IF VarS > 0 THEN ' valid name.
       VarX$ = Default.Net
       Imbedded = INSTR(VarX$, CHR$(0))
       IF Imbedded THEN
          VarX$ = LEFT$(VarX$, Imbedded - 1)
       END IF
       VarX$ = UCASE$(RTRIM$(VarX$))
       EXIT SUB
    END IF
 END IF
 ' check net path.
 If VarX$ = Nul Then
    Var$ = Environ$("COMPUTERNAME")
    If Len(Var$) Then
       VarX$ = Var$
    Endif
 Endif
ErrorResume19z:
 Exit Sub
ErrorTrap19z:
 Resume ErrorResume19z
End Sub

Sub Make.Format(Var#)
 On Local Error Goto ErrTrap13
 Var2#=Var#
 If Var2#=0 Then
    Strng="0.00 B"
    Exit Sub
 Endif
 If Var2#<0# Then
    Sign=-1
    Var2#=Abs(Var2#)
 Endif
 TempA=False
 Do
    If Var2#<1024# Then
       Exit Do
    Endif
    Var2#=Var2#/1024#
    TempA=TempA+1
    If TempA=8 Then
       Exit Do
    Endif
 Loop
 Strng=Nul
 If TempA>=1 And TempA<=8 Then
    Strng=Mid$("KMGTPEZY",TempA,1)
 Endif
 Strng=Format$(Var2#,"#,##0.00;;")+" "+Strng+"B"
 If Sign Then
    Strng="-"+Strng
 Endif
ErrResume13:
 Exit Sub
ErrTrap13:
 Resume ErrResume13
End Sub

Sub Get.Free.Memory
 On Local Error Goto ErrTrap12
 Strng=Nul
 If OS2.Detected Then ' has no freespace
    Strng="256.00 KB"
 Else
    Temp#=Cdbl(TempX!)
    Call Make.Format(Temp#)
 Endif
ErrResume12:
 Exit Sub
ErrTrap12:
 Resume ErrResume12
End Sub

' get drive freespace (modified 12/09/2022)
SUB FreeSpace (T%, T#)
 On Local Error Goto DriveError
 Dim ASCIIZ As String * 260

 ' declare structures
 Dim FAT32struc AS FAT32Type

 Temp.Path$=Environ$("DNDBBS")
 If Temp.Path$<>Nul Then
    If Right$(Temp.Path$,1)<>"\" Then
       Temp.Path$=Temp.Path$+"\"
    Endif
 Endif
 If Temp.Path$="" Then
    Temp.Path$=CURDIR$
 Endif
 ' get drive letter
 T# = 0#
 D$ = Left$(Temp.Path$,1)
 D$ = Ucase$(D$)
 If D$>="A" And D$<="Z" Then
    V = Asc(D$) - 64
 Else
    V = 3
 Endif

 ' get FAT32 drive space
 ASCIIZ = CHR$(V + 64) + ":\" + CHR$(0)
 InregsX.AX = &H7303
 InregsX.DS = VARSEG(ASCIIZ)
 InregsX.DX = VARPTR(ASCIIZ)
 InregsX.ES = VARSEG(FAT32Struc)
 InregsX.DI = VARPTR(FAT32Struc)
 InregsX.CX = LEN(FAT32Struc)
 CALL InterruptX(&H21, InregsX, OutregsX)
 IF (OutregsX.Flags AND &H1) = &H0 THEN
    If T% = 1 Then
       Bytes# = CLNG(ASC(MID$(FAT32Struc.BytesPerSector, 1, 1)))
       Bytes# = Bytes# + CLNG(ASC(MID$(FAT32Struc.BytesPerSector, 2, 1))) * 256#
       Bytes# = Bytes# + CLNG(ASC(MID$(FAT32Struc.BytesPerSector, 3, 1))) * 65536#
       Bytes# = Bytes# + CLNG(ASC(MID$(FAT32Struc.BytesPerSector, 4, 1))) * 16777216#
       Sectors# = CLNG(ASC(MID$(FAT32Struc.TotalSectors, 1, 1)))
       Sectors# = Sectors# + CLNG(ASC(MID$(FAT32Struc.TotalSectors, 2, 1))) * 256#
       Sectors# = Sectors# + CLNG(ASC(MID$(FAT32Struc.TotalSectors, 3, 1))) * 65536#
       Sectors# = Sectors# + CLNG(ASC(MID$(FAT32Struc.TotalSectors, 4, 1))) * 16777216#
       T# = Bytes# * Sectors#
    END IF
    If T% = 2 Then
       Bytes# = CLNG(ASC(MID$(FAT32Struc.BytesPerSector, 1, 1)))
       Bytes# = Bytes# + CLNG(ASC(MID$(FAT32Struc.BytesPerSector, 2, 1))) * 256#
       Bytes# = Bytes# + CLNG(ASC(MID$(FAT32Struc.BytesPerSector, 3, 1))) * 65536#
       Bytes# = Bytes# + CLNG(ASC(MID$(FAT32Struc.BytesPerSector, 4, 1))) * 16777216#
       Sectors# = CLNG(ASC(MID$(FAT32Struc.FreeSectors, 1, 1)))
       Sectors# = Sectors# + CLNG(ASC(MID$(FAT32Struc.FreeSectors, 2, 1))) * 256#
       Sectors# = Sectors# + CLNG(ASC(MID$(FAT32Struc.FreeSectors, 3, 1))) * 65536#
       Sectors# = Sectors# + CLNG(ASC(MID$(FAT32Struc.FreeSectors, 4, 1))) * 16777216#
       T# = Bytes# * Sectors#
    END IF
    IF T# THEN
       EXIT SUB
    END IF
 END IF

 ' check disk space.
 InregsX.AX = &H3600
 InregsX.DX = V
 CALL InterruptX(&H21, InregsX, OutregsX)
 ' check drive exists.
 IF OutregsX.AX = &HFFFF THEN
    T# = 0#
 ELSE
    ' Note: FAT16 only reports up to 2 GB.
    '  Registers can report up to 256 TB.
    If T% = 1 Then ' total
       ' total space on drive in bytes is AX * CX * DX adjusted signed-int
       T1# = OutregsX.AX: IF T1# < 0# THEN T1# = T1# + 65536#
       T2# = OutregsX.CX: IF T2# < 0# THEN T2# = T2# + 65536#
       T3# = OutregsX.DX: IF T3# < 0# THEN T3# = T3# + 65536#
       T# = T1# * T2# * T3#
    Endif
    If T% = 2 Then ' free
       ' free space on drive in bytes is AX * BX * CX adjusted signed-int
       T1# = OutregsX.AX: IF T1# < 0# THEN T1# = T1# + 65536#
       T2# = OutregsX.BX: IF T2# < 0# THEN T2# = T2# + 65536#
       T3# = OutregsX.CX: IF T3# < 0# THEN T3# = T3# + 65536#
       T# = T1# * T2# * T3#
    Endif
 END IF
DriveResume:
 IF T#=0# Then
    T#=256*1024^2
 Endif
 Exit Sub
DriveError:
 Resume DriveResume
END SUB

' parse the BLASTER environment string and return settings.
SUB GetBlaster (BasePort%, Channel%, SpeakerVolume, DSPVersion!, IRQ%, CardType)

 REM SET BLASTER=A220 I5 D1 H5 P330 T3 V9
 BasePort% = &H220
 Channel% = &H1
 IRQ% = 7
 SpeakerVolume = 13
 Var$ = Environ$("BLASTER")
 If Var$ = "" Then
    BasePort% = 0%
    Exit Sub
 Endif
 If Var$ = "A0" Then
    BasePort% = 0%
    Exit Sub
 Endif
 IF Var$ <> "" THEN ' default values
    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
    Var% = INSTR(Var$, "I") ' IRQ
    If Var% Then ' I7
       IRQ% = VAL(MID$(Var$, Var% + 1, 1))
    Endif
    Var% = INSTR(Var$, "T") ' cardtype
    If Var% Then ' T3
       CardType = 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
 END IF

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

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

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

 Var$ = Environ$("BLASTERVOLUME")
 IF Len(Var$) THEN ' default volume
    SpeakerVolume=Int(Val(Var$)+.5)
 Endif
END SUB

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

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