(*--------------------------------------------------------------------*)
(*                                                                    *)
(* Module . . . . . . .  CDAUDIO                                      *)
(* Source file  . . . .  CDAUDIO.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  . . . . .  -                                            *)
(*                                                                    *)
(*--------------------------------------------------------------------*)
(*                                                                    *)
(* Description                                                        *)
(* -----------                                                        *)
(*                                                                    *)
(* Advanced procedures and function to access a CD-ROM drive as an    *)
(* audio CD-Player.                                                   *)
(*                                                                    *)
(*--------------------------------------------------------------------*)
Unit CdAudio;
Interface
(*--------------------------------------------------------------------*)
(* Interface                                                          *)
(*--------------------------------------------------------------------*)
Uses
  Os2Def, Os2Base, Classes,
  CdBase;

Const
  cDefaultDrive = #0;

Type
  tAudioTrack = Record
    TrackNr         : Byte;
    StartAddr       : LongInt;
    EndAddr         : LongInt;
    TITwoChannel    : Boolean;        // True = Stereo;                 False = Mono
    TIAudioTrack    : Boolean;        // True = Audio;                  False = Data
    TICopyProhibited: Boolean;        // True = Prohibited;             False = Copy permitted
    TIPreemphasis   : Boolean;        // True = Audio with preemphasis; False = Audio without preemph.
    TIADR_Data      : Byte;           // ADR-Data
  End;
  tAudioTrackArray = Array[1..255] Of tAudioTrack;
  pAudioTrackArray = ^tAudioTrackArray;

Type
  tCDPlayer = Class(TComponent)
    Private
      DevHndl       : HFile;
      DskFirstTrack : LongInt;
      DskLastTrack  : LongInt;
      DskLeadOutAddr: LongInt;
      NrOfTracks    : Byte;
      Tracks        : pAudioTrackArray;
    Protected
      Function OpenCdRom(Drive : Char) : Boolean;
      Function IsDiskInDrive : Boolean;
      Function IsPlaying : Boolean;
      Procedure ReloadDiskInfo;
    Public
      Constructor Create(AOwner : TComponent);
      Destructor  Destroy; Override;
      Procedure   OpenPlayer(Drive : Char);
      Procedure   Play(TNr : Byte);
      Procedure   Stop;
      Procedure   Resume;
      Procedure   CurrentPos(Var Track, Minute, Second : Byte);
    Property Handle      : HFile    Read DevHndl;
    Property DiskInDrive : Boolean  Read IsDiskInDrive;
    Property Playing     : Boolean  Read IsPlaying;
    Property FirstTrack  : LongInt  Read DskFirstTrack;
    Property LastTrack   : LongInt  Read DskLastTrack;
    Property LeadOutAddr : LongInt  Read DskLeadOutAddr;
  End;

(*--------------------------------------------------------------------*)
(* Implementation                                                     *)
(*--------------------------------------------------------------------*)
Implementation

Type
  tMSFData = Record
    Case Byte Of
      1 : (Frame   : Byte;
           Second  : Byte;
           Minute  : Byte;
           Reserved: Byte);
      2 : (TrackAddr : LongInt);
  End;

{----------------------------------------------------------------------}
{ Basic Device Functions                                               }
{----------------------------------------------------------------------}
Function tCDPlayer.OpenCDRom(Drive : Char) : Boolean;
Var Status : LongInt;
Begin
  Result := False;   // A little pessimistic but useful

  DevHndl := OpenDevice(Drive, False);
  If IoCtlResult <> NO_ERROR Then Exit;

  If CDGetDriver(DevHndl) <> CDSignature Then
    Begin
      CloseDevice(DevHndl);
      Exit;
    End;

  Status := CDGetDiskStatus(DevHndl);
  If IoCtlResult <> NO_ERROR Then
    Begin
      CloseDevice(DevHndl);
      Exit;
    End;

  If (Status And AUDIO_DEVICE) = 0 Then
    Begin
      CloseDevice(DevHndl);
      Exit;
    End;

  Result := True;
End;

Function tCDPlayer.IsDiskInDrive : Boolean;
Var Status : LongInt;
Begin
  Result := False;
  Status := CDGetDiskStatus(DevHndl);
  If IoCtlResult <> NO_ERROR Then Exit;
  If (Status And NO_DISK_PRESENT) = NO_DISK_PRESENT Then Exit;
  Result := True;
