{
$Log: acs_cdrom.inc,v $
Revision 1.7  2006/08/31 20:10:56  z0m3ie
*** empty log message ***

Revision 1.6  2006/07/04 17:12:45  z0m3ie
ACS 2.4 alt wiederhergestellt (unterschiedliche Sampleformate ...)

Revision 1.2  2005/12/26 17:31:39  z0m3ie
fixed some problems in acs_dsfiles
fixed some problems in acs_vorbis
reworked all buffers

}

  function GetTocEntry(cd_fd, Track : Integer): TACSCDTrackInfo;
  var
    Entry : cdrom_tocentry;
    toc : cdrom_tochdr;
    frames1, frames2 : Integer;
  begin
    ioctl(cd_fd, CDROMREADTOCHDR, @toc);
    Entry.cdte_format := CDROM_MSF;
    Entry.cdte_track := Track+toc.cdth_trk0-1;
    ioctl(cd_fd, CDROMREADTOCENTRY, @Entry);
    frames1 := MSF2Frames(TACSCDMSF(Entry.cdte_addr.msf));
    if (Entry.cdte_adr_ctrl and CDROM_DATA_TRACK) <> 0 then
    Result.TrackType := ttData
    else Result.TrackType := ttAudio;
    if Entry.cdte_track < toc.cdth_trk1 then Inc(Entry.cdte_track)
    else Entry.cdte_track := CDROM_LEADOUT;
    ioctl(cd_fd, CDROMREADTOCENTRY, @Entry);
    frames2 := MSF2Frames(TACSCDMSF(Entry.cdte_addr.msf));
    Frames2MSF(frames2-frames1, Result.TrackLength);
  end;

  function GetCDStatus(cd_fd : Integer) : TACSCDStatus;
  (* not all drivers support the CDROM_DRIVE_STATUS ioctl
   we use this ioctl first and then some other tecnique
   if it is not supported. *)
  var
    sci : cdrom_subchnl;
    res :Integer;
  begin
    res := ioctl(cd_fd, CDROM_DRIVE_STATUS, CDSL_CURRENT);
    case res of
      CDS_TRAY_OPEN, CDS_NO_DISC, CDS_DRIVE_NOT_READY:
      begin
        Result := cdsNotReady;
        Exit;
      end;
    end;
    (* Either the disc is ok or no information
     from the driver. Trying CDROMSUBCHNL.*)
    sci.cdsc_format := CDROM_MSF;
    if ioctl(cd_fd, CDROMSUBCHNL, @sci) < 0 then
    begin
      Result := cdsNotReady;
      Exit;
    end;
    case sci.cdsc_audiostatus of
      CDROM_AUDIO_PLAY : Result := cdsPlaying;
      CDROM_AUDIO_PAUSED : Result := cdsPaused;
      CDROM_AUDIO_ERROR  : Result := cdsNotReady;
      else Result := cdsReady;
    end;
  end;

  function GetCDInfo(cd_fd : Integer) : TACSCDInfo;
  var
    res : Integer;
  begin
    Result := cdiUnknown;
    res := ioctl(cd_fd, CDROM_DRIVE_STATUS, CDSL_CURRENT);
    case res of
      CDS_TRAY_OPEN, CDS_NO_DISC: Result := cdiNoDisc;
      CDS_DISC_OK :
      begin
        res := ioctl(cd_fd, CDROM_DISC_STATUS, CDSL_CURRENT);
        case res of
          CDS_AUDIO : Result := cdiDiscAudio;
          CDS_MIXED : Result := cdiDiscMixed;
          else Result :=  cdiDiscData;
        end;
      end;
    end;
  end;

  procedure TACSCDIn.OpenCD;
  begin
    if FCurrentDrive >= length(DrivesPaths) then
      exit;
    if FOpened = 0 then
    begin
      _cd_fd := open(PChar(DrivesPaths[FCurrentDrive]), O_RDONLY or O_NONBLOCK);
      if _cd_fd < 0 then
      raise EACSException.Create(strerror(errno));
    end;
    Inc(FOpened);
  end;


  procedure TACSCDIn.CloseCD;
  begin
    if FOpened = 1 then __close(_cd_fd);
    if FOpened > 0 then Dec(FOpened);
  end;

  function TACSCDIn.GetInfo;
  begin
    if Busy then raise EACSException.Create(strBusy);
    OpenCD;
    Result := GetCDInfo(_cd_fd);
    CloseCD;
  end;

  function TACSCDIn.GetStatus;
  begin
    if FCurrentDrive >= length(DrivesPaths) then
      exit;
    if Busy then raise EACSException.Create(strBusy);
    if Fopened = 0 then
    _cd_fd := open(PChar(DrivesPaths[FCurrentDrive]), O_RDONLY or O_NONBLOCK);
    if _cd_fd < 0 then
    begin
      Result := cdsNotReady;
      Exit;
    end;
    Inc(FOpened);
    Result := GetCDStatus(_cd_fd);
    CloseCD;
  end;

  function TACSCDIn.GetNumTracks;
  var
    toc : cdrom_tochdr;
  begin
    if Busy then raise EACSException.Create(strBusy);
    OpenCD;
    if GetStatus <> cdsNotReady then
    begin
      ioctl(_cd_fd, CDROMREADTOCHDR, @toc);
      Result := toc.cdth_trk1 - toc.cdth_trk0 + 1;
    end else Result := 0;
    CloseCD;
  end;

  function TACSCDIn.GetTrackInfo;
  begin
    if Busy then raise EACSException.Create(strBusy);
    OpenCD;
    if (vIndex in [1..GetNumTracks]) = False then
    begin
      __close(_cd_fd);
      FOpened := 0;
      raise EACSException.Create(strTrackOutofRange);
    end;
    Result := GetTocEntry(_cd_fd, vIndex);
    CloseCD;
  end;

  function GetTrackMSF(cd_fd, Track : Integer) : TACSCDMSF;
  var
    entry : cdrom_tocentry;
    hdr : cdrom_tochdr;
  begin
    ioctl(cd_fd, CDROMREADTOCHDR, @hdr);
    entry.cdte_format := CDROM_MSF;
    entry.cdte_track := Track + hdr.cdth_trk0 - 1;
    if entry.cdte_track > hdr.cdth_trk1 then
    entry.cdte_track := CDROM_LEADOUT;
    ioctl(cd_fd, CDROMREADTOCENTRY, @entry);
    Result := TACSCDMSF(entry.cdte_addr.msf);
  end;

  function GetPosMSF(cd_fd : Integer; Pos : TACSCDPosition) : TACSCDMSF;
  var
    msf1 : TACSCDMSF;
    frames : Integer;
  begin
    msf1 := TACSCDMSF(GetTrackMSF(cd_fd, Pos.Track));
    frames := MSF2Frames(msf1);
    frames := frames + MSF2Frames(Pos.MSF);
    Frames2MSF(frames, msf1);
    Result := msf1;
  end;

  procedure TACSCDIn.SetST;
  begin
    if Self.Busy then raise EACSException.Create(strBusy);
    FStartTrack := Track;
    FStartPos.Track := FStartTrack;
    FillChar(FStartPos.MSF, SizeOf(FStartPos.MSF), 0);
  end;

  procedure TACSCDIn.SetET;
  begin
    if Self.Busy then raise EACSException.Create(strBusy);
    FEndTrack := Track;
    OpenCD;
    FEndPos.Track := FEndTrack + 1;
    FillChar(FEndPos.MSF, SizeOf(FEndPos.MSF), 0);
    CloseCD;
  end;

  procedure TACSCDIn.SetSP;
  begin
    if Self.Busy then raise EACSException.Create(strBusy);
    Self.FStartPos := Pos;
  end;

  procedure TACSCDIn.SetEP;
  begin
    if Self.Busy then raise EACSException.Create(strBusy);
    Self.FEndPos := Pos;
  end;

  constructor TACSCDIn.Create;
  begin
    inherited Create(AOwner);
    FCurrentDrive := 0;
  end;

  function TACSCDIn.GetSize;
  var
    msf1, msf2 : TACSCDMSF;
  begin
    if Busy then raise EACSException.Create(strBusy);
    OpenCD;
    msf1 := GetPosMSF(_cd_fd, FStartPos);
    msf2 := GetPosMSF(_cd_fd, FEndPos);
    CloseCD;
    Result := ((msf2.minute*60 + msf2.second)*75 + msf2.frame -
      ((msf1.minute*60 + msf1.second)*75 + msf1.frame))*CD_FRAMESIZE_RAW;
  end;

  procedure TACSCDIn.Init;
  begin
    if Busy then raise EACSException.Create(strBusy);
    if not (DiscInfo in [cdiDiscAudio, cdiDiscMixed]) then
    raise EACSException.Create(strNoAudioCD);
    FSize := GetSize;
    FBusy := True;
    BufStart := 1;
    BufEnd := 0;
    FPosition := 0;
    OpenCD;
    FCurPos := GetPosMSF(_cd_fd, FStartPos);
    FEndMSF := GetPosMSF(_cd_fd, FEndPos);
