'Resource Interchange File Format
DECLARE SUB WaveInfo ()
DECLARE FUNCTION NewResetDSP% ()
DECLARE SUB ResetDSP ()
DECLARE SUB ResetMix ()
DECLARE FUNCTION ReadDSP% ()
DECLARE SUB WriteDSP (what%)
DECLARE SUB VoiceVol (Left%, Right%, Set%)
DECLARE SUB MasterVol (Left%, Right%, Set%)
DECLARE SUB MidiVol (Left%, Right%, Set%)
DECLARE SUB CdVol (Left%, Right%, Set%)
DECLARE SUB LineVol (Left%, Right%, Set%)
DECLARE SUB InputFilter (State%, Set%)
DECLARE FUNCTION DSPVersion! ()
DECLARE SUB SpeakerState (State%, Set%)
DECLARE SUB InputMode (MonoStereo%)
DECLARE SUB StereoSwitch (MonoStereo%)
DECLARE SUB OutputFilter (State%, Set%)
DECLARE SUB ExitDMAMode (DMAMode816%)
DECLARE SUB ResumeDMAMode (DMAMode816%)
DECLARE SUB PauseDMAMode (DMAMode816%)
DECLARE SUB ProcessInit (DMAMode%, DMAIncrement%, DMAInitialize%, DMATransfer%, MonoStereo%, Sampling&)
DECLARE SUB AckInterrupt ()
DECLARE SUB DMAStart (Length&)
DECLARE FUNCTION DMAOver% (Length&)
DECLARE SUB DMAPaging (Buffer%)
DECLARE FUNCTION IntegerToLong& (int1%)
DECLARE SUB DSP8bitMonoSingleCycle (Length&)
DECLARE SUB DSP8bitStereoHighSpeed (Length&)
DECLARE SUB ConvStereo8 (Buffer%, Length&)
DECLARE SUB ConvMono16 (Buffer%, Length&)
DECLARE SUB ConvStereo16 (Buffer%, Length&)
DECLARE SUB Convert (Buffer%, Length&)
DECLARE SUB VolumeConv (Buffer%, Length&, Volume!)
DECLARE SUB PalleteInit ()


CONST BufferSize = 32764, BufferSizem2 = 65528, BufferSized2 = 16382, BifferSizem4 = 131056


TYPE WaveID
        RiffID AS STRING * 4
        RiffSize AS LONG
        WaveID AS STRING * 4
        FmtID AS STRING * 4
        FmtSize AS LONG
        AudioFmt AS INTEGER
        NumChannels AS INTEGER
        SampleRate AS LONG
        ByteRate AS LONG
        BlockAlign AS INTEGER
        BitsPerSample AS INTEGER
        DataID AS STRING * 4
        DataSize AS LONG
END TYPE
DIM SHARED DSPBase%, DSPReset%, DSPRead%, DSPWrite%, DSPReadBuffer%, DSPWriteBuffer%
DIM SHARED MixAddress%, MixData%, DMAChannel%, DMAPageReg%, DMAAddressReg%, DMACountReg%
DIM SHARED DMAMaskReg%, DMAModeReg%, DMAClearReg%, DMAMasked%, DMAUnMasked%
DIM SHARED DMAModeData%, DSPTimeConstant%, DMAPage%, DMAOffhigh%, DMAOfflow%
DIM SHARED WaveFile(0) AS WaveID
DIM SHARED WaveBuffer1(1) AS STRING * BufferSize
DIM SHARED WaveBuffer2(1) AS STRING * BufferSize
DIM SHARED Stereo%, Bit16%, Stereo8%

SCREEN 13
PalleteInit
IF NewResetDSP% THEN PRINT "SoundBlaster is found." ELSE PRINT "SoundBlaster not found!": SYSTEM
PRINT "Sound Blaster Music"
PRINT "-------------------"
PRINT "Version:"; DSPVersion!
PRINT "Blaster :"; ENVIRON$("BLASTER")
MasterVol 15, 15, -1
PRINT "Wave File"
PRINT "---------"
DMAChannel% = 1

INPUT "File Name"; fl1$
OPEN "B", #1, fl1$
IF (LOF(1) = 0) THEN CLOSE #1: SYSTEM

'Get Wave Information
GET #1, 1, WaveFile(0)
WaveInfo
Stereo% = WaveFile(0).NumChannels - 1
Bit16% = WaveFile(0).BlockAlign \ WaveFile(0).NumChannels - 1
TransferLength& = BufferSizem2 \ WaveFile(0).BlockAlign
SpeakerState 1, -1
DataLength& = LOF(1) - (45 + WaveFile(0).FmtSize - 16)
LengthFile# = LOF(1)

