'===========================================================================
' Subject: DISK PLAY                          Date: 10-01-98 (09:58)       
'  Author: David Karlov                       Code: QB, PDS                
'  Origin: davidk@softway.com.au            Packet: DISK.ABC
'===========================================================================
'
' Here is something truly bizarre: play music on your disk drive!!!
' That's right, make weird sound effects with a floppy disk while Num, Caps,
' & Scroll dance to the music...
'
' This program will only work if you have a fairly noisy floppy disk drive...
' Some of the newer FDDs are silent and when this program is run, it seems to
' do nothing....
' Also, you need to have a disk in the drive while running.
' For QB users, start QB with the command line option /L QB to load the
' library necessary for interrupt calls.
'
' NOTE -- Default setup is for a 1.44 MB disk in drive a:, if this does not
'         match your configuration then change the constants below.....
'
' David Karlov    dkarlov@acs.its.uts.edu.au
'                 dkarlov@rocketmail.com
'
' If you haven't seen Starfire yet, then check it out now!!!!
' ===  >>>>>    ftp.cdrom.com/pub/games/dos/arcade/starfire.zip    <<<<<  ===
'
DEFINT A-Z

TYPE RegTypeX
	  AX    AS INTEGER
	  bx    AS INTEGER
	  cx    AS INTEGER
	  DX    AS INTEGER
	  bp    AS INTEGER
	  si    AS INTEGER
	  di    AS INTEGER
	  flags AS INTEGER
	  ds    AS INTEGER
	  es    AS INTEGER
END TYPE

DECLARE SUB INTERRUPTX (intnum AS INTEGER, inreg AS RegTypeX, outreg AS RegTypeX)
DECLARE SUB ReadSector (DriveNum AS INTEGER, TrackNum AS INTEGER, SectorNum AS INTEGER)
DECLARE SUB ClearReg ()
DECLARE SUB IncTrack (inc AS INTEGER)
DECLARE SUB LockSet (ln AS INTEGER, c AS INTEGER)
DECLARE SUB Init ()


CONST Dr = 0
	' Use 0 for drive a:, 1 for drive b:

CONST DiskType = 3
	' 0  =  5.25 inch 360 KB
	' 1  =  5.25 inch 1.2 MB
	' 2  =  3.5  inch 720 KB
	' 3  =  3.5  inch 1.44 MB


DIM SHARED Reg AS RegTypeX
DIM SHARED Buffer AS STRING * 512

DIM SHARED Tr AS INTEGER
DIM SHARED TrDir AS INTEGER

DIM SHARED Pattern(15000) AS INTEGER
DIM SHARED NumPat AS INTEGER

DIM SHARED Speed AS INTEGER   ' 0 = normal, 1 = fast
DIM SHARED MaxSect AS INTEGER
DIM SHARED MaxTracks AS INTEGER

Init

c = 0
DO
	c = (c MOD NumPat) + 1
	IF Speed THEN Se = Se + MaxSect - 1
	Se = (Se MOD MaxSect) + 1
	IF Pattern(c) < 0 THEN
		DO    ' change speed on the fly....
			IF Speed = 0 THEN Se = Se + MaxSect - 1
			Se = (Se MOD MaxSect) + 1
			IF Pattern(c) = -1 THEN
				Speed = 0
			ELSEIF Pattern(c) = -2 THEN
				Speed = 1
			END IF
			c = (c MOD NumPat) + 1
		LOOP UNTIL Pattern(c) >= 0
	END IF

	tc = tc + 1 - (Pattern(c) >= 8)
	'ie. if Pattern(c) >= 8 then tc = tc + 2 else tc = tc + 1

	LockSet 3, 3
	IF tc MOD 2 = 0 THEN
		LockSet 1, 3
		IF tc MOD 4 = 0 THEN LockSet 2, 3
	END IF
  
	IncTrack Pattern(c) * 4
	ReadSector Dr, Tr, Se

LOOP UNTIL INKEY$ <> ""

' clear all locks . . .
LockSet 1, 0: LockSet 2, 0: LockSet 3, 0

END