End;

Function tCDPlayer.IsPlaying : Boolean;
Var Status : LongInt;
Begin
  Result := False;
  Status := CDGetDiskStatus(DevHndl);
  If IoCtlResult <> NO_ERROR Then Exit;
  If (Status And PLAYING_AUDIO) = 0 Then Exit;
  Result := True;
End;

Procedure tCDPlayer.ReloadDiskInfo;
Var Disk : tAudioDiskInfo;
    TNr  : Byte;
    Idx  : Integer;
    Trck : TAudioTrackInfo;
Begin
  CDGetAudioDisk(DevHndl, Disk);
  If IoCtlResult = NO_ERROR Then
    Begin
      DskFirstTrack := Disk.FirstTrack;
      DskLastTrack  := Disk.LastTrack;
      DskLeadOutAddr:= Disk.LeadOutAddr;
      NrOfTracks := (Disk.LastTrack-Disk.FirstTrack)+1;
      GetMem(Tracks,NrOfTracks*SizeOf(tAudioTrack));
      Idx := 1;
      For TNr:=Disk.FirstTrack To Disk.LastTrack Do
        Begin
          CDGetAudioTrack(Handle, TNr, Trck);
          With Tracks^[Idx] Do
            Begin
              If Idx > 1 Then Tracks^[Idx-1].EndAddr := Trck.TrackAddr;
              StartAddr := Trck.TrackAddr;
              TITwoChannel     := (Trck.TrackCtrl And $80) = 0;
              TIAudioTrack     := (Trck.TrackCtrl And $40) = 0;
              TICopyProhibited := (Trck.TrackCtrl And $20) = 0;
              TIPreemphasis    := (Trck.TrackCtrl And $10) = 0;
              TIADR_Data       := (Trck.TrackCtrl And $0F);
            End;
          Inc(Idx);
        End;
      Tracks^[Idx-1].EndAddr := LeadOutAddr;
    End;
End;

{----------------------------------------------------------------------}
{ Public Functions                                                     }
{----------------------------------------------------------------------}
Constructor tCDPlayer.Create(AOwner : TComponent);
Begin
  Inherited Create(AOwner);
  DevHndl := $FFFFFFFF;
  DskFirstTrack := 0;
  DskLastTrack  := 0;
  DskLeadOutAddr:= 0;
  Tracks := Nil;
  NrOfTracks := 0;
End;

Procedure tCDPlayer.OpenPlayer(Drive : Char);
Var C : Char;
    Found : Boolean;
Begin
  If Drive = cDefaultDrive Then
    Begin
      c := 'C';
      Found := False;
      While (c <= 'Z') And Not Found Do
        Begin
          If OpenCDRom(C)
            Then Found := True
            Else Inc(C);
        End;
    End
  Else
    Begin
      Found := OpenCDRom(Drive);
    End;

  If Not Found Then
    Begin
      // No CD drive found: Do something like raise an
      // exception ...
      Exit;
    End;

  If DiskInDrive Then ReloadDiskInfo;
End;

Procedure tCDPlayer.Play(TNr : Byte);
Begin
  CDPlayTrackMSF(Handle, Tracks^[TNr].StartAddr, Tracks^[TNr].EndAddr);
End;

Procedure TCDPlayer.Stop;
Begin
  If Playing Then CDStopAudio(DevHndl);
End;

Procedure TCDPlayer.Resume;
Begin
  CDResumeAudio(DevHndl);
End;

Procedure TCDPlayer.CurrentPos(Var Track, Minute, Second : Byte);
Var D : TSubCnlInfo;
Begin
  CDGetSubChannelQ(DevHndl, D);
  Track  := D.TrackNr;
  Minute := D.RunTrckMin;
  Second := D.RunTrckSec;
End;

Destructor tCDPlayer.Destroy;
Begin
  If DevHndl <> $FFFFFFFF Then
    Begin
      Stop;
      CloseDevice(DevHndl);
    End;
  If Assigned(Tracks) Then FreeMem(Tracks,NrOfTracks*SizeOf(tAudioTrack));
  Inherited Destroy;
End;

End.