Stereo8% = 1
'Select Mode
INPUT "Volume"; Volume!


IF Stereo% THEN
PRINT "Wave file is stereo."
PRINT "1 - Left"
PRINT "2 - Right"
PRINT "3 - Mixed"
PRINT "x - Hmixed"
INPUT "Select Mode"; Stereo8%
END IF


'Process Start
IF Stereo8% > 3 OR Stereo8% < 1 THEN
WaveFile(0).SampleRate = 2 * WaveFile(0).SampleRate
IF Bit16% THEN TransferLength& = BufferSize ELSE TransferLength& = BufferSizem2
END IF

'Process Initialization
SEEK #1, 45 + WaveFile(0).FmtSize - 16
ProcessInit 1, 0, 0, 1, 0, WaveFile(0).SampleRate

'Initial Play
IF (DataLength& < BufferSizem2) THEN GOTO FinalPlay
GET #1, , WaveBuffer2(0)
GET #1, , WaveBuffer2(1)
DMAPaging 2
Convert 2, BufferSizem2
VolumeConv 2, TransferLength&, Volume!
DSP8bitMonoSingleCycle TransferLength&
DataLength& = DataLength& - BufferSizem2

'Looped Play
DO
IF (DataLength& < BufferSizem2) THEN GOTO FinalPlay
GET #1, , WaveBuffer1(0)
GET #1, , WaveBuffer1(1)
DMAPaging 1
Convert 1, BufferSizem2
VolumeConv 1, TransferLength&, Volume!
DO
GOSUB InTime
LOOP UNTIL DMAOver%(TransferLength&)
DSP8bitMonoSingleCycle TransferLength&
DataLength& = DataLength& - BufferSizem2

IF (DataLength& < BufferSizem2) THEN GOTO FinalPlay
GET #1, , WaveBuffer2(0)
GET #1, , WaveBuffer2(1)
DMAPaging 2
Convert 2, BufferSizem2
VolumeConv 2, TransferLength&, Volume!
DO
GOSUB InTime
LOOP UNTIL DMAOver%(TransferLength&)
DSP8bitMonoSingleCycle TransferLength&
DataLength& = DataLength& - BufferSizem2
LOOP

'Final Play
FinalPlay:
DO
GOSUB InTime
LOOP UNTIL DMAOver%(TransferLength&)
GET #1, , WaveBuffer1(0)
GET #1, , WaveBuffer1(1)
DMAPaging 1
Convert 1, BufferSizem2
VolumeConv 1, TransferLength&, Volume!
DSP8bitMonoSingleCycle DataLength&
DataLength& = 0
PRINT "Data Left:"; DataLength&
DO
GOSUB InTime
LOOP UNTIL DMAOver%(TransferLength&)
Exita:
SpeakerState 0, -1
ExitDMAMode 0
ResetDSP

CLOSE #1
PRINT "All Done"
k$ = INPUT$(1)
SYSTEM