' PATTERN DATA.....
' Each number represents one read operation on the disk... the bigger
' the number, the further the R/W heads will move and the louder and
' longer the sound.  0 is a rest, -1 changes speed to slow and -2 changes
' speed to fast.  Numbers > 7 will take twice as long as others, since
' the disk will have to rotate twice for this (on my disk drive anyway....)
' Don't use numbers > 10.
' Don't use 6 or 7, they take a varying no. of disk revolutions for
' different speeds. Notes 1 -> 5 use 1 disk revolution with varying
' loudness, 8 -> 10 use 2 disk revolutions.
DATA -2,1,2,2,3,3,4,4,5
DATA 3,0,0,0,0,0,0,1,3,0,0,0,0,0,0,1,3,0,0,0,0,0,0,1,3,0,0,0,0,0,0,1
DATA 2,0,0,0,2,0,0,0,2,0,0,0,2,0,0,1,2,0,0,0,2,0,0,0,2,0,0,0,0,2,0,2
DATA 1,0,5,0,1,0,5,0,1,0,5,0,1,0,5,0,1,0,5,0,1,0,5,0,1,0,5,0,1,0,5,1
DATA 2,1,5,1,2,1,5,1,2,1,5,1,2,1,5,2,2,1,5,1,2,1,5,1,2,0,0,0,0,2,3,4
DATA 5,1,1,1,5,1,1,1,5,1,1,1,5,1,1,5,1,5,5,1,5,1,1,1,5,1,5,1,5,1,5,1
DATA 9,  0,9,  0,9,  0,9,  0,9,  9,  9,  0,9,  0,9,  0,9,  0,9,  9
DATA 5,1,1,5,1,1,5,1,1,5,1,1,5,1,5,1,5,1,1,5,1,1,5,1,1,5,1,1,5,1,5,1
DATA 5,1,5,1,5,1,5,1,9,  0,0,0,1,0,1,5,1,5,1,5,1,5,1,9,  0,1,1,4,4,4
DATA 5,0,1,0,5,0,1,0,5,0,1,0,5,0,1,0,5,1,1,0,5,0,1,1,5,1,0,1,5,1,1,1
DATA 5,2,1,5,2,1,3,3,5,2,1,5,1,5,5,5,5,0,5,0,5,0,5,5,0,5,0,2,5,1,4,4
DATA 2,0,5,1,2,0,5,0,2,0,5,0,2,0,5,0,2,2,5,0,2,1,5,0,2,2,5,2,2,5,5,5
DATA 9,  1,1,5,5,1,5,5,1,5,1,5,2,4,1,5,5,5,0,5,0,5,5,0,5,5,4,5,0,5,5

' use 999 to mark the end of the data.
DATA 999

SUB ClearReg

Reg.AX = 0: Reg.bx = 0: Reg.cx = 0: Reg.DX = 0
Reg.bp = 0: Reg.si = 0: Reg.di = 0: Reg.flags = 0
Reg.ds = 0: Reg.es = 0

END SUB

SUB IncTrack (inc AS INTEGER)
' move the R/W heads by (inc) tracks.

IF TrDir = 1 THEN
	IF Tr + inc <= MaxTracks THEN
		Tr = Tr + inc
		IF Tr = MaxTracks THEN TrDir = -1
	ELSE
		TrDir = -1
		Tr = Tr - inc
		IF Tr < 0 THEN Tr = 0
	END IF
ELSE
	IF Tr - inc >= 0 THEN
		Tr = Tr - inc
		IF Tr = 0 THEN TrDir = 1
	ELSE
		TrDir = 1
		Tr = Tr + inc
		IF Tr > MaxTracks THEN Tr = MaxTracks
	END IF
END IF


END SUB

SUB Init
' some boring stuff...

SELECT CASE DiskType
CASE 0
	' 5.25 inch 360 KB
	MaxSect = 9
	MaxTracks = 39
CASE 1
	' 5.25 inch 1.2 MB
	MaxSect = 15
	MaxTracks = 79
CASE 2
	' 3.5 inch 720 KB
	MaxSect = 9
	MaxTracks = 79
CASE 3
	' 3.5 inch 1.44 MB
	MaxSect = 18
	MaxTracks = 79
END SELECT


c = 0
DO
	c = c + 1
	READ Pattern(c)
LOOP UNTIL Pattern(c) = 999
NumPat = c - 1
								 
TrDir = 1: Tr = MaxTracks \ 2

RANDOMIZE TIMER

ReadSector 0, Tr, 0

END SUB

SUB LockSet (ln, c)
' turns Caps/Num/Scroll Lock on, off, or toggles

	DEF SEG = 0
	IF ln = 1 THEN mask% = &H40   'Caps Lock
	IF ln = 2 THEN mask% = &H20   'Num Lock
	IF ln = 3 THEN mask% = &H10   'Scroll Lock
	cur% = PEEK(&H417)
	IF c = 1 THEN POKE &H417, cur% OR mask%                  'on
	IF c = 2 OR c = 0 THEN POKE &H417, cur% AND (NOT mask%)  'off
	IF c = 3 THEN POKE &H417, cur% XOR mask%                 'toggle
	DEF SEG

END SUB

SUB ReadSector (DriveNum AS INTEGER, TrackNum AS INTEGER, SectorNum AS INTEGER)
' Read a sector from drive DriveNum.

ClearReg

Reg.AX = CVI(CHR$(1) + CHR$(2))
Reg.cx = CVI(CHR$(SectorNum) + CHR$(TrackNum))
Reg.DX = CVI(CHR$(DriveNum) + CHR$(0))

Reg.es = VARSEG(Buffer)
Reg.bx = VARPTR(Buffer)

c = 0
DO
	DO
		CALL INTERRUPTX(&H13, Reg, Reg)
		c = c + 1
		IF ((Reg.flags AND 2048) > 0 AND (Reg.flags AND 128) = 0) THEN
			PRINT "Disk not found in drive a:"
			LockSet 1, 0: LockSet 2, 0: LockSet 3, 0
			END
		END IF
	LOOP UNTIL (Reg.flags AND 1) = 0 OR c MOD 4 = 0
	IF c MOD 4 = 0 THEN SLEEP 1
LOOP UNTIL c MOD 4 <> 0


END SUB
