(*--------------------------------------------------------------------*)
(*                                                                    *)
(* Module . . . . . . .  CDBASE                                       *)
(* Source file  . . . .  CDBASE.PAS                                   *)
(* Language . . . . . .  Object Pascal                                *)
(* Compiler . . . . . .  Virtual Pascal/2 V1.10                       *)
(* Operating system . .  OS/2 Warp V3                                 *)
(* Author . . . . . . .  Th. Trepl, Munich Germany                    *)
(*                       101353,671@CompuServ.com                     *)
(* Reference  . . . . .  Control Program Programming Guide            *)
(*                       Example program CDPLAY of VP/2               *)
(*                                                                    *)
(*--------------------------------------------------------------------*)
(*                                                                    *)
(* Description                                                        *)
(* -----------                                                        *)
(*                                                                    *)
(* Functions and procedures to access a CDROM-drive.                  *)
(* Also providing low level functions and procedures to control the   *)
(* playback of audio tracks.                                          *)
(*                                                                    *)
(*--------------------------------------------------------------------*)
Unit CdBase;
Interface
(*--------------------------------------------------------------------*)
(* Interface                                                          *)
(*--------------------------------------------------------------------*)
Uses Os2Def, Os2Base;

{----------------------------------------------------------------------}
{ Api-Call Return Value                                                }
{----------------------------------------------------------------------}
Const
  IOCtlResult  : ApiRet = 0;

{----------------------------------------------------------------------}
{ Error Messages                                                       }
{----------------------------------------------------------------------}
Const
  NO_ERROR              = $0000;
  DRIVE_NOT_READY       = $0002;
  REQUEST_UNSUPPORTED   = $0003;
  ACCESS_DENIED         = $0005;
  SEEK_ERROR            = $0006;
  UNKNOWN_MEDIA         = $0007;
  SECTOR_NOT_FOUND      = $0008;
  UNCERTAIN_MEDIA       = $0010;
  INVALID_PARAMETER     = $0013;
  DRIVE_IN_USE          = $0014;

{----------------------------------------------------------------------}
{ Device Status Masks                                                  }
{----------------------------------------------------------------------}

Const
  DOOR_OPEN             = $0001;
  DOOR_LOCKED           = $0002;
  COOKED_AND_RAW        = $0004;
  READ_AND_WRITE        = $0008;
  AUDIO_DEVICE          = $0010;
  ISO_INTERLEAVE        = $0020;
{ RESERVED              = $0040; }
  PREFETCH_SUPPORT      = $0080;
  AUDIO_MANIPULATION    = $0100;
  LBF_AND_MSF_ADDRESS   = $0200;
  FORM1_AND_FORM2       = $0400;
  NO_DISK_PRESENT       = $0800;
  PLAYING_AUDIO         = $1000;

{----------------------------------------------------------------------}
{ Common Types                                                         }
{----------------------------------------------------------------------}
Type
  tReadBlock = Record
    Synch  : Array[0..11] Of Byte;
    Header : Array[0..3] Of Byte;
    Data   : Array[0..2047] Of Byte;
    EDCECC : Array[0..287] Of Byte;
  End;

Type
  tUPCStruct = Record
    CtrlAddr : Byte;
    UPC      : Array[0..6] Of Char;
    Reserved : Byte;
    Frame    : Byte;
  End;

Type
  tChannelCtrl = Record
    InpCnl : Array[0..3] Of Byte;
    Volume : Array[0..3] Of Byte;
  End;

Type
  tAudioDiskInfo = Record
    FirstTrack : Byte;
    LastTrack  : Byte;
    LeadOutAddr: LongInt;
  End;

Type
  tAudioTrackInfo = Record
    TrackAddr : LongInt;
    TrackCtrl : Byte;
  End;

Type
  tSubCnlInfo = Record
    CtrlADR    : Byte;
    TrackNr    : Byte;
    Index      : Byte;
    RunTrckMin : Byte;
    RunTrckSec : Byte;
    RunTrckFrm : Byte;
    Reserved   : Byte;
    RunDiskMin : Byte;
    RunDiskSec : Byte;
    RunDiskFrm : Byte;
  End;