'In time drawing
InTime:
k$ = INKEY$
IF k$ <> "" THEN GOSUB KeyHandle
'Ima
'PRINT
r% = (r% + 1) MOD 100
k = k + .01
IF (k > 3000) THEN k = 0
FOR i = 0 TO 6.29 STEP .05
PSET (150 + r% * (TAN(i) - TAN(k)), 100 + r% * (TAN(i) + TAN(k))), 0
PSET (150 + r% * (COS(i) - TAN(k)), 100 + r% * (SIN(i) + TAN(k))), 255 * COS(i)
NEXT
'LINE (1, 195)-(318, 198), 0, BF
LINE (0, 194)-(319, 199), 15, B
LINE (1, 195)-((319 / LengthFile#) * DataLength&, 198), CINT(k) MOD 256, BF
RETURN

KeyHandle:
k$ = LCASE$(k$)
SELECT CASE k$
CASE CHR$(27)
GOTO Exita
CASE "p"
PauseDMAMode 0
CASE "r"
PauseDMAMode 1
CASE ELSE
END SELECT
RETURN

SUB AckInterrupt
IF (DMAChannel% <= 3) THEN Ack% = INP(DSPBase% + &HE) ELSE Ack% = INP(DSPBase% + &HF)
'OUT &H20, &H20
END SUB

SUB CdVol (Left%, Right%, Set%)
OUT MixAddress%, &H28
IF Set% THEN
a% = Left% * &H10 + Right%
OUT MixDtata%, a%
ELSE
a% = INP(MixData%)
Left% = a% \ &H10
Right% = a% AND &HF
END IF
END SUB

SUB Convert (Buffer%, Length&)
IF Bit16% AND Stereo% THEN
ConvStereo16 Buffer%, Length&
ELSEIF Bit16% THEN
ConvMono16 Buffer%, Length&
ELSEIF Stereo% THEN
ConvStereo8 Buffer%, Length&
END IF
END SUB

SUB ConvMono16 (Buffer%, Length&)
IF (Buffer% = 1) THEN
DEF SEG = VARSEG(WaveBuffer1(0))
ELSE
DEF SEG = VARSEG(WaveBuffer2(0))
END IF
x& = 0
FOR i& = 1 TO Length& - 1 STEP 2
POKE x&, (PEEK(i&) + &H80) AND &HFF
x& = x& + 1
NEXT
END SUB

SUB ConvStereo16 (Buffer%, Length&)
IF (Buffer% = 1) THEN
DEF SEG = VARSEG(WaveBuffer1(0))
ELSE
DEF SEG = VARSEG(WaveBuffer2(0))
END IF
x& = 0
SELECT CASE Stereo8%
CASE 1
FOR i& = 1 TO Length& - 1 STEP 4
POKE x&, (PEEK(i&) + &H80) AND &HFF
x& = x& + 1
NEXT
CASE 2
FOR i& = 3 TO Length& - 1 STEP 4
POKE x&, (PEEK(i&) + &H80) AND &HFF
x& = x& + 1
NEXT
CASE 3
FOR i& = 1 TO Length& - 1 STEP 4
POKE x&, (((PEEK(i&) + &H80) AND &HFF) + ((PEEK(i& + 2) + &H80) AND &HFF)) \ 2
x& = x& + 1
NEXT
CASE ELSE
FOR i& = 1 TO Length& - 1 STEP 4
POKE x&, (PEEK(i&) + &H80) AND &HFF
POKE x& + 1, (PEEK(i& + 2) + &H80) AND &HFF
x& = x& + 2
NEXT
END SELECT
DEF SEG
END SUB

SUB ConvStereo8 (Buffer%, Length&)
IF (Buffer% = 1) THEN
DEF SEG = VARSEG(WaveBuffer1(0))
ELSE
DEF SEG = VARSEG(WaveBuffer2(0))
END IF
x& = 0
SELECT CASE Stereo8%
CASE 1
FOR i& = 0 TO Length& - 1 STEP 2
POKE x&, PEEK(i&)
x& = x& + 1
NEXT
CASE 2
FOR i& = 1 TO Length& - 1 STEP 2
POKE x&, PEEK(i&)
x& = x& + 1
NEXT
CASE 3
FOR i& = 0 TO Length& - 1 STEP 2
POKE x&, (PEEK(i&) + PEEK(i& + 1)) \ 2
x& = x& + 1
NEXT
CASE ELSE
END SELECT
DEF SEG
END SUB

FUNCTION DMAOver% (Length&)
count& = INP(DMACountReg%) + CLNG(INP(DMACountReg%)) * &H100
IF (count& > Length& - 1) THEN
AckInterrupt
DMAOver% = -1
END IF
END FUNCTION

SUB DMAPaging (Buffer%)
IF (Buffer% = 1) THEN
a1& = IntegerToLong&(VARSEG(WaveBuffer1(0))) * &H10 + IntegerToLong&(VARPTR(WaveBuffer1(0)))
ELSE
a1& = IntegerToLong&(VARSEG(WaveBuffer2(0))) * &H10 + IntegerToLong&(VARPTR(WaveBuffer2(0)))
END IF
DMAPage% = a1& \ &H10000
DMAOffhigh% = (a1& AND &HFF00) \ &H100
DMAOfflow% = a1& AND &HFF
END SUB

SUB DMAStart (Length&)
OUT DMAMaskReg%, DMAMasked%
OUT DMAClearReg%, 0
OUT DMAModeReg%, DMAModeData%
OUT DMAAddressReg%, DMAOfflow%
OUT DMAAddressReg%, DMAOffhigh%
OUT DMAPageReg%, DMAPage%
OUT DMACountReg%, (Length& - 1) AND &HFF
OUT DMACountReg%, (Length& - 1) \ &H100
OUT DMAMaskReg%, DMAUnMasked%
WriteDSP &H40
WriteDSP DSPTimeConstant%
END SUB

SUB DSP8bitMonoSingleCycle (Length&)
DMAStart Length&
WriteDSP &H14
WriteDSP ((Length& - 1) AND &HFF)
WriteDSP ((Length& - 1) \ &H100)
END SUB

SUB DSP8bitStereoHighSpeed (Length&)
DMAStart Length&
WriteDSP &H91
WriteDSP ((Length& - 1) AND &HFF)
WriteDSP ((Length& - 1) \ &H100)
END SUB

FUNCTION DSPVersion!
WriteDSP &HE1
a! = ReadDSP% + ReadDSP% * .01
DSPVersion! = a!
END FUNCTION

SUB ExitDMAMode (DMAMode816%)
IF DMAMode816% THEN WriteDSP &HD9 ELSE WriteDSP &HDA
END SUB

SUB InputFilter (State%, Set%)
OUT MixAddress%, &HC
a% = INP(MixData%)
IF Set% THEN
a% = a% AND &HDF
a% = a% OR State%
OUT MixData%, a%
ELSE
State% = (a% AND &H20) \ &H20
END IF
END SUB

SUB InputMode (MonoStereo%)
IF MonoStereo% THEN WriteDSP &HA8 ELSE WriteDSP &HA0
END SUB

FUNCTION IntegerToLong& (int1%)
IF (int1% >= 0) THEN a1& = int1% ELSE a1& = 65536 + CLNG(int1%)
IntegerToLong& = a1&
END FUNCTION

SUB LineVol (Left%, Right%, Set%)
OUT MixAddress%, &H2E
IF Set% THEN
a% = Left% * &H10 + Right%
OUT MixDtata%, a%
ELSE
a% = INP(MixData%)
Left% = a% \ &H10
Right% = a% AND &HF
END IF
END SUB

SUB MasterVol (Left%, Right%, Set%)
OUT MixAddress%, &H22
IF Set% THEN
a% = Left% * &H10 + Right%
OUT MixDtata%, a%
ELSE
a% = INP(MixData%)
Left% = a% \ &H10
Right% = a% AND &HF
END IF
END SUB

SUB MidiVol (Left%, Right%, Set%)
OUT MixAddress%, &H26
IF Set% THEN
a% = Left% * &H10 + Right%
OUT MixDtata%, a%
ELSE
a% = INP(MixData%)
Left% = a% \ &H10
Right% = a% AND &HF
END IF
END SUB

FUNCTION NewResetDSP%
FOR i% = &H210 TO &H280 STEP &H10
OUT i% + &H6, 1
OUT i% + &H6, 0
Expect% = 0
DO
Expect% = Expect% + 1
LOOP UNTIL (INP(i% + &HE) AND &H80 OR Expect% = 200)
IF (Expect% <> 100 AND INP(i% + &HA) = &HAA) THEN Success% = -1: EXIT FOR
NEXT
IF Success% THEN
DSPBase% = i%
DSPReset% = i% + &H6
DSPRead% = i% + &HA
DSPWrite% = i% + &HC
DSPWriteBuffer% = DSPWrite%
DSPReadBuffer% = i% + &HE
MixAddress% = i% + &H4
MixData% = i% + &H5
'Reset Mixer Too
OUT MixAddress%, 0
OUT MixData%, 0
END IF
NewResetDSP% = Success%
END FUNCTION

SUB OutputFilter (State%, Set%)
OUT MixAddress%, &HE
a% = INP(MixData%)
IF Set% THEN
a% = a% AND &HDF
a% = a% OR State%
OUT MixData%, a%
ELSE
State% = (a% AND &H20) \ &H20
END IF
END SUB

SUB PalleteInit
FOR i% = 0 TO 255
OUT &H3C8, i%
OUT &H3C9, i% MOD 64
OUT &H3C9, (i% * 2) MOD 64
OUT &H3C9, (i% * 4) MOD 64
NEXT
END SUB

SUB PauseDMAMode (DMAMode816%)
IF DMAMode816% THEN
WriteDSP &HD5
OUT DMAMaskReg%, DMAUnMasked%
ELSE
WriteDSP &HD0
OUT DMAMaskReg%, DMAMasked%
END IF
END SUB

SUB ProcessInit (DMAMode%, DMAIncrement%, DMAInitialize%, DMATransfer%, MonoStereo%, Sampling&)
SELECT CASE DMAChannel%
CASE 0
DMAPageReg% = &H87
DMAAddressReg% = &H0
DMACountReg% = &H1
CASE 1
DMAPageReg% = &H83
DMAAddressReg% = &H2
DMACountReg% = &H3
CASE 2
DMAPageReg% = &H81
DMAAddressReg% = &H4
DMACountReg% = &H5
CASE 3
DMAPageReg% = &H82
DMAAddressReg% = &H6
DMACountReg% = &H7
CASE 4
DMAPageReg% = &H8F
DMAAddressReg% = &HC0
DMACountReg% = &HC2
CASE 5
DMAPageReg% = &H8B
DMAAddressReg% = &HC4
DMACountReg% = &HC6
CASE 6
DMAPageReg% = &H89
DMAAddressReg% = &HC8
DMACountReg% = &HCA
CASE 7
DMAPageReg% = &H8A
DMAAddressReg% = &HCC
DMACountReg% = &HCE
CASE ELSE
END SELECT
IF (DMAChannel% <= 3) THEN
DMAMaskReg% = &HA
DMAModeReg% = &HB
DMAClearReg% = &HC
DMAMasked% = &H4 + DMAChannel%
DMAUnMasked% = DMAChannel%
DMAModeData% = DMAMode% * &H40 + DMAIncrement% * &H20 + DMAInitialize% * &H10 + DMATransfer% * &H4 + DMAChannel%
ELSE
DMAMaskReg% = &HD4
DMAModeReg% = &HD6
DMAClearReg% = &HD8
DMAMasked% = DMAChannel%
DMAUnMasked% = DMAChannel% - &H4
DMAModeData% = DMAMode% * &H40 + DMAIncrement% * &H20 + DMAInitialize% * &H10 + DMATransfer% * &H4 + DMAChannel% - 4
END IF
DSPTimeConstant% = (65536 - (256000000 / ((MonoStereo% + 1) * Sampling&))) \ 256
END SUB

FUNCTION ReadDSP%
DO: LOOP UNTIL INP(DSPReadBuffer%) AND &H80
ReadDSP% = INP(DSPRead%)
END FUNCTION

SUB ResetDSP
OUT DSPReset%, 1
OUT DSPReset%, 0
DO: LOOP UNTIL (INP(DSPReadBuffer%)) AND &H80
HeyHo% = INP(DSPRead%)
END SUB

SUB ResetMix
OUT MixAddress%, 0
OUT MixData%, 0
END SUB

SUB ResumeDMAMode (DMAMode816%)
IF DMAMode816% THEN WriteDSP &HD6 ELSE WriteDSP &HD4
END SUB

SUB SpeakerState (State%, Set%)
IF Set% THEN
IF State% THEN WriteDSP &HD1 ELSE WriteDSP &HD3
ELSE
WriteDSP &HD8
State% = ReadDSP%
END IF
END SUB

SUB StereoSwitch (MonoStereo%)
OUT MixAddress%, &HE
a1% = INP(MixData%)
IF MonoStereo% THEN OUT MixData%, (a1% AND &HD) ELSE OUT MixData%, a1% OR 2
END SUB

SUB VoiceVol (Left%, Right%, Set%)
OUT MixAddress%, &H4
IF Set% THEN
a% = Left% * &H10 + Right%
OUT MixDtata%, a%
ELSE
a% = INP(MixData%)
Left% = a% \ &H10
Right% = a% AND &HF
END IF
END SUB

SUB VolumeConv (Buffer%, Length&, Volume!)
IF (Volume! <> 1) THEN
Vol% = Volume! * 256
IF (Buffer% = 1) THEN
DEF SEG = VARSEG(WaveBuffer1(0))
ELSE
DEF SEG = VARSEG(WaveBuffer2(0))
END IF
FOR i& = 0 TO Length& - 1
a& = ((CLNG(PEEK(i&) - 128) * Vol%) \ 256)
IF (a& > 127) THEN a& = 127
IF (a& < -128) THEN a& = -128
a& = a& + 128
POKE i&, a&
NEXT
DEF SEG
END IF

END SUB

SUB WaveInfo
PRINT "Riff ID = "; WaveFile(0).RiffID
PRINT "Riff Size = "; WaveFile(0).RiffSize
PRINT "Wave ID = "; WaveFile(0).WaveID
PRINT "Format ID = "; WaveFile(0).FmtID
PRINT "Format Size = "; WaveFile(0).FmtSize
PRINT "Audio Format = "; WaveFile(0).AudioFmt
PRINT "Number of Channels = "; WaveFile(0).NumChannels
PRINT "Sampling Rate = "; WaveFile(0).SampleRate; "Hz"
PRINT "Bytes per second = "; WaveFile(0).ByteRate
PRINT "Block Align = "; WaveFile(0).BlockAlign
PRINT "(number of bytes per sample)"
PRINT "Bits per sample = "; WaveFile(0).BitsPerSample
PRINT "Data ID = "; WaveFile(0).DataID
PRINT "Data Size = "; WaveFile(0).DataSize
END SUB

SUB WriteDSP (what%)
DO: LOOP WHILE INP(DSPWriteBuffer%) AND &H80
OUT DSPWrite%, what%
END SUB