//    GetMem(FBuffer,BUF_SIZE * CD_FRAMESIZE_RAW);
  end;

  procedure TACSCDIn.Flush;
  begin
    CloseCD;
    FBusy := False;
//    FreeMem(FBuffer);
    FSize := 0;
  end;

  function TACSCDIn.GetData;
  var
    StartFrame, EndFrame : Integer;
    cdaudio : cdrom_read_audio;
  begin
    if not Busy then  raise EACSException.Create(strStreamnotopen);
    StartFrame := MSF2Frames(FCurPos);
    EndFrame := MSF2Frames(FEndMSF);
    if BufStart > BufEnd then
    begin
      if EndFrame = StartFrame then
      begin
        Result := 0;
        Exit;
      end;
      BufStart := 1;
      if (EndFrame - StartFrame) > (BUF_SIZE) then
        cdaudio.nframes := BUF_SIZE
      else
        cdaudio.nframes := EndFrame - StartFrame;
      cdaudio.addr_format := CDROM_MSF;
      cdaudio.addr.msf := cdrom_msf0(FCurPos);
      cdaudio.buf := Pointer(FBuffer);
      ioctl(_cd_fd, CDROMREADAUDIO, @cdaudio);
      BufEnd := cdaudio.nframes * CD_FRAMESIZE_RAW;
      StartFrame := MSF2Frames(FCurPos) + cdaudio.nframes;
      Frames2MSF(StartFrame, FCurPos);
    end;
    if BufferSize < (BufEnd - BufStart + 1)
    then Result := BufferSize
    else Result := BufEnd - BufStart + 1;
    Move(FBuffer[BufStart], Buffer^, Result);
    Inc(BufStart, Result);
    Inc(FPosition, Result);
  end;

  procedure TACSCDIn.Eject;
  begin
    if Busy then raise EACSException.Create(strBusy);
    OpenCD;
    ioctl(_cd_fd, CDROMEJECT);
    CloseCD;
  end;

  procedure TACSCDIn.CloseTray;
  begin
    OpenCD;
    ioctl(_cd_fd, CDROMCLOSETRAY);
    CloseCD;
  end;
  
  procedure CountDrives;
  var
    _cd_fd, i : Integer;
    fname : String;
    sci : cdrom_subchnl;
    res :Integer;
  begin
    DrivesCount := 0;
    for i := 0 to 3 do
    begin
      fname := '/dev/hd'+chr(ord('a')+i);
      _cd_fd := open(PChar(fname), O_RDONLY or O_NONBLOCK);
      if _cd_fd >= 0 then
        begin
          res := ioctl(_cd_fd, CDROM_DRIVE_STATUS, CDSL_CURRENT);
          case res of
          CDS_TRAY_OPEN, CDS_NO_DISC, CDS_DRIVE_NOT_READY:
             begin
               inc(DrivesCount);
               setlength(DrivesPaths,DrivesCount);
               DrivesPaths[DrivesCount-1] := fname;
               __close(_cd_fd);
               continue;
             end;
          end;
          (* Either the disc is ok or no information
          from the driver. Trying CDROMSUBCHNL.*)
          sci.cdsc_format := CDROM_MSF;
          if ioctl(_cd_fd, CDROMSUBCHNL, @sci) >= 0 then
            begin
               inc(DrivesCount);
               setlength(DrivesPaths,DrivesCount);
               DrivesPaths[DrivesCount-1] := fname;
            end;
          __close(_cd_fd);
        end;
    end;
  end;
  
  function TACSCDIn.GetDrivesCount : Integer;
  begin
    Result := DrivesCount;
  end;
  
  procedure TACSCDIn.SetCurrentDrive(Value : Integer);
  begin
    if Busy then raise EACSException.Create(strBusy);
    FCurrentDrive := Value;
  end;
  
  function TACSCDIn.GetDriveName : String;
  begin
    Result := '';
  end;

  destructor TACSCDIn.Destroy;
  begin
    inherited Destroy;
  end;