Type
  tAudioStatus = Record
    AudioStatus : Word;
    StartLoc    : LongInt;
    EndingLoc   : LongInt;
  End;

{----------------------------------------------------------------------}
{ Basic Device-IO Functions                                            }
{----------------------------------------------------------------------}
Function OpenDevice(Drive : Char; ReadOnly : Boolean) : HFile;
Procedure CloseDevice(Var DevHndl : HFile);

{----------------------------------------------------------------------}
{ CDROM-Disk-Device Functions                                          }
{----------------------------------------------------------------------}
Procedure CDResetDrive(DevHndl : HFile);
Procedure CDEjectDisk(DevHndl : HFile);
Procedure CDCloseTray(DevHndl : HFile);
Procedure CDLockDoor(DevHndl : HFile);
Procedure CDUnlockDoor(DevHndl : HFile);
Procedure CDSeekSector(DevHndl : HFile; StartingSector : LongInt);
Procedure CDSeekMSF(DevHndl : HFile; MSF : LongInt);
Function  CDGetDiskStatus(DevHndl : HFile) : LongInt;
Function  CDGetDriver(DevHndl : HFile) : String;
Function  CDGetSectorSize(DevHndl : HFile) : Word;
Procedure CDGetHeadLocLBF(DevHndl : HFile; Var LBF : LongInt);
Procedure CDGetHeadLocMSF(DevHndl : HFile; Var MSF : LongInt);
Procedure CDReadLong(DevHndl : HFile; StartSector : LongInt; Var Buf : tReadBlock);
Function  CDGetVolumeSize(DevHndl : HFile) : LongInt;
Procedure CDGetUPC(DevHndl : HFile; Var UPC : tUPCStruct);
Function  CDSignature : String;

{----------------------------------------------------------------------}
{ CDROM-Audio Functions                                                }
{----------------------------------------------------------------------}
Procedure CDSetChannelCtrl(DevHndl : HFile; Data : tChannelCtrl);
Procedure CDPlayTrackMSF(DevHndl : HFile; StartTrack, StopTrack : LongInt);
Procedure CDPlayTrackLBF(DevHndl : HFile; StartTrack, StopTrack : LongInt);
Procedure CDStopAudio(DevHndl : HFile);
Procedure CDResumeAudio(DevHndl : HFile);
Procedure CDGetChannelCtrl(DevHndl : HFile; Var Data : tChannelCtrl);
Procedure CDGetAudioDisk(DevHndl : HFile; Var Data : tAudioDiskInfo);
Procedure CDGetAudioTrack(DevHndl : HFile; TrackNr : Byte; Var Data : tAudioTrackInfo);
Procedure CDGetSubChannelQ(DevHndl : HFile; Var Data : tSubCnlInfo);
Procedure CDGetAudioStatus(DevHndl : HFile; Var Data : tAudioStatus);

(*--------------------------------------------------------------------*)
(* Implementation                                                     *)
(*--------------------------------------------------------------------*)
Implementation

Const
  CDROMDISK_CATEGORY       = $80;
  CDROMDISK_RESETDRIVE     = $40;
  CDROMDISK_EJECTDISK      = $44;
  CDROMDISK_CLOSETRAY      = $45;
  CDROMDISK_LOCKUNLOCKDOOR = $46;
  CDROMDISK_SEEK           = $50;
  CDROMDISK_DEVICESTATUS   = $60;
  CDROMDISK_GETDRIVER      = $61;
  CDROMDISK_GETSECTORSIZE  = $63;
  CDROMDISK_GETHEADLOC     = $70;
  CDROMDISK_READLONG       = $72;
  CDROMDISK_GETVOLUMESIZE  = $78;
  CDROMDISK_GETUPC         = $79;

Const
  CDROMAUDIO_CATEGORY      = $81;
  CDROMAUDIO_SETCHANNELCTRL= $40;
  CDROMAUDIO_PLAYAUDIO     = $50;
  CDROMAUDIO_STOPAUDIO     = $51;
  CDROMAUDIO_RESUMEAUDIO   = $52;
  CDROMAUDIO_GETCHANNEL    = $60;
  CDROMAUDIO_GETAUDIODISK  = $61;
  CDROMAUDIO_GETAUDIOTRACK = $62;
  CDROMAUDIO_GETSUBCHANNELQ= $63;
  CDROMAUDIO_GETAUDIOSTATUS= $65;

