{ Hello Gayle Davis... I would just like to say how pleased i am with the continuing success of SWAGS.. Below I have included some source of my own. a cd-player, that I believe is quite nifty, anyways I like it. I would be very pleased and honored if it was included in SWAGS... Yours truly, Lars Koudal Denmark, 25th of february 1997 A bit of history: ------------------ I am one of those people who use my cd-rom drive for playing music while I am working, eventhough at home I have my left shoulder about 5 inches from the volume knop on my somewhat larger stereo.. This is a habbit from my good old days where I worked in far less equipped environments. Nowadays I have what I need in win95... Back then though, I was never really satisfied with the cd-players out there. So I wrote my own... I used a lot of routines grabbed from SWAGS.. (Thanks...) I always intended this to be only for personal use, but as the program grew larger I felt like I perhaps could earn some bucks selling the damn thing... THAT was in my young and restless days... I recently picked up a newer version of swags (haven't done that in more than a year), and was very thrilled to see how alive this wonderful source of information is.. Therefore I decided to post the small version of my program... If people want it, I will ofcourse send the full-scale version as well.. That hasn't been fully written yet, but the damn thing works... This version is called mini... Probaply due to it's small size (compared to the larger one), but since it is some years ago, I am not quite sure... :-) This program uses, as mentioned before, a lot of routines and units from other people. All grabbed here from swags... Remember! Credit where credit is due! When you run this damn thing, it pops up on your dos-screen with a single line... It shows what song is playing, and how long it has been playing... When you press Pgup, it goes one song up. Guess what happens when you press PgDn! :-) Press '.' and up comes a list of songs you can pick. Just use up- and down-keys to scroll and ENTER to make your selection... The whole thing ends when you press ESC... Try to press F1 from inside the player... I had forgotten this little nifty detail until I tried it out a few minutes ago... BTW: If you have a SoundBlaster in your computer, and the routines I use for detecting it _can_ find it, you can use '+' and '-' to adjust the volume... Pretty nifty... I used it a lot from inside Turbo Pascal.. I made it a tool, and just pressed Shift-F5, and there it was... pretty handy... and a lot faster... Ever used QCD (comes with SndB)?? Goddamn slow! (If you can't figure out how to make a new tool in TP, don't bother... put the keyboard down!) Well, so much about the past, a bit about the future..: -------------------------------------------------------- As I have written, this code is from my novice years. If you for some reason want to contact me, don't do so if you just want to complain about the lousy code, the many unused variables and the many work-arounds I did for making the whole thing work. I provide this code to help novices people out, as I was helped myself some years ago... If you DO decide to contact me, you can e-mail me... (Sorry, left FIDO years ago): lkoudal@usa.net Have fun! Yours truly, Lars Koudal. {Installation notes... Cut and paste the files to their original names, and the compile MINI.PAS... THATS IT! Play around as much as you like...} {CUT ... Save this as MINI.PAS } {ÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜ} PROGRAM mini; {ßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßß} {This program is determined that you start it with a color-screen If you don't have that, or you do not know how to change it to a monochrome screen, don't bother... put the keyboard down... Lars Koudal.... hint: look about 15 lines down, and read the comment... } USES { effects, } CD_Unit, CD_Vars, DOS, CRT, TPTimer, TCTimer, TPBuffer, ScanCode; TYPE TotPlayRec = RECORD Frames, Seconds, Minutes, Nada : Byte; END; CONST TextVidSeg : Word = $b800; vga_segment = $0A000; fade_Delay = 20; vSeg : Word = $B800; {change for mono} VAR CurrIndex : Word; ScreenLoc : Pointer; ScrollSize : Word; vol_time : longint; toslet : boolean; sbfound, portok : Boolean; ScrBuf, Pdwns : Word; origmode : word; lcv : Integer; temp : Char; a1, a2, a3 : Byte; b1, b2, b3 : Byte; crc : LongInt; cdidstr : String; number : Byte; SaveExit : Pointer; TrackInfo : ARRAY [1..99] OF PAudioTrackInfo; I : Integer; CH : Char; SP, EP : LongInt; LeadOut, StartP, TotalPlayTime: LongInt; TotPlay : TotPlayRec; place : LongInt; secs, pps, s : LongInt; Track : Byte; StartTrack, EndTrack, NumTracks : Integer; Player : ARRAY [1..100] OF Byte; PlayTime : TotPlayRec; result : Word; resultchar : Char; Hi, Hi2 : Byte; crstyp : Word; arbejder : Byte; lvolume, rvolume : Byte; {Volume-control} Scroll_Lock, Caps_Lock, Num_Lock, Ins, Alt, Ctrl, Left_Shift, Right_Shift : Boolean; Bios_Keys : Byte ABSOLUTE $40:$17; Procedure WaitForRetrace; Assembler; Asm Mov DX, 3DAh @Rep1: In AL, DX Test AL, 08h JZ @Rep1 @Rep2: In AL, DX Test AL, 08h JNZ @Rep2 End; Function LeadingZero (w : Word) : String; Var s : String; Begin Str (w: 0, s); If Length (s) = 1 Then s := '0' + s; LeadingZero := s; End; Function ITOS ( nNum: LongInt; nSpaces: Integer ): String; Var s: ^String; Begin Asm mov sp, BP push ss push Word Ptr @RESULT End; If nSpaces > 0 Then Str ( nNum: nSpaces, s^ ) Else Str ( nNum: 0, s^ ); End; Function returnspace (s: String; wantedspace: Byte): String; Var i : Byte; temp : String; Begin temp := ''; For i := Length (s) To wantedspace Do Begin temp := temp + ' '; End; returnspace := temp; End; {home-made-calculations of which track is currently being played} Procedure calctrack; Var Min, Sec: Byte; i: Byte; svar: Boolean; {**************} Procedure addtime (m, s: Byte); Begin Min := Min + m; Sec := Sec + s; If Sec = 60 Then Begin Min := Min + 1; Sec := 0; End; If Sec > 60 Then Begin Min := Min + 1; Sec := Sec - 60; End; End; {**************} {**************} Procedure bigger (m1, s1, m2, s2: Byte; svar: Boolean); {calculates whether m1:s1 is bigger than m2:s2:} Begin If (m1 * 60 + s1) > (m2 * 60 + s2) Then svar := True Else svar := False; End; {**************} Begin track := 0; Min := 0; Sec := 0; secs := 0; place := Head_Location (1); For i := starttrack To endtrack Do Begin If trackinfo [i]^. startpoint < place Then Begin track := i; End; If track = 0 Then track := 1; End; End; Procedure NoTracks; Begin WriteLn; WriteLn ('No tracks on disk'); WriteLn; ExitProc := SaveExit; End; Procedure Setup; Begin TotalPlayTime := 0; LeadOut := AudioDiskInfo. LeadOutTrack; StartTrack := AudioDiskInfo. LowestTrack; EndTrack := AudioDiskInfo. HighestTrack; NumTracks := EndTrack - StartTrack + 1; For I := StartTrack To EndTrack Do Begin Track := I; Audio_Track_Info (StartP, Track); New (TrackInfo [I] ); FillChar (TrackInfo [I]^, SizeOf (TrackInfo [I]^), #0); TrackInfo [I]^. StartPoint := StartP; TrackInfo [I]^. TrackControl := Track; End; For I := StartTrack To EndTrack - 1 Do TrackInfo [I]^. EndPoint := TrackInfo [I + 1]^. StartPoint - 1; TrackInfo [EndTrack]^. EndPoint := AudioDiskInfo. LeadOutTrack - 1; For I := StartTrack To EndTrack Do Move (TrackInfo [I]^. EndPoint, TrackInfo [I]^. Frames, 4); TrackInfo [StartTrack]^. PlayMin := TrackInfo [StartTrack]^. Minutes; TrackInfo [StartTrack]^. PlaySec := TrackInfo [StartTrack]^. Seconds - 2; For I := StartTrack + 1 To EndTrack Do Begin EP := (TrackInfo [I]^. Minutes * 60) + TrackInfo [I]^. Seconds; SP := (TrackInfo [I - 1]^. Minutes * 60) + TrackInfo [I - 1]^. Seconds; EP := EP - SP; TrackInfo [I]^. PlayMin := EP Div 60; TrackInfo [I]^. PlaySec := EP Mod 60; End; TotalPlayTime := AudioDiskInfo. LeadOutTrack - TrackInfo [StartTrack]^. StartPoint; Move (TotalPlayTime, TotPlay, 4); End; Function KeyEnh: Boolean; Var Enh: Byte Absolute $0040:$0096; Begin KeyEnh := False; If (Enh And $10) = $10 Then KeyEnh := True; End; Function InKey (Var SCAN, ASCII: Byte): Boolean; Var i : Integer; Shift, Ctrl, Alt : Boolean; Temp, Flag1 : Byte; HEXCH, HEXRD, HEXFL : Byte; reg : Registers; Begin If KeyEnh Then Begin HEXCH := $11; HEXRD := $10; HEXFL := $12; End Else Begin HEXCH := $01; HEXRD := $00; HEXFL := $02; End; reg. AH := HEXCH; Intr ($16, reg); i := reg. Flags And fZero; reg. AH := HEXFL; Intr ($16, reg); Flag1 := Reg. AL; Temp := Flag1 And $03; If Temp = 0 Then SHIFT := False Else SHIFT := True; Temp := Flag1 And $04; If Temp = 0 Then CTRL := False Else CTRL := True; Temp := Flag1 And $08; If Temp = 0 Then ALT := False Else ALT := True; If i = 0 Then Begin reg. AH := HEXRD; Intr ($16, reg); scan := reg. AH; ascii := reg. AL; InKey := True; End Else InKey := False; End; {ÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜ} FUNCTION UpStr (CONST s: String): String; ASSEMBLER; ASM push DS lds SI, s les DI, @result lodsb { load and store length of string } stosb XOR CH, CH mov CL, AL jcxz @empty { FIX for null length string } @upperLoop: lodsb cmp AL, 'a' jb @cont cmp AL, 'z' ja @cont sub AL, ' ' @cont: stosb loop @UpperLoop @empty: pop DS END; procedure vretrace; assembler; { vertical retrace } asm mov dx,3dah @vert1: in al,dx test al,8 jz @vert1 @vert2: in al,dx test al,8 jnz @vert2 end; Procedure Setupsc(Col, Row, ScrollSize : Word; Var ScreenLoc : Pointer); Var Seg1, Ofs1 : Word; Begin {I guess we're assuming an 80 column text mode } Ofs1 := (Row-1)*160 + ((Col-1)*2); If (Mem[$40:$49] = 7) then Seg1 := $B000 else Seg1 := $B800; ScreenLoc := Ptr(Seg1,Ofs1); End; {ÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜ} FUNCTION Get_svar: Byte ; VAR CH: Char; no_svar: Boolean; BEGIN no_svar := TRUE; REPEAT CH := UpCase (ReadKey); IF CH = NullKey THEN BEGIN CASE Ord (ReadKey) OF dnarrow: BEGIN get_svar := dnarrow; END; uparrow: BEGIN get_svar := uparrow; END; lfarrow: BEGIN get_svar := lfarrow; END; rtarrow: BEGIN get_Svar := rtarrow; END; END; END ELSE CASE CH OF EnterKey : BEGIN get_svar := 100; END; EscapeKey : BEGIN get_svar := 27; END; END; UNTIL no_svar <> FALSE; END; Procedure Update;Assembler; ASM CLD LES DI, ScreenLoc MOV CX, ScrollSize MOV SI, CurrIndex OR SI, SI JZ @WriteString DEC CX @ShiftLeft: MOV AL, ES:[DI+2] STOSB INC DI LOOP @ShiftLeft MOV AL, CS:[SI] OR AL, AL JNZ @NotEndOfStr MOV SI, Offset @Message MOV AL, CS:[SI] @NotEndOfStr: STOSB INC SI JMP @SaveIndex @WriteString: MOV SI, Offset @Message @NextChar: MOV AL, CS:[SI] OR AL, AL JZ @WriteString STOSB INC DI INC SI LOOP @NextChar @SaveIndex: MOV CurrIndex, SI JMP @Exit @Message: DB ' ' DB ' ' DB '(\/)ini HELP! ' DB ' Function keys available:' DB ' PgUP : One track up ... PgDN : One track down ' DB ' ... "." : Pick a track using arrow keys ... ' DB 'RightArrow : FastForward ... LeftArrow : Rewind ... ' DB 'If you have a Sound Blaster you can use the "+" & "-" keys to control ' DB 'the volume..... ' DB 0 { terminate it with NULL } @Exit: End; procedure help; Var Fedup : Boolean; time:byte; c:byte; emptystr:string; i:integer; Begin fillchar(emptystr,80,' '); emptystr[0]:=#80; ScrollSize := 80; Setupsc(01,wherey,SCrollSize,ScreenLoc); CurrIndex := 0; time:=0; fedup:=false; textcolor(lightgray); gotoxy(1,wherey); write(emptystr); while keypressed do readkey; Repeat waitforretrace; Update; if keypressed then begin c:=get_svar; if c=uparrow then inc(time); if c=dnarrow then dec(time); Fedup := (c = 27); end; Until (Fedup); End; {ÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜ} FUNCTION IntToStr (I: LongInt): String; {Converts any integer type to a string} VAR S: String [11]; BEGIN Str (I, S); IntToStr := S; END; {ÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜ} PROCEDURE ShowVolume; var i:byte; BEGIN gotoxy(33,wherey); TEXTCOLOR (DarkGray); FOR i := 1 TO 32 DO BEGIN WRITE ('ž'); END; TEXTCOLOR (Yellow); GOTOXY (33, wherey); FOR i := 1 TO lvolume DIV 8 DO BEGIN WRITE ('Ž'); END; vol_time:=readtimer; toslet:=true; END; {ÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜ} PROCEDURE Cursoff; { Turns the cursor off. Stores its format for later redisplaying} BEGIN ASM Mov AH, 03H Mov BH, 00H Int 10H Mov Crstyp, CX Mov AH, 01H Mov CX, 65535 Int 10H END; END; {ÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜ} PROCEDURE Curson; {Turns the cursor back on, using the cursor display previously stored} BEGIN ASM Mov AH, 01H Mov CX, Crstyp Int 10H END; END; {ÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜ} PROCEDURE SetColor (Color, Red, Green, Blue : Byte); {Sets the RGB-values for a given color} BEGIN port [$3C8] := Color; port [$3C9] := Red; port [$3C9] := Green; port [$3C9] := Blue; END; {ÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜ} PROCEDURE GetColor (Nr: Byte; VAR R, G, B: Byte); {Retrieves the RGB-values for a given color} BEGIN Port [$3C7] := Nr; R := Port [$3C9]; G := Port [$3C9]; B := Port [$3C9]; END; {ÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜ} PROCEDURE wait_4_refresh; ASSEMBLER; {Waits for the monitors vertical retrace} LABEL wait, retr; ASM mov DX, 3DAh wait: IN AL, DX Test AL, 08h jz wait retr: IN AL, DX Test AL, 08h jnz retr END; {ÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜ} FUNCTION ISCOLOR : Boolean; {Returns FALSE for MONO or TRUE for COLOR} VAR regs : Registers; video_mode : Integer; equ_lo : Byte; BEGIN Intr ($11, regs); video_mode := regs. AL AND $30; video_mode := video_mode SHR 4; CASE video_mode OF 1 : ISCOLOR := FALSE; { Monochrome } 2 : ISCOLOR := TRUE{ Color } END END; {ÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜ} PROCEDURE SAVESCR ( VAR screen ); {Saves the screen in an array of bytes} VAR vidc : Byte ABSOLUTE $B800: 0000; vidm : Byte ABSOLUTE $B000: 0000; BEGIN IF NOT ISCOLOR THEN { if MONO } Move (vidm, screen, 6000) ELSE { else COLOR } Move (vidc, screen, 6000) END; {ÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜ} PROCEDURE RESTORESCR ( VAR screen ); {Restores the screen previous stored in an array of bytes} VAR vidc : Byte ABSOLUTE $B800: 0000; vidm : Byte ABSOLUTE $B000: 0000; BEGIN IF NOT ISCOLOR THEN { if MONO } Move (screen, vidm, 6000) ELSE { else COLOR } Move (screen, vidc, 6000) END; {ÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜ} PROCEDURE working; {Displays an 'working'-status on the screen} VAR X, Y: Byte; c: Byte; BEGIN IF playing THEN BEGIN X := WhereX; Y := WhereY; c := TextAttr; TextBackground (Blue); TextColor (Black); GotoXY (70, 3); IF arbejder = 1 THEN Write (''); IF arbejder = 2 THEN Write (''); IF arbejder = 3 THEN Write (''); IF arbejder = 4 THEN Write (''); IF arbejder < 4 THEN Inc (arbejder) ELSE arbejder := 1; GotoXY (X, Y); TextAttr := c; END; END; {ÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜ} PROCEDURE center (s: String; Y: Byte); {Centers a given string on a given line on the screen} BEGIN GotoXY (40 - (Length (s) DIV 2), Y); Write (s); END; {ÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜ} Function hex(a : Word; b : Byte) : String; Const digit : Array[$0..$F] Of Char = '0123456789ABCDEF'; Var i : Byte; xstring : String; Begin xstring:=''; For i:=1 To b Do Begin Insert(digit[a And $000F], xstring, 1); a:=a ShR 4 End; hex:=xstring End; {hex} {ÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜ} Procedure SoundPort; Var xbyte1, xbyte2, xbyte3, xbyte4: Byte; xword, xword1, xword2, temp, sbport: Word; Begin sbfound:=False; xbyte1:=1; While (xbyte1 < 7) And (Not sbfound) Do Begin sbport:=$200 + ($10 * xbyte1); xword1:=0; portok:=False; While (xword1 < $201) And (Not portok) Do Begin If (Port[sbport + $0C] And $80) = 0 Then portok:=True; Inc(xword1) End; If portok Then Begin xbyte3:=Port[sbport + $0C]; Port[sbport + $0C]:=$D3; For xword2:=1 To $1000 Do {nothing}; xbyte4:=Port[sbport + 6]; Port[sbport + 6]:=1; xbyte2:=Port[sbport + 6]; xbyte2:=Port[sbport + 6]; xbyte2:=Port[sbport + 6]; xbyte2:=Port[sbport + 6]; Port[sbport + 6]:=0; xbyte2:=0; Repeat xword1:=0; portok:=False; While (xword1 < $201) And (Not portok) Do Begin If (Port[sbport + $0E] And $80) = $80 Then portok:=True; Inc(xword1) End; If portok Then If Port[sbport + $0A] = $AA Then sbfound:=True; Inc(xbyte2); Until (xbyte2 = $10) Or (portok); If Not portok Then Begin Port[sbport + $0C]:=xbyte3; Port[sbport + 6]:=xbyte4; End; End; If sbfound Then Begin End Else Inc(xbyte1); End; End; {ÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜ} FUNCTION pickatrack: Byte; {Displays the user with a list of tracks to pick} VAR Top, Bottom : Byte; change : Boolean; {scroller vi op/ned?} slut : Boolean; i : Byte; c : Byte; curr : Byte; index : Byte; s: String; topl: Byte; BEGIN topl := wherey-1; {topline} pickatrack := 0; s := ' '; change := FALSE; curr := 1; slut := FALSE; Top := 1; index := endtrack; TextColor (lightgray); gotoxy(32,topl+1); write('Select '); gotoxy(42,topl+1); write( ' ³ '); curr:=track; REPEAT BEGIN TextBackground (Black); TextColor (lightgray); FOR i := Top TO Bottom DO BEGIN GotoXY (43, topl + 1); Write (' '); IF i = track THEN BEGIN TextColor (lightgray+ Blink); Write (leadingzero (i) ); TextColor (lightgray); Write ('³'); TextColor (lightgray+ Blink); Write (leadingzero (trackinfo [i]^. playmin) ); TextColor (lightgray); Write (':'); TextColor (lightgray+ Blink); Write (leadingzero (trackinfo [i]^. playsec) ); END ELSE BEGIN Write (leadingzero (i) ); Write ('³'); Write (leadingzero (trackinfo [i]^. playmin) ); Write (':'); Write (leadingzero (trackinfo [i]^. playsec) ); END; END; IF curr = track THEN BEGIN TextColor (lightgray); GotoXY (44, topl + 1); Write (leadingzero (curr) ); TextColor (lightgray); Write ('³'); TextColor (lightgray); Write (leadingzero (trackinfo [curr]^. playmin) ); TextColor (lightgray); Write (':'); TextColor (lightgray); Write (leadingzero (trackinfo [curr]^. playsec) ); END ELSE BEGIN TextColor (lightgray); GotoXY (44, topl + 1); Write (leadingzero (curr) ); Write ('³'); Write (leadingzero (trackinfo [curr]^. playmin) ); Write (':'); Write (leadingzero (trackinfo [curr]^. playsec) ); END; textbackground(black); textcolor(lightgray); gotoxy(39,topl+1); if curr=1 then write('( )'); if curr=index then write('( )'); if ((curr1)) then write('()'); repeat calctrack; q_channel_info; textcolor(yellow); gotoxy(18,wherey); write(leadingzero(track)); gotoxy(21,wherey); textcolor(white); write(leadingzero(endtrack)); textcolor(yellow); gotoxy(24,wherey); write(leadingzero(qchannelinfo.minutes)); gotoxy(27,wherey); write(leadingzero(qchannelinfo.seconds)); until keypressed; c := get_Svar; IF (c = uparrow) THEN BEGIN IF (curr = Top) AND (Top > 1) THEN BEGIN Dec (Top); Dec (curr); change := TRUE; END; IF (curr > Top) THEN Dec (curr); END; IF (c = dnarrow) THEN BEGIN IF (curr < index)THEN begin Inc (curr); inc(top); end; END; IF c = 100 THEN BEGIN pickatrack := curr; slut := TRUE; END; IF c = 27 THEN BEGIN TextBackground (Black); gotoxy(32,topl+1);write(' '); Exit; END; END; {while} UNTIL slut; TextBackground (Black); gotoxy(32,topl+1);write(' '); END; {ÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜ} PROCEDURE colwrite (col, startline: Byte; s: String); {Writes a given line downwards from the given column and the given startline} VAR i, j: Byte; BEGIN j := 1; FOR i := startline TO startline+ Length (s) - 1 DO BEGIN GotoXY (col, i); Write (s [j] ); Inc (j); END; END; {ÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜ} PROCEDURE stuffthebuff; {Empties the buffer} VAR chartoskip: Char; BEGIN WHILE KeyPressed DO chartoskip := ReadKey; END; {ÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜ} FUNCTION Get_Scan_Code : Word; VAR HTregs : Registers; BEGIN HTregs. AH := $01; Intr ($16, HTregs); Get_Scan_Code := HTregs. AX; END; {ÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜ} PROCEDURE fuckthebuff; {Flushes the keyboard-buffer} BEGIN ASM Mov AX, $0C00; Int 21h; END; END; {ÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜ} {ÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜ} {ÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜ} {ÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜ} {ÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜ} {ÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜ} {ÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜ} {ÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜ} {ÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜ} VAR currtrack : Byte; ieren : LongInt; slut : Boolean; newtrack : Byte; xkor, ykor : Byte; timepassed:longint; BEGIN origmode := LastMode; cursoff; soundport; port [$224] := 48; lvolume := port [$225]; port [$224] := 49; rvolume := port [$225]; port [$224] := 65; xkor := WhereX; ykor := WhereY; TextColor (LightGray); TextBackground (Black); gotoxy(1,wherey-1); textcolor(white); write('(\/)ini'); textcolor(lightgray); writeln(' v.1 Checking CD-ROM ... '); gotoxy(1,wherey); Audio_Disk_Info; Setup; IF AudioDiskInfo. HighestTrack < 1 THEN BEGIN delay(200); Audio_Disk_Info; Setup; WriteLn ('Not an audio-CD!'); curson; Exit; END; gotoxy(1,wherey-1); gotoxy(01,wherey); write('(\/)ini v.1 xx/xx xx:XX L/th 1996'); gotoxy(1,wherey-1); gotoxy(18,wherey); slut := FALSE; textcolor(white); audio_status_info; q_channel_info; audio_status_info; audio_disk_info; Play_Audio (trackinfo [starttrack]^. startpoint, trackinfo [endtrack]^. endpoint); REPEAT REPEAT if toslet then begin if elapsedtime(vol_time,readtimer)>700 then begin gotoxy(33,wherey); write(' '); toslet:=false; end; end; fuckthebuff; calctrack; q_channel_info; gotoxy(18,wherey); write(leadingzero(track)); gotoxy(21,wherey); textcolor(white); write(leadingzero(endtrack)); textcolor(yellow); gotoxy(24,wherey); write(leadingzero(qchannelinfo.minutes)); gotoxy(27,wherey); write(leadingzero(qchannelinfo.seconds)); UNTIL InKey (Hi, Hi2); {ESC (EXIT AUDIO)} IF ( (Hi = 1) AND (Hi2 = 27) ) THEN slut := TRUE; {Page Up (UP ONE TRACK)} IF ( (Hi = 73) AND ( (Hi2 = 0) OR (Hi2 = 224) ) AND (playing) AND (track < endtrack) ) THEN BEGIN pause_audio; play_audio (trackinfo [track + 1]^. startpoint, trackinfo [endtrack]^. endpoint); END; {Page Down (DOWN ONE TRACK)} IF ( (Hi = 81) AND ( (Hi2 = 0) OR (Hi2 = 224) ) AND (playing) AND (track > starttrack) ) THEN BEGIN IF ( (place < (trackinfo [track]^. startpoint + 3000) ) ) THEN BEGIN pause_audio; play_audio (trackinfo [track - 1]^. startpoint, trackinfo [endtrack]^. endpoint); END; IF ( (place > (trackinfo [track]^. startpoint + 3000) ) ) THEN BEGIN pause_audio; play_audio (trackinfo [track]^. startpoint, trackinfo [endtrack]^. endpoint); END; END; {Right Arrow (SKIP 3-4 SECS)} IF ( (Hi = 77) AND ( (Hi2 = 0) OR (Hi2 = 224) ) AND (playing) AND ( (place+ (3000) ) < trackinfo [endtrack]^. endpoint) ) THEN BEGIN pause_audio; play_audio (place+1000, trackinfo [endtrack]^. endpoint); END; {Left Arrow (SKIP 3-4 SECS)} IF ( (Hi = 75) AND ( (Hi2 = 0) OR (Hi2 = 224) ) AND (playing) AND ( (place- (3000 * 4) ) > trackinfo [starttrack]^. startpoint) ) THEN BEGIN pause_audio; play_audio ((place- 1000), trackinfo [endtrack]^. endpoint); delay(20); END; {Middle key (PAUSE/RESUME)} IF ( (Hi = 76) AND (Hi2 = 0) ) THEN BEGIN IF playing THEN BEGIN io_control (stopplay); audio_status_info; END ELSE BEGIN resume_play; END; END; IF ( (Hi = 52) AND (Hi2 = 46) ) THEN BEGIN newtrack := pickatrack; IF newtrack > 0 THEN BEGIN pause_audio; play_audio (trackinfo [newtrack]^. startpoint, trackinfo [endtrack]^. endpoint); END; END; {HELP MENU!} IF ( (Hi = 59) AND (Hi2 = 0) ) THEN BEGIN fuckthebuff; help; gotoxy(01,wherey-1); write('(\/)ini v.1 xx/xx xx:XX L/th 1996'); gotoxy(1,wherey-1); END; { VOLUME-CONTROL!} {'-' (Reduce BOTH volumes)} IF ( (Hi = 74) AND (Hi2 = 45) AND NOT ( (left_shift) OR (right_shift) ) ) THEN BEGIN if sbfound then begin IF rvolume > 04 THEN BEGIN DEC (rvolume, 4); port [$224] := 49; port [$225] := rvolume; END; IF lvolume > 04 THEN BEGIN DEC (lvolume, 4); port [$224] := 48; port [$225] := lvolume; END; showvolume; end; END; {'+' (Increase BOTH volumes)} IF ( (Hi = 78) AND (Hi2 = 43) AND NOT ( (left_shift) OR (right_shift) ) ) THEN BEGIN if sbfound then begin IF rvolume < 252 THEN BEGIN INC (rvolume, 4); port [$224] := 49; port [$225] := rvolume; END; IF lvolume < 252 THEN BEGIN INC (lvolume, 4); port [$224] := 48; port [$225] := lvolume; END; showvolume; end; END; { VOLUME-CONTROL!} stuffthebuff; UNTIL slut; gotoxy(1,wherey); textcolor(lightgray); writeln('(\/)ini v.1 Mini-CD-ROM-player L/th 1996'); curson; END. {CUT OFF ...} {CUT ... Save this as CD_UNIT.PAS} UNIT CD_Unit; INTERFACE USES DOS, CD_Vars; VAR Drive : Integer; { Must set drive before all operations } SubUnit : Integer; PROCEDURE IO_Control (Command : Byte); FUNCTION File_Name (VAR Code : Integer) : String; FUNCTION Read_VTOC (VAR VTOC : VTOCArray; VAR Index : Integer) : Boolean; PROCEDURE CD_Check (VAR Code : Integer); PROCEDURE Vol_Desc (VAR Code : Integer; VAR ErrCode : Integer); PROCEDURE CD_Dev_Req (DevPointer : Pointer); PROCEDURE Get_Dir_Entry (PathName : String; VAR Format, ErrCode : Integer); PROCEDURE DeviceStatus; PROCEDURE Audio_Channel_Info; PROCEDURE Audio_Disk_Info; PROCEDURE Audio_Track_Info (VAR StartPoint : LongInt; VAR TrackControl : Byte); PROCEDURE Audio_Status_Info; PROCEDURE Q_Channel_Info; PROCEDURE Lock (LockDrive : Boolean); PROCEDURE Resetcd; PROCEDURE Eject; PROCEDURE CloseTray; PROCEDURE Resume_Play; PROCEDURE Pause_Audio; PROCEDURE Play_Audio (StartSec, EndSec : LongInt); FUNCTION Sector_Size (ReadMode : Integer) : Word; FUNCTION Volume_Size : LongInt; FUNCTION Media_Changed : Boolean; FUNCTION Head_Location (AddrMode : Byte) : LongInt; PROCEDURE Read_Drive_Bytes (VAR ReadBytes : DriveByteArray); PROCEDURE Read_Long (TransAddr : Pointer; StartSec : LongInt); PROCEDURE SeekSec (StartSec : LongInt); PROCEDURE DevClose; PROCEDURE DevOpen; PROCEDURE OutputFlush; PROCEDURE InputFlush; FUNCTION UPC_Code : String; IMPLEMENTATION CONST CarryFlag = $0001; TYPE PointerHalf = RECORD LoHalf, HiHalf : Word; END; VAR Regs : Registers; IOBlock : IOControl; DriveBytes : ARRAY [1..130] OF Byte; PROCEDURE Clear_Regs; BEGIN FillChar (Regs, SizeOf (Regs), #0); END; PROCEDURE CD_Intr; BEGIN Regs. AH := $15; Intr ($2F, Regs); END; PROCEDURE MSCDEX_Ver; BEGIN Clear_Regs; Regs. AL := $0C; Regs. BX := $0000; CD_Intr; MSCDEX_Version. Minor := 0; IF Regs. BX = 0 THEN MSCDEX_Version. Major := 1 ELSE BEGIN MSCDEX_Version. Major := Regs. BH; MSCDEX_Version. Minor := Regs. BL; END; END; PROCEDURE Initialize; BEGIN NumberOfCD := 0; Clear_Regs; Regs. AL := $00; Regs. BX := $0000; CD_Intr; IF Regs. BX <> 0 THEN BEGIN NumberOfCD := Regs. BX; FirstCD := Regs. CX; Clear_Regs; FillChar (DriverList, SizeOf (DriverList), #0); FillChar (UnitList, SizeOf (UnitList), #0); Regs. AL := $01; { Get List of Driver Header Addresses } Regs. ES := Seg (DriverList); Regs. BX := Ofs (DriverList); CD_Intr; Clear_Regs; Regs. AL := $0D; { Get List of CD-ROM Units } Regs. ES := Seg (UnitList); Regs. BX := Ofs (UnitList); CD_Intr; MSCDEX_Ver; END; END; FUNCTION File_Name (VAR Code : Integer) : String; VAR FN : String [38]; BEGIN Clear_Regs; Regs. AL := Code + 1; { Copyright Filename = 1 Abstract Filename = 2 Bibliographic Filename = 3 } Regs. CX := Drive; Regs. ES := Seg (FN); Regs. BX := Ofs (FN); CD_Intr; Code := Regs. AX; IF (Regs. Flags AND CarryFlag) = 0 THEN File_Name := FN ELSE File_Name := ''; END; FUNCTION Read_VTOC (VAR VTOC : VTOCArray; VAR Index : Integer) : Boolean; { On entry - Index = Vol Desc Number to read from 0 to ? On return Case Index of 1 : Standard Volume Descriptor $FF : Volume Descriptor Terminator 0 : All others } BEGIN Clear_Regs; Regs. AL := $05; Regs. CX := Drive; Regs. DX := Index; Regs. ES := Seg (VTOC); Regs. BX := Ofs (VTOC); CD_Intr; Index := Regs. AX; IF (Regs. Flags AND CarryFlag) = 0 THEN Read_VTOC := TRUE ELSE Read_VTOC := FALSE; END; PROCEDURE CD_Check (VAR Code : Integer); BEGIN Clear_Regs; Regs. AL := $0B; Regs. BX := $0000; Regs. CX := Drive; CD_Intr; IF Regs. BX <> $ADAD THEN Code := 2 ELSE BEGIN IF Regs. AX <> 0 THEN Code := 0 ELSE Code := 1; END; END; PROCEDURE Vol_Desc (VAR Code : Integer; VAR ErrCode : Integer); FUNCTION Get_Vol_Desc : Byte; BEGIN Clear_Regs; Regs. CX := Drive; Regs. AL := $0E; Regs. BX := $0000; CD_Intr; Code := Regs. AX; IF (Regs. Flags AND CarryFlag) <> 0 THEN ErrCode := $FF; Get_Vol_Desc := Regs. DH; END; BEGIN Clear_Regs; ErrCode := 0; IF Code <> 0 THEN BEGIN Regs. DH := Code; Regs. DL := 0; Regs. BX := $0001; Regs. AL := $0E; Regs. CX := Drive; CD_Intr; Code := Regs. AX; IF (Regs. Flags AND CarryFlag) <> 0 THEN ErrCode := $FF; END; IF ErrCode = 0 THEN Code := Get_Vol_Desc; END; PROCEDURE Get_Dir_Entry (PathName : String; VAR Format, ErrCode : Integer); BEGIN FillChar (DirBuf, SizeOf (DirBuf), #0); PathName := PathName + #0; Clear_Regs; Regs. AL := $0F; Regs. CL := Drive; Regs. CH := 1; Regs. ES := Seg (PathName); Regs. BX := Ofs (PathName); Regs. SI := Seg (DirBuf); Regs. DI := Ofs (DirBuf); CD_Intr; ErrCode := Regs. AX; IF (Regs. Flags AND CarryFlag) = 0 THEN BEGIN Move (DirBuf. NameArray [1], DirBuf. FileName [1], 38); DirBuf. FileName [0] := #12; { File names are only 8.3 } Format := Regs. AX END ELSE Format := $FF; END; PROCEDURE CD_Dev_Req (DevPointer : Pointer); BEGIN Clear_Regs; Regs. AL := $10; Regs. CX := Drive; Regs. ES := PointerHalf (DevPointer).HiHalf; Regs. BX := PointerHalf (DevPointer).LoHalf; CD_Intr; END; PROCEDURE IO_Control (Command : Byte); BEGIN IOBlock. IOReq_Hdr. Len := 26; IOBlock. IOReq_Hdr. SubUnit := SubUnit; IOBlock. IOReq_Hdr. Status := 0; IOBlock. TransAddr := @DriveBytes; IOBlock. IOReq_Hdr. Command := Command; FillChar (IOBlock. IOReq_Hdr. Reserved, 8, #0); CD_Dev_Req (@IOBlock); Busy := (IOBlock. IOReq_Hdr. Status AND 512) <> 0; END; PROCEDURE Audio_Channel_Info; BEGIN FillChar (DriveBytes, SizeOf (DriveBytes), #0); DriveBytes [1] := 4; IOBlock. NumBytes := 9; IO_Control (IOCtlInput); Move (DriveBytes, AudioChannel, 9); END; PROCEDURE DeviceStatus; BEGIN FillChar (DriveBytes, SizeOf (DriveBytes), #0); DriveBytes [1] := 6; IOBlock. NumBytes := 5; IO_Control (IOCtlInput); DoorOpen := DriveBytes [2] AND 1 <> 0; DoorLocked := DriveBytes [2] AND 2 <> 0; AudioManip := DriveBytes [3] AND 1 <> 0; DiscInDrive := DriveBytes [3] AND 8 <> 0; END; PROCEDURE Audio_Disk_Info; BEGIN FillChar (DriveBytes, SizeOf (DriveBytes), #0); DriveBytes [1] := 10; IOBlock. NumBytes := 7; IO_Control (IOCtlInput); Move (DriveBytes [2], AudioDiskInfo, 6); Playing := Busy; END; PROCEDURE Audio_Track_Info (VAR StartPoint : LongInt; VAR TrackControl : Byte); BEGIN FillChar (DriveBytes, SizeOf (DriveBytes), #0); DriveBytes [1] := 11; DriveBytes [2] := TrackControl; { Track number } IOBlock. NumBytes := 7; IO_Control (IOCtlInput); Move (DriveBytes [3], StartPoint, 4); TrackControl := DriveBytes [7]; Playing := Busy; END; PROCEDURE Q_Channel_Info; BEGIN FillChar (DriveBytes, SizeOf (DriveBytes), #0); DriveBytes [1] := 12; IOBlock. NumBytes := 11; IO_Control (IOCtlInput); Move (DriveBytes [2], QChannelInfo, 11); END; PROCEDURE Audio_Status_Info; BEGIN FillChar (DriveBytes, SizeOf (DriveBytes), #0); DriveBytes [1] := 15; IOBlock. NumBytes := 11; IO_Control (IOCtlInput); Paused := (Word (DriveBytes [2] ) AND 1) <> 0; Move (DriveBytes [4], Last_Start, 4); Move (DriveBytes [8], Last_End, 4); Playing := Busy; END; PROCEDURE Eject; BEGIN FillChar (DriveBytes, SizeOf (DriveBytes), #0); DriveBytes [1] := 0; IOBlock. NumBytes := 1; IO_Control (IOCtlOutput); END; PROCEDURE Resetcd; BEGIN FillChar (DriveBytes, SizeOf (DriveBytes), #0); DriveBytes [1] := 2; IOBlock. NumBytes := 1; IO_Control (IOCtlOutput); Busy := TRUE; END; PROCEDURE Lock (LockDrive : Boolean); BEGIN FillChar (DriveBytes, SizeOf (DriveBytes), #0); DriveBytes [1] := 1; IF LockDrive THEN DriveBytes [2] := 1 ELSE DriveBytes [2] := 0; IOBlock. NumBytes := 2; IO_Control (IOCtlOutput); END; PROCEDURE CloseTray; BEGIN FillChar (DriveBytes, SizeOf (DriveBytes), #0); DriveBytes [1] := 5; IOBlock. NumBytes := 1; IO_Control (IOCtlOutput); END; VAR AudioPlay : Audio_Play; FUNCTION Play (StartLoc, NumSec : LongInt) : Boolean; BEGIN FillChar (AudioPlay, SizeOf (AudioPlay), #0); AudioPlay. APReq. Command := PlayCD; AudioPlay. APReq. Len := 22; AudioPlay. APReq. SubUnit := SubUnit; AudioPlay. Start := StartLoc; AudioPlay. NumSecs := NumSec; AudioPlay. AddrMode := 1; CD_Dev_Req (@AudioPlay); Play := ( (AudioPlay. APReq. Status AND 32768) = 0); END; PROCEDURE Play_Audio (StartSec, EndSec : LongInt); VAR SP, EP : LongInt; SArray : ARRAY [1..4] OF Byte; EArray : ARRAY [1..4] OF Byte; BEGIN Move (StartSec, SArray [1], 4); Move (EndSec, EArray [1], 4); SP := SArray [3]; { Must use longint or get negative result } SP := (SP * 75 * 60) + (SArray [2] * 75) + SArray [1]; EP := EArray [3]; EP := (EP * 75 * 60) + (EArray [2] * 75) + EArray [1]; EP := EP - SP; Playing := Play (StartSec, EP); Audio_Status_Info; END; PROCEDURE Pause_Audio; BEGIN IF Playing THEN BEGIN FillChar (AudioPlay, SizeOf (AudioPlay), #0); AudioPlay. APReq. Command := stopplay; {stopplay} AudioPlay. APReq. Len := 13; AudioPlay. APReq. SubUnit := SubUnit; CD_Dev_Req (@AudioPlay); END; Audio_Status_Info; Playing := FALSE; END; PROCEDURE Resume_Play; BEGIN FillChar (AudioPlay, SizeOf (AudioPlay), #0); AudioPlay. APReq. Command := ResumePlay; AudioPlay. APReq. Len := 13; AudioPlay. APReq. SubUnit := SubUnit; CD_Dev_Req (@AudioPlay); Audio_Status_Info; END; FUNCTION Sector_Size (ReadMode : Integer) : Word; VAR SecSize : Word; BEGIN FillChar (DriveBytes, SizeOf (DriveBytes), #0); DriveBytes [1] := 7; DriveBytes [2] := ReadMode; IOBlock. NumBytes := 4; IO_Control (IOCtlInput); Move (DriveBytes [3], SecSize, 2); Sector_Size := SecSize; END; (*Function CD_GetVol:Boolean; begin CtlBlk[0] := 4; { die Lautstaerke lesen } CD_GetVol := CD_IOCtl(IoCtlRead, 8); if ((R.Flags and FCARRY) = 0) then Move(CtlBlk[1], CD.VolInfo, 8) else FillChar( CD.VolInfo, 8, 0) end; Function CD_SetVol:Boolean; begin CtlBlk[0] := 3; { die Lautstaerke setzen } CD_SetVol := CD_IOCtl( IoCtlWrite, 8); end; *) FUNCTION Volume_Size : LongInt; VAR VolSize : LongInt; BEGIN FillChar (DriveBytes, SizeOf (DriveBytes), #0); DriveBytes [1] := 8; IOBlock. NumBytes := 5; IO_Control (IOCtlInput); Move (DriveBytes [2], VolSize, 4); Volume_Size := VolSize; END; FUNCTION Media_Changed : Boolean; VAR MedChng : Byte; { 1 : Media not changed 0 : Don't Know -1 : Media changed } BEGIN FillChar (DriveBytes, SizeOf (DriveBytes), #0); DriveBytes [1] := 9; IOBlock. NumBytes := 2; IO_Control (IOCtlInput); Move (DriveBytes [2], MedChng, 4); Inc (MedChng); CASE MedChng OF 2 : Media_Changed := FALSE; 1, 0 : Media_Changed := TRUE; END; END; FUNCTION Head_Location (AddrMode : Byte) : LongInt; VAR HeadLoc : LongInt; BEGIN FillChar (DriveBytes, SizeOf (DriveBytes), #0); DriveBytes [1] := 1; DriveBytes [2] := AddrMode; IOBlock. NumBytes := 6; IO_Control (IOCtlInput); Move (DriveBytes [3], HeadLoc, 4); Head_Location := HeadLoc; END; PROCEDURE Read_Drive_Bytes (VAR ReadBytes : DriveByteArray); BEGIN FillChar (DriveBytes, SizeOf (DriveBytes), #0); DriveBytes [1] := 5; IOBlock. NumBytes := 130; IO_Control (IOCtlInput); Move (DriveBytes [3], ReadBytes, 128); END; FUNCTION UPC_Code : String; VAR I, J, K : Integer; TempStr : String; BEGIN FillChar (DriveBytes, SizeOf (DriveBytes), #0); TempStr := ''; DriveBytes [1] := 14; IOBlock. NumBytes := 11; IO_Control (IOCtlInput); IF ( (IOBlock. IOReq_Hdr. Status AND 32768) = 0) THEN; FOR I := 3 TO 9 DO BEGIN J := DriveBytes [I] AND $0F; K := DriveBytes [I] AND $F0; TempStr := TempStr + Chr (J + 48); TempStr := TempStr + Chr (K + 48); END; IF Length (TempStr) > 13 THEN TempStr [0] := Chr (Ord (TempStr [0] ) - 1); UPC_Code := TempStr; END; PROCEDURE Read_Long (TransAddr : Pointer; StartSec : LongInt); VAR RL : ReadControl; { ReadControl = Record IOReq_Hdr : Req_Hdr; AddrMode : Byte; TransAddr : Pointer; NumSecs : Word; StartSec : LongInt; ReadMode : Byte; IL_Size, IL_Skip : Byte; End; } BEGIN FillChar (RL, SizeOf (RL), #0); RL. IOReq_Hdr. Len := 27; RL. IOReq_Hdr. SubUnit := SubUnit; RL. IOReq_Hdr. Command := ReadLong; RL. AddrMode := 1; RL. TransAddr := TransAddr; RL. NumSecs := 1; RL. StartSec := StartSec; RL. ReadMode := 0; CD_Dev_Req (@RL); END; PROCEDURE SeekSec (StartSec : LongInt); VAR RL : ReadControl; BEGIN FillChar (RL, SizeOf (RL), #0); RL. IOReq_Hdr. Len := 24; RL. IOReq_Hdr. SubUnit := SubUnit; RL. IOReq_Hdr. Command := SeekCmd; RL. AddrMode := 1; RL. StartSec := StartSec; RL. ReadMode := 0; CD_Dev_Req (@RL); END; PROCEDURE InputFlush; VAR IOReq : Req_Hdr; BEGIN FillChar (IOReq, SizeOf (IOReq), #0); WITH IOReq DO BEGIN Len := 13; SubUnit := SubUnit; Command := 7; Status := 0; END; CD_Dev_Req (@IOReq); END; PROCEDURE OutputFlush; VAR IOReq : Req_Hdr; BEGIN FillChar (IOReq, SizeOf (IOReq), #0); WITH IOReq DO BEGIN Len := 13; SubUnit := SubUnit; Command := 11; Status := 0; END; CD_Dev_Req (@IOReq); END; PROCEDURE DevOpen; VAR IOReq : Req_Hdr; BEGIN FillChar (IOReq, SizeOf (IOReq), #0); WITH IOReq DO BEGIN Len := 13; SubUnit := SubUnit; Command := 13; Status := 0; END; CD_Dev_Req (@IOReq); END; PROCEDURE DevClose; VAR IOReq : Req_Hdr; BEGIN FillChar (IOReq, SizeOf (IOReq), #0); WITH IOReq DO BEGIN Len := 13; SubUnit := SubUnit; Command := 14; Status := 0; END; CD_Dev_Req (@IOReq); END; {************************************************************} BEGIN NumberOfCD := 0; FirstCD := 0; FillChar (MSCDEX_Version, SizeOf (MSCDEX_Version), #0); Initialize; Drive := FirstCD; SubUnit := 0; END. {CUT OFF ...} {CUT ... Save this as CD_VARS.PAS} UNIT CD_Vars; INTERFACE TYPE ListBuf = RECORD UnitCode : Byte; UnitSeg, UnitOfs : Word; END; VTOCArray = ARRAY [1..2048] OF Byte; DriveByteArray = ARRAY [1..128] OF Byte; Req_Hdr = RECORD Len : Byte; SubUnit : Byte; Command : Byte; Status : Word; Reserved: ARRAY [1..8] OF Byte; END; CONST Init = 0; IoCtlInput = 3; InputFlush = 7; IOCtlOutput = 12; DevOpen = 13; DevClose = 14; ReadLong = 128; ReadLongP = 130; SeekCmd = 131; PlayCD = 132; StopPlay = 133; ResumePlay = 136; TYPE Audio_Play = RECORD APReq : Req_Hdr; AddrMode : Byte; Start : LongInt; NumSecs : LongInt; END; IOControl = RECORD IOReq_Hdr : Req_Hdr; MediaDesc : Byte; TransAddr : Pointer; NumBytes : Word; StartSec : Word; ReqVol : Pointer; END; ReadControl = RECORD IOReq_Hdr : Req_Hdr; AddrMode : Byte; TransAddr : Pointer; NumSecs : Word; StartSec : LongInt; ReadMode : Byte; IL_Size, IL_Skip : Byte; END; AudioDiskInfoRec = RECORD LowestTrack : Byte; HighestTrack : Byte; LeadOutTrack : LongInt; {new!} VolInfo: ARRAY [1..8] OF Byte; { Lautst.-Einstellungen } END; PAudioTrackInfo = ^AudioTrackInfoRec; AudioTrackInfoRec = RECORD Track : Integer; StartPoint : LongInt; EndPoint : LongInt; Frames, Seconds, Minutes, PlayMin, PlaySec, TrackControl : Byte; END; MSCDEX_Ver_Rec = RECORD Major, Minor : Integer; END; DirBufRec = RECORD XAR_Len : Byte; FileStart : LongInt; BlockSize : Integer; FileLen : LongInt; DT : Byte; Flags : Byte; InterSize : Byte; InterSkip : Byte; VSSN : Integer; NameLen : Byte; NameArray : ARRAY [1..38] OF Char; FileVer : Integer; SysUseLen : Byte; SysUseData: ARRAY [1..220] OF Byte; FileName : String [38]; END; Q_Channel_Rec = RECORD Control : Byte; Track : Byte; Index : Byte; Minutes : Byte; Seconds : Byte; Frame : Byte; Zero : Byte; AMinutes : Byte; ASeconds : Byte; AFrame : Byte; END; VAR AudioChannel : ARRAY [1..9] OF Byte; DoorOpen, DoorLocked, AudioManip, DiscInDrive : Boolean; AudioDiskInfo : AudioDiskInfoRec; DriverList : ARRAY [1..26] OF ListBuf; NumberOfCD : Integer; FirstCD : Integer; UnitList : ARRAY [1..26] OF Byte; MSCDEX_Version : MSCDEX_Ver_Rec; QChannelInfo : Q_Channel_Rec; Busy, Playing, Paused : Boolean; Last_Start, Last_End : LongInt; DirBuf : DirBufRec; IMPLEMENTATION BEGIN FillChar (DriverList, SizeOf (DriverList), #0); FillChar (UnitList, SizeOf (UnitList), #0); NumberOfCD := 0; FirstCD := 0; MSCDEX_Version. Major := 0; MSCDEX_Version. Minor := 0; END. {CUT OFF ...} {CUT ... Save this as TPTIMER.PAS} {$S-,R-,I-,V-,B-} {*********************************************************} {* TPTIMER.PAS 2.00 *} {* by TurboPower Software *} {*********************************************************} UNIT TpTimer; {-Allows events to be timed with 1 microsecond resolution} INTERFACE PROCEDURE InitializeTimer; {-Reprogram the timer chip to allow 1 microsecond resolution} PROCEDURE RestoreTimer; {-Restore the timer chip to its normal state} FUNCTION ReadTimer : LongInt; {-Read the timer with 1 microsecond resolution} FUNCTION ElapsedTime (Start, Stop : LongInt) : Real; {-Calculate time elapsed (in milliseconds) between Start and Stop} FUNCTION ElapsedTimeString (Start, Stop : LongInt) : String; {-Return time elapsed (in milliseconds) between Start and Stop as a string} {==========================================================================} IMPLEMENTATION CONST TimerResolution = 1193181.667; VAR SaveExitProc : Pointer; Delta : LongInt; FUNCTION Cardinal (L : LongInt) : Real; {-Return the unsigned equivalent of L as a real} BEGIN {Cardinal} IF L < 0 THEN Cardinal := 4294967296.0 + L ELSE Cardinal := L; END; {Cardinal} FUNCTION ElapsedTime (Start, Stop : LongInt) : Real; {-Calculate time elapsed (in milliseconds) between Start and Stop} BEGIN {ElapsedTime} ElapsedTime := 1000.0 * Cardinal (Stop - (Start + Delta) ) / TimerResolution; END; {ElapsedTime} FUNCTION ElapsedTimeString (Start, Stop : LongInt) : String; {-Return time elapsed (in milliseconds) between Start and Stop as a string} VAR R : Real; S : String; BEGIN {ElapsedTimeString} R := ElapsedTime (Start, Stop); Str (R: 0: 3, S); ElapsedTimeString := S; END; {ElapsedTimeString} PROCEDURE InitializeTimer; {-Reprogram the timer chip to allow 1 microsecond resolution} BEGIN {InitializeTimer} {select timer mode 2, read/write channel 0} Port [$43] := $34; {00110100b} INLINE ($EB / $00); {jmp short $+2 ;delay} Port [$40] := $00; {LSB = 0} INLINE ($EB / $00); {jmp short $+2 ;delay} Port [$40] := $00; {MSB = 0} END; {InitializeTimer} PROCEDURE RestoreTimer; {-Restore the timer chip to its normal state} BEGIN {RestoreTimer} {select timer mode 3, read/write channel 0} Port [$43] := $36; {00110110b} INLINE ($EB / $00); {jmp short $+2 ;delay} Port [$40] := $00; {LSB = 0} INLINE ($EB / $00); {jmp short $+2 ;delay} Port [$40] := $00; {MSB = 0} END; {RestoreTimer} FUNCTION ReadTimer : LongInt; {-Read the timer with 1 microsecond resolution} BEGIN {ReadTimer} INLINE ( $FA / {cli ;Disable interrupts} $BA / $20 / $00 / {mov dx,$20 ;Address PIC ocw3} $B0 / $0A / {mov al,$0A ;Ask to read irr} $EE / {out dx,al} $B0 / $00 / {mov al,$00 ;Latch timer 0} $E6 / $43 / {out $43,al} $EC / {in al,dx ;Read irr} $89 / $C7 / {mov di,ax ;Save it in DI} $E4 / $40 / {in al,$40 ;Counter --> bx} $88 / $C3 / {mov bl,al ;LSB in BL} $E4 / $40 / {in al,$40} $88 / $C7 / {mov bh,al ;MSB in BH} $F7 / $D3 / {not bx ;Need ascending counter} $E4 / $21 / {in al,$21 ;Read PIC imr} $89 / $C6 / {mov si,ax ;Save it in SI} $B0 / $FF / {mov al,$0FF ;Mask all interrupts} $E6 / $21 / {out $21,al} $B8 / $40 / $00 / {mov ax,$40 ;read low word of time} $8E / $C0 / {mov es,ax ;from BIOS data area} $26 / $8B / $16 / $6C / $00 / {mov dx,es:[$6C]} $89 / $F0 / {mov ax,si ;Restore imr from SI} $E6 / $21 / {out $21,al} $FB / {sti ;Enable interrupts} $89 / $F8 / {mov ax,di ;Retrieve old irr} $A8 / $01 / {test al,$01 ;Counter hit 0?} $74 / $07 / {jz done ;Jump if not} $81 / $FB / $FF / $00 / {cmp bx,$FF ;Counter > $FF?} $77 / $01 / {ja done ;Done if so} $42 / {inc dx ;Else count int req.} {done:} $89 / $5E / $FC / {mov [bp-4],bx ;set function result} $89 / $56 / $FE); {mov [bp-2],dx} END; {ReadTimer} PROCEDURE Calibrate; {-Calibrate the timer} CONST Reps = 1000; VAR I : Word; L1, L2, Diff : LongInt; BEGIN {Calibrate} Delta := MaxInt; FOR I := 1 TO Reps DO BEGIN L1 := ReadTimer; L2 := ReadTimer; {use the minimum difference} Diff := L2 - L1; IF Diff < Delta THEN Delta := Diff; END; END; {Calibrate} {$F+} PROCEDURE OurExitProc; {-Restore timer chip to its original state} BEGIN {OurExitProc} ExitProc := SaveExitProc; RestoreTimer; END; {OurExitProc} {$F-} BEGIN {set up our exit handler} SaveExitProc := ExitProc; ExitProc := @OurExitProc; {reprogram the timer chip} InitializeTimer; {adjust for speed of machine} Calibrate; END. {CUT OFF...} {CUT ... Save this as TCTIMER.PAS} UNIT tctimer; INTERFACE USES tptimer; VAR start : LongInt; PROCEDURE StartTimer; PROCEDURE WriteElapsedTime; IMPLEMENTATION PROCEDURE StartTimer; BEGIN start := ReadTimer; END; PROCEDURE WriteElapsedTime; VAR stop : LongInt; BEGIN stop := ReadTimer; WriteLn ('calc = ', (ElapsedTime (start, stop) / 1000): 10: 6, ' sec'); END; END. {CUT OFF...} {CUT ... Save this as TPBUFFER.PAS} UNIT TPbuffer; (* TP-Buffer unit version 1.1 /Update *) (* Using the keyboard's buffer in Turbo Pascal *) (* This unit is released to the public domain *) (* by Lavi Tidhar on 5-10-1992 *) (* This unit adds three special functions not *) (* incuded in the Turbo Pascal regular package *) (* You may alter this source code, move the *) (* procedures to your own programs. Please do *) (* NOT change these lines of documentation *) (* This source might teach you about how to *) (* use interrupts in pascal, and the keyboard's *) (* buffer. from the other hand, it might not :-) *) (* Used: INT 16, functions 0 and 1 *) (* INT 21, function 0Ch *) (* INT 16 - KEYBOARD - READ CHAR FROM BUFFER, WAIT IF EMPTY AH = 00h Return: AH = scan code AL = character *) (* INT 16 - KEYBOARD - CHECK BUFFER, DO NOT CLEAR AH = 01h Return: ZF = 0 character in buffer AH = scan code AL = character ZF = 1 no character in buffer *) (* INT 21 - DOS - CLEAR KEYBOARD BUFFER AH = 0Ch AL must be 1, 6, 7, 8, or 0Ah. Notes: Flushes all typeahead input, then executes function specified by AL (effectively moving it to AH and repeating the INT 21 call). If AL contains a value not in the list above, the keyboard buffer is flushed and no other action is taken. *) (* For more details/help etc, you can contact me on: *) (* Mail: Lavi Tidhar 46 Bantam Dr. Blairgowrie 2194 South Africa *) (* Phone: International: +27-11-787-8093 South Africa: (011)-787-8093 *) (* Netmail: The Catacomb BBS 5:7101/45 (fidonet) The Catacomb BBS 80:80/100 (pipemail) *) INTERFACE USES DOS; FUNCTION GetScanCode: Byte; (* Get SCAN CODE from buffer, wait if empty *) FUNCTION GetKey: Char; (* Get Char from buffer, do NOT wait *) PROCEDURE FlushKB; IMPLEMENTATION FUNCTION GetKey: Char; VAR Regs: Registers; BEGIN Regs. AH := 1; (* Int 16 function 1 *) Intr ($16, Regs); (* Read a charecter from the keyboard buffer *) GetKey := Chr (Regs. AL); (* do not wait. If no char was found, CHR(0) *) END; (* (nul) is returned *) FUNCTION GetScanCode: Byte; (* Int 16 function 0 *) VAR Regs: Registers; (* The same as CRT's Readkey, but gives you *) BEGIN (* the scan code. Esp usefull when you want to *) Regs. AH := 1; (* use special keys as the arrows, there will *) Intr ($16, Regs); (* be a conflict when using ReadKey *) GetScanCode := Regs. AH; END; PROCEDURE FlushKB; (* INT 21 function 0C *) VAR Regs: Registers; (* Flushes (erase) the keyboard buffer *) BEGIN (* ONLY. No other function is executed *) Regs. AH := $0C; Regs. AL := 2; Intr ($21, Regs); END; END. {CUT OFF...} {CUT... Save this as SCANCODE.PAS} UNIT ScanCode; { This UNIT is created by Wayne Boyd, aka Vipramukhya Swami, BBS phone (604)431-6260, Fidonet node 1:153/763. It's function is to facilitate the use of Function keys and Alt keys in a program. It includes F1 through F10, Shift-F1 through Shift-F10, Ctrl-F1 through Ctrl-F10, and Alt-F1 through Alt-F10. It also includes all of the alt keys, all of the Ctrl keys and many other keys as well. This UNIT and source code are copyrighted material and may not be used for commercial use without express written permission from the author. Use at your own risk. I take absolutely no responsibility for it, and there are no guarantees that it will do anything more than take up space on your disk. } INTERFACE CONST F1 = 59; CtrlF1 = 94; AltF1 = 104; Homekey = 71; F2 = 60; CtrlF2 = 95; AltF2 = 105; Endkey = 79; F3 = 61; CtrlF3 = 96; AltF3 = 106; PgUp = 73; F4 = 62; CtrlF4 = 97; AltF4 = 107; PgDn = 81; F5 = 63; CtrlF5 = 98; AltF5 = 108; UpArrow = 72; F6 = 64; CtrlF6 = 99; AltF6 = 109; RtArrow = 77; F7 = 65; CtrlF7 = 100; AltF7 = 110; DnArrow = 80; F8 = 66; CtrlF8 = 101; AltF8 = 111; LfArrow = 75; F9 = 67; CtrlF9 = 102; AltF9 = 112; InsertKey = 82; F10 = 68; CtrlF10 = 103; AltF10 = 113; DeleteKey = 83; AltQ = 16; AltA = 30; AltZ = 44; Alt1 = 120; ShftF1 = 84; AltW = 17; AltS = 31; AltX = 45; Alt2 = 121; ShftF2 = 85; AltE = 18; AltD = 32; AltC = 46; Alt3 = 122; ShftF3 = 86; AltR = 19; AltF = 33; AltV = 47; Alt4 = 123; ShftF4 = 87; AltT = 20; AltG = 34; AltB = 48; Alt5 = 124; ShftF5 = 88; AltY = 21; AltH = 35; AltN = 49; Alt6 = 125; ShftF6 = 89; AltU = 22; AltJ = 36; AltM = 50; Alt7 = 126; ShftF7 = 90; AltI = 23; AltK = 37; Alt8 = 127; ShftF8 = 91; AltO = 24; AltL = 38; Alt9 = 128; ShftF9 = 92; AltP = 25; CtrlLf = 115; Alt0 = 129; ShftF10 = 93; CtrlRt = 116; CtrlA = #1; CtrlK = #11; CtrlU = #21; CtrlB = #2; CtrlL = #12; CtrlV = #22; CtrlC = #3; CtrlM = #13; CtrlW = #23; CtrlD = #4; CtrlN = #14; CtrlX = #24; CtrlE = #5; CtrlO = #15; CtrlY = #25; CtrlF = #6; CtrlP = #16; CtrlZ = #26; CtrlG = #7; CtrlQ = #17; CtrlS = #19; CtrlH = #8; CtrlR = #18; CtrlI = #9; CtrlJ = #10; CtrlT = #20; BSpace = #8; EscapeKey = #27; EnterKey = #13; NullKey = #0; IMPLEMENTATION END. {CUT OFF...}