Unit CD;

{----------------------------------------------------------------------------}

{  CD : An implementation of a CD-ROM driver.                                }

{****************************************************************************}

{  Author            : Menno Victor van der star                             }

{  E-Mail            : s795238@dutiwy.twi.tudelft.nl                         }

{  Developed on      : 08-06-'95                                             }

{  Last update on    : 07-09-'95                                             }

{  Status            : Finished                                              }

{  Future extensions : None                                                  }

{----------------------------------------------------------------------------}

{$R-}

Interface



Uses Dos;



Type

  CDRomParametersRecord = Record

                            Raw : Boolean;

                            SectorSize : Word;

                            NumberOfSectors : LongInt;

                          End;



  CDRomPositionInfo = Record

                        CntAdr : Byte;

                        CTrk   : Byte;

                        Cindx  : Byte;

                        CMin   : Byte;

                        CSek   : Byte;

                        CFrm   : Byte;

                        Czero  : Byte;

                        CAmin  : Byte;

                        CAsec  : Byte;

                        CAFrm  : Byte;

                      End;



  CDRom = Object



            ValidCDRoms : String;

            Error : Word;

            CDRomDevice : Text;



            Constructor Init;

            Destructor  Done; Virtual;



            Procedure   ChangeDrive (DriveLetter : Char);

            Procedure   OpenDoor;

            Procedure   CloseDoor;

            Procedure   LockDoor;

            Procedure   UnlockDoor;

            Procedure   Reset;

            Function    DriveStatus : Word;

            Procedure   GetDriveParameters (Var Parameters : CDRomParametersRecord);

            Procedure   GetPosition (Var Position : CDRomPositionInfo);



            Procedure   PlayAudio (MinuteStart, SecondStart, MinuteEnd, SecondEnd : Byte);

            Procedure   PlayTrack (TrackNr : Byte);

            Procedure   PausePlay;

            Procedure   ResumePlay;

            Function    NumberOfAudioTracks : Byte;



          Private



            Regs : Registers;

            MSCDEXVerMajor, MSCDEXVerMinor : Byte;

            NumCDRoms : Byte;

            DriverNames : Array ['A'..'Z'] Of Record

                                                SubunitNr : Byte;

                                                Name : String[8];

                                              End;

            CurrentDrive : Char;



            Function    DeviceCommand (CommandNr, DosFunction : Word; Var Data) : Word;

            Function    RedBookToHSG (Minute, Second, Frame : Byte) : LongInt;



          End;



Implementation



Type

  PCharArray = ^CharArray;

  CharArray = Array [0..0] Of Char;



Constructor CDRom.Init;



Var

  n : Word;

  c, c2 : Char;

  DeviceInfo : Array ['A'..'Z'] Of Record

                                     SubunitNr : Byte;

                                     NamePtr : PCharArray;

                                   End;

Begin

  Regs.ax:=$1100;             { MSCDEX Installed? }

  Intr ($2F,Regs);

  If Regs.al<>255 then Fail;  { MSCDEX Not installed, fail to construct }



  Regs.AX:=$150C;            { Get MSCDEX version }

  Intr ($2F,Regs);

  MSCDEXVerMajor:=Regs.BH;

  MSCDEXVerMinor:=Regs.BL;

  { Only work with versions 2.1 or higher }

  If (MSCDEXVerMajor<2) Or ((MSCDEXVerMajor=2) And (MSCDEXVerMinor < 10)) then Fail;



  Regs.AX:=$1500;             { get number of cdrom's }

  Regs.BX:=0;

  Intr ($2F,Regs);

  NumCDRoms:=Regs.BX;

  If NumCDRoms=0 then Fail;   { No cdroms present, fail to construct }



  Regs.AX:=$150D;

  Regs.ES:=Seg (ValidCDRoms[1]);

  Regs.BX:=Ofs (ValidCDRoms[1]);

  Intr ($2F,Regs);

  ValidCDRoms[0]:=Chr (NumCDRoms);

  For n:=1 to Length (ValidCDRoms) Do ValidCDRoms[n]:=Chr (Ord (ValidCDRoms[n])+65);

  For c:='A' to 'Z' Do Begin

    DriverNames[c].Name:='';

    DriverNames[c].SubunitNr:=0;

    DeviceInfo[c].SubunitNr:=0;

    DeviceInfo[c].NamePtr:=NIL;

  End;

  Regs.AX:=$1501;

  Regs.ES:=Seg (DeviceInfo);

  Regs.BX:=Ofs (DeviceInfo);

  Intr ($2f,Regs);

  c2:='A';

  For c:='A' to 'Z' Do Begin

    Regs.AX:=$150B;

    Regs.CX:=Ord (c)-65;

    Intr ($2F,Regs);

    If (Regs.AX>0) And Assigned (DeviceInfo[c2].NamePtr) then Begin

      n:=10;

      While (n<=17) And (DeviceInfo[c2].NamePtr^[n]<>' ') Do Begin

        DriverNames[c].Name:=DriverNames[c].Name+DeviceInfo[c2].NamePtr^[n];

        Inc (n);

      End;

      DriverNames[c].SubunitNr:=DeviceInfo[c2].SubunitNr;

      If c2='A' then ChangeDrive (c);

      Inc (c2);

    End

  End;

  Reset;

End;



Destructor CDRom.Done;



Begin

  Close (CDRomDevice);

End;



Procedure CDRom.ChangeDrive (DriveLetter : Char);



Begin

  If DriverNames[DriveLetter].Name='' then Exit;

  Assign (CDRomDevice,DriverNames[DriveLetter].Name);

  System.Reset (CDRomDevice);

  CurrentDrive:=DriveLetter;

End;



Procedure CDRom.OpenDoor;



Var

  Data : Byte;



Begin

  Data:=0;

  Error:=DeviceCommand (1,$4403,Data);

End;



Procedure CDRom.CloseDoor;



Var

  Data : Byte;



Begin

  Data:=5;

  Error:=DeviceCommand (1,$4403,Data);

  Reset;

End;



Procedure CDRom.LockDoor;



Var

  Data : Word;



Begin

  Data:=$0001;

  Error:=DeviceCommand (2,$4403,Data);

End;



Procedure CDRom.UnlockDoor;



Var

  Data : Word;



Begin

  Data:=$0101;

  Error:=DeviceCommand (2,$4403,Data);

  Reset;

End;



Procedure CDRom.Reset;



Var

  Data : Byte;



Begin

  Data:=2;

  Error:=DeviceCommand (1,$4403,Data);

End;



Function CDRom.DriveStatus : Word;



Var

  Data : Record Command : Byte; Status : Word; Dummy2 : Word; End;



Begin

  Data.Command:=6;

  Error:=DeviceCommand (5,$4402,Data);

  DriveStatus:=Data.Status And 2047;

{  Reset; }

End;



Procedure CDRom.GetDriveParameters (Var Parameters : CDRomParametersRecord);



Var

  Data1 : Record Command, Raw : Byte; SectorSize : Word; End;

  Data2 : Record Command : Byte; NumberOfSectors : LongInt; End;



Begin

  Data1.Command:=7;

  Error:=DeviceCommand (4,$4402,Data1);

  Data2.Command:=8;

  Error:=DeviceCommand (5,$4402,Data2);

  Parameters.Raw:=Data1.Raw=1;

  Parameters.SectorSize:=Data1.SectorSize;

  Parameters.NumberOfSectors:=Data2.NumberOfSectors;

End;



Procedure CDRom.GetPosition (Var Position : CDRomPositionInfo);



Var

  Data : Record

           Command : Byte;

           Info : CDRomPositionInfo;

         End;



Begin

  Data.Command:=12;

  Error:=DeviceCommand (129,$4402,Data);

  Position:=Data.Info;

End;



Procedure CDRom.PlayAudio (MinuteStart, SecondStart, MinuteEnd, SecondEnd : Byte);



Var

  HSGAddress1, HSGAddress2 : LongInt;

  Data : Record

           Bytes : Array [0..13] Of Byte;

           HSGAddress : LongInt;

           NumberOfFrames : LongInt;

         End;



Begin

  HSGAddress1:=RedBookToHSG (MinuteStart, SecondStart, 0);

  HSGAddress2:=RedBookToHSG (MinuteEnd, SecondEnd, 0);



  Data.Bytes[0]:=$16;

  Data.Bytes[1]:=DriverNames[CurrentDrive].SubunitNr;

  Data.Bytes[2]:=$84;

  Data.Bytes[13]:=0;

  Data.HSGAddress:=HSGAddress1;

  Data.NumberOfFrames:=HSGAddress2-HSGAddress1;



  Regs.ES:=Seg (Data);

  Regs.BX:=Ofs (Data);

  Regs.CX:=Ord (CurrentDrive)-65;

  Regs.AX:=$1510;

  Intr ($2F,Regs);

End;



Procedure CDRom.PlayTrack (TrackNr : Byte);



Var

  Track1 : Record

            Command, TrackNr : Byte;

            RedBookAdress : Record

                              Frame,

                              Second,

                              Minute,

                              Dummy : Byte;

                            End;

            TrackControl : Word;

            HSGAddress : LongInt;

          End;

  Track2 : Record

            Command, TrackNr : Byte;

            RedBookAdress : Record

                              Frame,

                              Second,

                              Minute,

                              Dummy : Byte;

                            End;

            TrackControl : Word;

            HSGAddress : LongInt;

          End;

  Data : Record

           Bytes : Array [0..13] Of Byte;

           HSGAddress : LongInt;

           NumberOfFrames : LongInt;

         End;

  NumberOfTracks : Byte;



Begin

  NumberOfTracks:=NumberOfAudioTracks;

  Track1.Command:=$0B;

  Track1.TrackNr:=TrackNr;

  Error:=DeviceCommand (8,$4402,Track1);

  Track1.HSGAddress:=RedBookToHSG (Track1.RedBookAdress.Minute,

                                   Track1.RedBookAdress.Second,

                                   Track1.RedBookAdress.Frame);

  If Track1.TrackControl And 16384<>0 then Exit;

  Track2.Command:=$0B;

  Track2.TrackNr:=TrackNr+1;

  Error:=DeviceCommand (8,$4402,Track2);

  Track2.HSGAddress:=RedBookToHSG (Track2.RedBookAdress.Minute,

                                   Track2.RedBookAdress.Second,

                                   Track2.RedBookAdress.Frame);

  Data.Bytes[0]:=$16;

  Data.Bytes[1]:=DriverNames[CurrentDrive].SubunitNr;

  Data.Bytes[2]:=$84;

  Data.Bytes[13]:=0;

  Data.HSGAddress:=Track1.HSGAddress;

  Data.NumberOfFrames:=Track2.HSGAddress-Track1.HSGAddress;



  Regs.ES:=Seg (Data);

  Regs.BX:=Ofs (Data);

  Regs.CX:=Ord (CurrentDrive)-65;

  Regs.AX:=$1510;

  Intr ($2F,Regs);

End;



Procedure CDRom.PausePlay;



Var

  Data : Array [0..12] Of Byte;



Begin

  Data[0]:=$0D;

  Data[1]:=DriverNames[CurrentDrive].SubunitNr;

  Data[2]:=$85;

  Regs.ES:=Seg (Data);

  Regs.BX:=Ofs (Data);

  Regs.CX:=Ord (CurrentDrive)-65;

  Regs.AX:=$1510;

  Intr ($2F,Regs);

End;



Procedure CDRom.ResumePlay;



Var

  Data : Array [0..12] Of Byte;



Begin

  Data[0]:=$0D;

  Data[1]:=DriverNames[CurrentDrive].SubunitNr;

  Data[2]:=$88;

  Regs.ES:=Seg (Data);

  Regs.BX:=Ofs (Data);

  Regs.CX:=Ord (CurrentDrive)-65;

  Regs.AX:=$1510;

  Intr ($2F,Regs);

End;



Function CDRom.NumberOfAudioTracks : Byte;



Var

  Data : Record Command : Byte; FirstTrack, LastTrack : Byte; Dummy : LongInt; End;



Begin

  Data.Command:=$0A;

  Error:=DeviceCommand (7,$4402,Data);

  NumberOfAudioTracks:=Data.LastTrack-Data.FirstTrack+1;

End;



Function CDRom.DeviceCommand (CommandNr, DosFunction : Word; Var Data) : Word;



Begin

  Regs.BX:=TextRec (CDRomDevice).Handle;

  Regs.DS:=Seg (Data);

  Regs.DX:=Ofs (Data);

  Regs.CX:=CommandNr;

  Regs.AX:=DosFunction;

  MsDos (Regs);

  If Regs.Flags And fCarry=0 then

    DeviceCommand:=0

  Else

    DeviceCommand:=Regs.AX;

End;



Function CDRom.RedBookToHSG (Minute, Second, Frame : Byte) : LongInt;



Begin

  RedBookToHSG:=(LongInt (Minute)*4500)+(LongInt (Second)*75)+Frame-183;

End;



End.