Type
  tCDSignature = Array[0..3] Of Char;

Const
  CD_Signature : tCDSignature = ('C','D','0','1');

Type
  tCommandStrct = Record
    Signature : tCDSignature;
    Case Byte Of
      CDROMDISK_LOCKUNLOCKDOOR : (LockDoor     : Byte);
      CDROMDISK_SEEK           : (SeekAddrMode : Byte;
                                  SeekSector   : LongInt);
      CDROMDISK_GETHEADLOC     : (HdLocAddrMode: Byte);
      CDROMDISK_READLONG       : (ReadAddrMode : Byte;
                                  NrOfSectors  : Word;
                                  StartSector  : LongInt;
                                  Reserved     : Char;
                                  Interleave   : Byte);
      CDROMAUDIO_PLAYAUDIO     : (PlayAddrMode : Byte;
                                  PlayStartSect: LongInt;
                                  PlayStopSect : LongInt);
      CDROMAUDIO_GETAUDIOTRACK : (TrackNbr     : Byte);
  End;

Type
  tRtnDataStrct = Record
    Case Byte Of
      CDROMDISK_DEVICESTATUS   : (DevStatus    : LongInt);
      CDROMDISK_GETDRIVER      : (Signature    : Array[0..3] Of Char);
      CDROMDISK_GETSECTORSIZE  : (SectorSize   : Word);
      CDROMDISK_GETHEADLOC     : (HeadLocation : LongInt);
      CDROMDISK_GETVOLUMESIZE  : (VolumeSize   : LongInt);
      CDROMAUDIO_SETCHANNELCTRL: (InputCnl0    : Byte;
                                  VolumeCnl0   : Byte;
                                  InputCnl1    : Byte;
                                  VolumeCnl1   : Byte;
                                  InputCnl2    : Byte;
                                  VolumeCnl2   : Byte;
                                  InputCnl3    : Byte;
                                  VolumeCnl3   : Byte);
  End;

{----------------------------------------------------------------------}
{ Utility Functions                                                    }
{----------------------------------------------------------------------}
Function CDROMDISK_IoCtl(DevHndl : HFile; Fnct : LongInt;
                         Var CmdStrct; CmdSize : LongInt;
                         Var ParmStrct; ParmSize : LongInt) : ApiRet;
Begin
  Result := DosDevIOCtl(DevHndl, CDROMDISK_CATEGORY, Fnct,
                        @CmdStrct, CmdSize, @CmdSize,
                        @ParmStrct, ParmSize, @ParmSize);
  IOCtlResult := Result;
End;

Function CDROMAUDIO_IoCtl(DevHndl : HFile; Fnct : LongInt;
                          Var CmdStrct; CmdSize : LongInt;
                          Var ParmStrct; ParmSize : LongInt) : ApiRet;
Begin
  Result := DosDevIOCtl(DevHndl, CDROMAUDIO_CATEGORY, Fnct,
                        @CmdStrct, CmdSize, @CmdSize,
                        @ParmStrct, ParmSize, @ParmSize);
  IOCtlResult := Result;
End;

{----------------------------------------------------------------------}
{ Basic Device-IO Functions                                            }
{----------------------------------------------------------------------}
Function OpenDevice(Drive : Char; ReadOnly : Boolean) : HFile;
Var FName  : Array[0..2] Of Char;
    Action : LongInt;
    Attributes : LongInt;
    OpenFlags  : LongInt;
    OpenMode   : LongInt;
    EAs        : pEAOp2;
    DevHndl    : HFile;
Begin
  FName[0] := Drive;
  FName[1] := ':';
  FName[2] := #0;

  Attributes := File_Normal;
  OpenFlags  := File_Open Or Open_Action_Open_If_Exists Or Open_Action_Fail_If_New;
  If ReadOnly
    Then OpenMode := Open_Access_ReadOnly  Or Open_Share_DenyNone Or Open_Flags_Dasd
    Else OpenMode := Open_Access_ReadWrite Or Open_Share_DenyNone Or Open_Flags_Dasd;
  EAs        := Nil;
  IOCtlResult := DosOpen(@FName, DevHndl, Action, 0, Attributes, OpenFlags, OpenMode, EAs);
  If IOCtlResult = 0
    Then Result := DevHndl
    Else Result := $FFFFFFFF;
