(* this file is a part of audio components suite see the license file for more details. you can contact me at mail@z0m3ie.de Special thanks to Thomas Grelle for improving this unit. $Log: acs_cdrom.pas,v $ Revision 1.11 2006/08/31 20:10:54 z0m3ie *** empty log message *** Revision 1.10 2006/07/04 17:12:45 z0m3ie ACS 2.4 alt wiederhergestellt (unterschiedliche Sampleformate ...) Revision 1.2 2005/12/26 17:31:38 z0m3ie fixed some problems in acs_dsfiles fixed some problems in acs_vorbis reworked all buffers Revision 1.1 2005/12/19 18:34:35 z0m3ie *** empty log message *** Revision 1.7 2005/12/18 17:01:54 z0m3ie delphi compatibility Revision 1.6 2005/12/04 16:54:33 z0m3ie All classes are renamed, Style TACS... than T... to avoid conflicts with other components (eg TMixer is TACSMixer now) Revision 1.5 2005/11/28 21:57:24 z0m3ie mostly FileOut fixes moved PBuffer to PBuffer8 set all to dynamically Buffering Revision 1.4 2005/10/02 16:51:46 z0m3ie *** empty log message *** Revision 1.3 2005/09/15 20:59:38 z0m3ie start translate the documentation in the source for pasdoc Revision 1.2 2005/09/13 21:54:11 z0m3ie acs is localizeable now (ACS_Strings) Revision 1.1 2005/09/12 22:04:52 z0m3ie modified structure again, fileformats are now in an sperat folder. all File In/Out classes are capsulated from TFileIn and TFileOut Revision 1.6 2005/09/09 21:33:42 z0m3ie linux corrections Revision 1.5 2005/09/08 22:18:59 z0m3ie completed akrip based CDIn Revision 1.4 2005/09/07 20:53:22 z0m3ie begon to add MPEG and WMA support using DirectX Revision 1.3 2005/09/04 17:59:37 z0m3ie moving CDIn support to AKRip mostly begon to add mpegin support for Win with mpg123 Revision 1.2 2005/08/28 20:31:17 z0m3ie linux restructuring for 2.4 Revision 1.1 2005/08/25 20:18:00 z0m3ie Version 2.4 restructure TCDPlayer removed (fits not in component structure) TMP3ToWavConverter removed (fits not in component structure) Revision 1.5 2005/08/22 20:17:02 z0m3ie changed Headers to log changed mail adress *) { @abstract(this unit introduces the base classes for acs) @author(Andrei Borovsky (2003-2005)) @author(Christian Ulrich (2005)) } unit acs_cdrom; {$ifdef fpc} {$mode delphi} {$endif} interface uses Classes, SysUtils, ACS_Classes,ACS_Strings,ACS_Types {$IFDEF MSWINDOWS} ,Windows, MMSystem, akrip32 {$ELSE} ,baseunix,cd_rom {$ENDIF} ; type {$IFDEF MSWINDOWS} {$IFDEF FPC} TAuxCaps = AUXCAPS; {$ENDIF} {$ENDIF} TACSCDStatus = (cdsNotReady, cdsReady, cdsPlaying, cdsPaused); TACSTrackType = (ttAudio, ttData); TACSCDInfo = (cdiNoDisc, cdiDiscAudio, cdiDiscData, cdiDiscMixed, cdiUnknown); TACSMCN = array[0..13] of Char; TACSCDMSF = record Minute : Byte; Second : Byte; Frame : Byte; end; PACSCDMSF = ^TACSCDMSF; TACSCDTrackInfo = record TrackStart: TACSCDMSF; TrackLength : TACSCDMSF; TrackType : TACSTrackType; end; TACSCDPosition = record Track : Integer; MSF : TACSCDMSF; end; const EndOfDisc : TACSCDPosition = (Track : 100; MSF : (Minute : 0; Second : 0; Frame : 0)); CD_FRAMESIZE_RAW = 2352; BUF_SIZE = 50; // 75 frames - 1 sec var AppPath : String; WinPath : String; type { This is the cdreader component of acs it reads in windows with aspi and linux direct from device } TACSCDIn = class(TACSCustomInput) private FBuffer : array of byte; FCurrentDrive : Integer; FStartTrack, FEndTrack : Integer; FStartPos, FEndPos: TACSCDPosition; FRipEnd : Integer; FCDDBId: Longint; {$IFDEF LINUX} FOpened : Integer; FCurPos,FEndMSF : TACSCDMSF; FDrivesCount : Integer; _cd_fd : Integer; BufSize : Integer; {$ELSE} FToc: TOC; FCDList: CDLIST; FCDHandle : HCDROM; FPlaying : Boolean; FRipStart : LongInt; FiBuffer : PTRACKBUF; {$ENDIF} procedure OpenCD; procedure CloseCD; function GetStatus : TACSCDStatus; function GetNumTracks : Integer; function GetTrackInfo(const vIndex : Integer) : TACSCDTrackInfo; procedure SetST(Track : Integer); procedure SetET(Track : Integer); procedure SetSP(Pos : TACSCDPosition); procedure SetEP(Pos : TACSCDPosition); function GetSize : Integer; function GetInfo : TACSCDInfo; function GetDrivesCount : Integer; procedure SetCurrentDrive(Value : Integer); function GetDriveName : String; function GetCDDBID : LongInt; function GetTotalTime : real; override; protected function GetBPS : Integer; override; function GetCh : Integer; override; function GetSR : Integer; override; public constructor Create(AOwner: TComponent); override; destructor Destroy; override; function GetData(Buffer : Pointer; BufferSize : Integer): Integer; override; procedure Init; override; procedure Flush; override; procedure Eject; procedure CloseTray; property DiscInfo: TACSCDInfo read GetInfo; property Status: TACSCDStatus read GetStatus; property Tracks[const vIndex : Integer] : TACSCDTrackInfo read GetTrackInfo; property TracksCount : Integer read GetNumTracks; property DriveName : String read GetDriveName; property DrivesCount : Integer read GetDrivesCount; property StartPos : TACSCDPosition read FStartPos write SetSP; property EndPos : TACSCDPosition read FEndPos write SetEP; property CDDBId : LongInt read GetCDDBID; published property CurrentDrive : Integer read FCurrentDrive write SetCurrentDrive; property StartTrack: Integer read FStartTrack write SetSt; property EndTrack: Integer read FEndTrack write SetET; end; function MSFToStr(const MSF : TACSCDMSF) : String; procedure Frames2MSF(Frames : Integer; var MSF : TACSCDMSF); function MSF2Frames(const MSF : TACSCDMSF) : Integer; {$IFDEF LINUX} var DrivesCount : Integer; DrivesPaths : array of string; procedure CountDrives; {$ENDIF} implementation {$I ACS_CDROM.inc} function MSFToStr(const MSF : TACSCDMSF) : String; var sep : String; sec, min : Integer; begin min := MSF.Minute; if MSF.Frame > 37 then begin sec := MSF.Second + 1; if sec = 60 then begin Inc(min); sec := 0; end; end else sec := MSF.Second; if sec<10 then sep := ':0' else sep := ':'; Result := IntToStr(min) + sep + IntToStr(sec); end; procedure Frames2MSF(Frames : Integer; var MSF : TACSCDMSF); var Temp : Integer; begin Temp := Frames div 75; MSF.Minute := Temp div 60; MSF.Second := Temp mod 60; MSF.Frame := Frames mod 75; end; function MSF2Frames(const MSF : TACSCDMSF) : Integer; begin Result := ((MSF.Minute * 60) + MSF.Second) * 75 + MSF.Frame; end; function TACSCDIn.GetBPS : Integer; begin Result := 16; end; function TACSCDIn.GetCh : Integer; begin Result := 2; end; function TACSCDIn.GetSR : Integer; begin Result := 44100; end; function TACSCDIn.GetTotalTime : real; begin if (SampleRate = 0) or (Channels = 0) or (BitsPerSample = 0) then Exit; Result := Size/(SampleRate*Channels*(BitsPerSample shr 3)); end; function TACSCDIn.GetCDDBID: LongInt; FUNCTION prg_sum(n: integer): integer; VAR buf: STRING; ib: Integer; BEGIN buf := IntToStr(n); Result := 0; FOR ib := 1 TO Length(buf) DO Result := Result + (StrToInt(Copy(Buf, ib, 1))); END; VAR i, N, L: Longint; CDM: TACSCDMSF; BEGIN N := 0; L := 0; FOR i := 0 TO GetNumTracks-1 DO BEGIN WITH Tracks[i].TrackStart DO BEGIN N := N + prg_sum((minute * 60) + second + 2); L := L + MSF2Frames(Tracks[i].TrackLength); // adjust the length of last audio track if a data track is following IF (i > 0) AND (i = TracksCount - 2) AND (Tracks[i + 1].TrackType = ttData) THEN inc(L, 152 * 75); END; END; Frames2MSF(L, CDM); L := CDM.Minute * 60 + CDM.Second; Result := ((N MOD $0FF) SHL 24) XOR (L SHL 8) XOR TracksCount; FCDDBId := Result; end; {$IFDEF LINUX} initialization CountDrives; {$ENDIF} end.