322 lines
8.1 KiB
ObjectPascal

(*
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 <grelle@online.de> 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.