End;

Procedure CloseDevice(Var DevHndl : HFile);
Begin
  IOCtlResult := DosClose(DevHndl);
  If IoCtlResult = 0 Then DevHndl := $FFFFFFFF;
End;

{----------------------------------------------------------------------}
{ CDROM-Disk-Device Functions                                          }
{----------------------------------------------------------------------}
Procedure CDResetDrive(DevHndl : HFile);
Var CmdStrct : tCommandStrct;
    ParmStrct: tRtnDataStrct;
Begin
  CmdStrct.Signature := CD_Signature;
  FillChar(ParmStrct, SizeOf(ParmStrct), 0);
  CDROMDISK_IOCtl(DevHndl, CDROMDISK_RESETDRIVE,
                           CmdStrct, SizeOf(CmdStrct),
                           ParmStrct, SizeOf(ParmStrct));
End;

Procedure CDEjectDisk(DevHndl : HFile);
Var CmdStrct : tCommandStrct;
    ParmStrct: tRtnDataStrct;
Begin
  CmdStrct.Signature := CD_Signature;
  FillChar(ParmStrct, SizeOf(ParmStrct), 0);
  CDROMDISK_IOCtl(DevHndl, CDROMDISK_EJECTDISK,
                           CmdStrct, SizeOf(CmdStrct),
                           ParmStrct, SizeOf(ParmStrct));
End;

Procedure CDCloseTray(DevHndl : HFile);
Var CmdStrct : tCommandStrct;
    ParmStrct: tRtnDataStrct;
Begin
  CmdStrct.Signature := CD_Signature;
  FillChar(ParmStrct, SizeOf(ParmStrct), 0);
  CDROMDISK_IOCtl(DevHndl, CDROMDISK_CLOSETRAY,
                           CmdStrct, SizeOf(CmdStrct),
                           ParmStrct, SizeOf(ParmStrct));
End;

Procedure CDLockDoor(DevHndl : HFile);
Var CmdStrct : tCommandStrct;
    ParmStrct: tRtnDataStrct;
Begin
  CmdStrct.Signature := CD_Signature;
  CmdStrct.LockDoor := $01;
  FillChar(ParmStrct, SizeOf(ParmStrct), 0);
  CDROMDISK_IOCtl(DevHndl, CDROMDISK_LOCKUNLOCKDOOR,
                           CmdStrct, SizeOf(CmdStrct),
                           ParmStrct, SizeOf(ParmStrct));
End;

Procedure CDUnlockDoor(DevHndl : HFile);
Var CmdStrct : tCommandStrct;
    ParmStrct: tRtnDataStrct;
Begin
  CmdStrct.Signature := CD_Signature;
  CmdStrct.LockDoor  := $00;
  FillChar(ParmStrct, SizeOf(ParmStrct), 0);
  CDROMDISK_IOCtl(DevHndl, CDROMDISK_LOCKUNLOCKDOOR,
                           CmdStrct, SizeOf(CmdStrct),
                           ParmStrct, SizeOf(ParmStrct));
End;

Procedure CDSeekSector(DevHndl : HFile; StartingSector : LongInt);
Var CmdStrct : tCommandStrct;
    ParmStrct: tRtnDataStrct;
Begin
  CmdStrct.Signature := CD_Signature;
  CmdStrct.SeekAddrMode := $00;    // Logical-Block Format
  CmdStrct.SeekSector := StartingSector;
  FillChar(ParmStrct, SizeOf(ParmStrct), 0);
  CDROMDISK_IOCtl(DevHndl, CDROMDISK_SEEK,
                           CmdStrct, SizeOf(CmdStrct),
                           ParmStrct, SizeOf(ParmStrct));
End;

Procedure CDSeekMSF(DevHndl : HFile; MSF : LongInt);
Var CmdStrct : tCommandStrct;
    ParmStrct: tRtnDataStrct;
Begin
  CmdStrct.Signature := CD_Signature;
  CmdStrct.SeekAddrMode := $01;    // Minute/Second/Frame Format
  CmdStrct.SeekSector := MSF;
  FillChar(ParmStrct, SizeOf(ParmStrct), 0);
  CDROMDISK_IOCtl(DevHndl, CDROMDISK_SEEK,
                           CmdStrct, SizeOf(CmdStrct),
                           ParmStrct, SizeOf(ParmStrct));
End;

Function CDGetDiskStatus(DevHndl : HFile) : LongInt;
Var CmdStrct : tCommandStrct;
    ParmStrct: tRtnDataStrct;
Begin
  CmdStrct.Signature := CD_Signature;
  FillChar(ParmStrct, SizeOf(ParmStrct), 0);
  CDROMDISK_IOCtl(DevHndl, CDROMDISK_DEVICESTATUS,
                           CmdStrct, SizeOf(CmdStrct),
                           ParmStrct, SizeOf(ParmStrct));
  Result := ParmStrct.DevStatus;
End;

Function CDGetDriver(DevHndl : HFile) : String;
Var CmdStrct : tCommandStrct;
    ParmStrct: tRtnDataStrct;
Begin
  CmdStrct.Signature := CD_Signature;
  FillChar(ParmStrct, SizeOf(ParmStrct), 0);
  CDROMDISK_IOCtl(DevHndl, CDROMDISK_GETDRIVER,
                           CmdStrct, SizeOf(CmdStrct),
                           ParmStrct, SizeOf(ParmStrct));
  Result := ParmStrct.Signature;
End;

Function CDGetSectorSize(DevHndl : HFile) : Word;
Var CmdStrct : tCommandStrct;
    ParmStrct: tRtnDataStrct;
Begin
  CmdStrct.Signature := CD_Signature;
  FillChar(ParmStrct, SizeOf(ParmStrct), 0);
  CDROMDISK_IOCtl(DevHndl, CDROMDISK_GETSECTORSIZE,
                           CmdStrct, SizeOf(CmdStrct),
                           ParmStrct, SizeOf(ParmStrct));
  Result := ParmStrct.SectorSize;
End;

Procedure CDGetHeadLocLBF(DevHndl : HFile; Var LBF : LongInt);
Var CmdStrct : tCommandStrct;
    ParmStrct: tRtnDataStrct;
Begin
  CmdStrct.Signature := CD_Signature;
  CmdStrct.SeekAddrMode := $00;    // Logical-Block Format
  FillChar(ParmStrct, SizeOf(ParmStrct), 0);
  CDROMDISK_IOCtl(DevHndl, CDROMDISK_GETHEADLOC,
                           CmdStrct, SizeOf(CmdStrct),
                           ParmStrct, SizeOf(ParmStrct));
  LBF := ParmStrct.HeadLocation;
End;

Procedure CDGetHeadLocMSF(DevHndl : HFile; Var MSF : LongInt);
Var CmdStrct : tCommandStrct;
    ParmStrct: tRtnDataStrct;
Begin
  CmdStrct.Signature := CD_Signature;
  CmdStrct.SeekAddrMode := $01;    // Minute/Second/Frame Format
  FillChar(ParmStrct, SizeOf(ParmStrct), 0);
  CDROMDISK_IOCtl(DevHndl, CDROMDISK_GETHEADLOC,
                           CmdStrct, SizeOf(CmdStrct),
                           ParmStrct, SizeOf(ParmStrct));
  MSF := ParmStrct.HeadLocation;
End;

Procedure CDReadLong(DevHndl : HFile; StartSector : LongInt; Var Buf : tReadBlock);
Var CmdStrct : tCommandStrct;
Begin
  CmdStrct.Signature := CD_Signature;
  CmdStrct.ReadAddrMode := $00;    // Logical-Block Format
  CmdStrct.NrOfSectors  := 1;
  CmdStrct.StartSector  := StartSector;
  CmdStrct.Reserved     := #$00;
  CmdStrct.Interleave   := $00;
  FillChar(Buf, SizeOf(Buf), 0);
  CDROMDISK_IOCtl(DevHndl, CDROMDISK_READLONG,
                           CmdStrct, SizeOf(CmdStrct),
                           Buf, SizeOf(Buf));
End;

Function  CDGetVolumeSize(DevHndl : HFile) : LongInt;
Var CmdStrct : tCommandStrct;
    ParmStrct: tRtnDataStrct;
Begin
  CmdStrct.Signature := CD_Signature;
  FillChar(ParmStrct, SizeOf(ParmStrct), 0);
  CDROMDISK_IOCtl(DevHndl, CDROMDISK_GETVOLUMESIZE,
                           CmdStrct, SizeOf(CmdStrct),
                           ParmStrct, SizeOf(ParmStrct));
  Result := ParmStrct.VolumeSize;
End;

Procedure CDGetUPC(DevHndl : HFile; Var UPC : tUPCStruct);
Var CmdStrct : tCommandStrct;
Begin
  CmdStrct.Signature := CD_Signature;
  FillChar(UPC, SizeOf(UPC), 0);
  CDROMDISK_IOCtl(DevHndl, CDROMDISK_GETUPC,
                           CmdStrct, SizeOf(CmdStrct),
                           UPC, SizeOf(UPC));
End;

Function  CDSignature : String;
Begin
  Result := CD_Signature;
End;

{----------------------------------------------------------------------}
{ CDROM-Audio Functions                                                }
{----------------------------------------------------------------------}
Procedure CDSetChannelCtrl(DevHndl : HFile; Data : tChannelCtrl);
Var CmdStrct : tCommandStrct;
    ParmStrct: tRtnDataStrct;
Begin
  CmdStrct.Signature  := CD_Signature;
  ParmStrct.InputCnl0 := Data.InpCnl[0];
  ParmStrct.VolumeCnl0:= Data.Volume[0];
  ParmStrct.InputCnl1 := Data.InpCnl[1];
  ParmStrct.VolumeCnl1:= Data.Volume[1];
  ParmStrct.InputCnl2 := Data.InpCnl[2];
  ParmStrct.VolumeCnl2:= Data.Volume[2];
  ParmStrct.InputCnl3 := Data.InpCnl[3];
  ParmStrct.VolumeCnl3:= Data.Volume[3];
  CDROMAUDIO_IOCtl(DevHndl, CDROMAUDIO_SETCHANNELCTRL,
                            CmdStrct, SizeOf(CmdStrct),
                            ParmStrct, SizeOf(ParmStrct));
End;

Procedure CDPlayTrackMSF(DevHndl : HFile; StartTrack, StopTrack : LongInt);
Var CmdStrct : tCommandStrct;
    ParmStrct: tRtnDataStrct;
Begin
  CmdStrct.Signature  := CD_Signature;
  CmdStrct.PlayAddrMode := $01;    // Minute/Second/Frame Format
  CmdStrct.PlayStartSect:= StartTrack;
  CmdStrct.PlayStopSect := StopTrack;
  FillChar(ParmStrct, SizeOf(ParmStrct), 0);
  CDROMAUDIO_IOCtl(DevHndl, CDROMAUDIO_PLAYAUDIO,
                            CmdStrct, SizeOf(CmdStrct),
                            ParmStrct, SizeOf(ParmStrct));
End;

Procedure CDPlayTrackLBF(DevHndl : HFile; StartTrack, StopTrack : LongInt);
Var CmdStrct : tCommandStrct;
    ParmStrct: tRtnDataStrct;
Begin
  CmdStrct.Signature  := CD_Signature;
  CmdStrct.PlayAddrMode := $00;    // Logical-Block Format
  CmdStrct.PlayStartSect:= StartTrack;
  CmdStrct.PlayStopSect := StopTrack;
  FillChar(ParmStrct, SizeOf(ParmStrct), 0);
  CDROMAUDIO_IOCtl(DevHndl, CDROMAUDIO_PLAYAUDIO,
                            CmdStrct, SizeOf(CmdStrct),
                            ParmStrct, SizeOf(ParmStrct));
End;

Procedure CDStopAudio(DevHndl : HFile);
Var CmdStrct : tCommandStrct;
    ParmStrct: tRtnDataStrct;
Begin
  CmdStrct.Signature  := CD_Signature;
  FillChar(ParmStrct, SizeOf(ParmStrct), 0);
  CDROMAUDIO_IOCtl(DevHndl, CDROMAUDIO_STOPAUDIO,
                            CmdStrct, SizeOf(CmdStrct),
                            ParmStrct, SizeOf(ParmStrct));
End;

Procedure CDResumeAudio(DevHndl : HFile);
Var CmdStrct : tCommandStrct;
    ParmStrct: tRtnDataStrct;
Begin
  CmdStrct.Signature  := CD_Signature;
  FillChar(ParmStrct, SizeOf(ParmStrct), 0);
  CDROMAUDIO_IOCtl(DevHndl, CDROMAUDIO_RESUMEAUDIO,
                            CmdStrct, SizeOf(CmdStrct),
                            ParmStrct, SizeOf(ParmStrct));
End;

Procedure CDGetChannelCtrl(DevHndl : HFile; Var Data : tChannelCtrl);
Var CmdStrct : tCommandStrct;
    ParmStrct: tRtnDataStrct;
Begin
  CmdStrct.Signature  := CD_Signature;
  FillChar(ParmStrct, SizeOf(ParmStrct), 0);
  CDROMAUDIO_IOCtl(DevHndl, CDROMAUDIO_GETCHANNEL,
                            CmdStrct, SizeOf(CmdStrct),
                            ParmStrct, SizeOf(ParmStrct));
  If IOCtlResult = NO_ERROR Then
    Begin
      Data.InpCnl[0] := ParmStrct.InputCnl0;
      Data.Volume[0] := ParmStrct.VolumeCnl0;
      Data.InpCnl[1] := ParmStrct.InputCnl1;
      Data.Volume[1] := ParmStrct.VolumeCnl1;
      Data.InpCnl[2] := ParmStrct.InputCnl2;
      Data.Volume[2] := ParmStrct.VolumeCnl2;
      Data.InpCnl[3] := ParmStrct.InputCnl3;
      Data.Volume[3] := ParmStrct.VolumeCnl3;
    End;
End;

Procedure CDGetAudioDisk(DevHndl : HFile; Var Data : tAudioDiskInfo);
Var CmdStrct : tCommandStrct;
Begin
  CmdStrct.Signature  := CD_Signature;
  FillChar(Data, SizeOf(Data), 0);
  CDROMAUDIO_IOCtl(DevHndl, CDROMAUDIO_GETAUDIODISK,
                            CmdStrct, SizeOf(CmdStrct),
                            Data, SizeOf(Data));
End;

Procedure CDGetAudioTrack(DevHndl : HFile; TrackNr : Byte; Var Data : tAudioTrackInfo);
Var CmdStrct : tCommandStrct;
Begin
  CmdStrct.Signature  := CD_Signature;
  CmdStrct.TrackNbr   := TrackNr;
  FillChar(Data, SizeOf(Data), 0);
  CDROMAUDIO_IOCtl(DevHndl, CDROMAUDIO_GETAUDIOTRACK,
                            CmdStrct, SizeOf(CmdStrct),
                            Data, SizeOf(Data));
End;

Procedure CDGetSubChannelQ(DevHndl : HFile; Var Data : tSubCnlInfo);
Var CmdStrct : tCommandStrct;
Begin
  CmdStrct.Signature  := CD_Signature;
  FillChar(Data, SizeOf(Data), 0);
  CDROMAUDIO_IOCtl(DevHndl, CDROMAUDIO_GETSUBCHANNELQ,
                            CmdStrct, SizeOf(CmdStrct),
                            Data, SizeOf(Data));
  If IOCtlResult = NO_ERROR Then
    Begin
      // Convert from BCD to binary format
      Data.TrackNr := (Data.TrackNr And $0F) + (Data.TrackNr Shr 4) * 10;
      Data.Index   := (Data.Index   And $0F) + (Data.Index   Shr 4) * 10;
    End;
End;

Procedure CDGetAudioStatus(DevHndl : HFile; Var Data : tAudioStatus);
Var CmdStrct : tCommandStrct;
Begin
  CmdStrct.Signature  := CD_Signature;
  FillChar(Data, SizeOf(Data), 0);
  CDROMAUDIO_IOCtl(DevHndl, CDROMAUDIO_GETAUDIOSTATUS,
                            CmdStrct, SizeOf(CmdStrct),
                            Data, SizeOf(Data));
End;

End.

