Registriert seit: 31. Aug 2005
1.622 Beiträge
FreePascal / Lazarus
|
Audio CD Rippen
2. Jan 2010, 23:41
Audio CD Rippen
Windows bietet keine Möglichkeit um über ReadFile Daten von einem als Volume geöffneten optischen Laufwerk zu lesen. Folgender Code demonstriert das Auslesen von Audio CDs über die entsprechende Schnittstelle der DeviceIOControl Funktion (IOCTL_CDROM_RAW_READ).
Die Daten werden in eine RAW-Datei geschrieben, könnten aber z.B. direkt wiedergegeben werden, andersweitig codiert oder mit entsprechendem WAVE-Header versehen direkt als WAVE-Datei gespeichert werden. RAW-Audio Dateien können mit den gängigen Audiobearbeitungsprogrammen geöffnet werden, es muss entsprechend Bittiefe (16-Bit), Abtastrate (44100Hz) und Kanalanzahl (2, Stereo) angegeben werden.
Folgendes Tutorial hat mir beim Erstellen des Codes sehr geholfen: http://www.codeproject.com/KB/audio-...px?msg=1686942
Delphi-Quellcode:
program Project1;
{$APPTYPE CONSOLE}
uses
Windows,
SysUtils, Classes;
type
TTrackDataAddressArray = array[0..3] of Byte;
TTrackData = packed record
Reserved: Byte;
ControlAdr: Byte;
TrackNumber: Byte;
Reserved1: Byte;
Address: TTrackDataAddressArray;
end;
TCDROMTOC = packed record
Length: Word;
FirstTrack: Byte;
LastTrack: Byte;
TrackData: array[0..99] of TTrackData;
end;
TRAWReadInfo = packed record
DiskOffset: Int64;
SectorCount: Cardinal;
TrackMode: Cardinal;
end;
const
IOCTL_CDROM_READ_TOC = $00024000;
IOCTL_CDROM_RAW_READ = $0002403e;
YellowMode2 = 0;
XAForm2 = 1;
CDDA = 2;
const
sector_size = 2352;
sector_count = 20;
function AddressToSectors(addr: TTrackDataAddressArray): int64;
begin
result := addr[1] * 75 * 60 + addr[2] * 75 + addr[3] - 150;
end;
procedure ReadTrackData(AStream: TStream; AID: integer; const AToc: TCDROMTOC;
ADev: HFILE);
var
buf: PByte;
s: integer;
c, rc: integer;
offs: Int64;
read: Cardinal;
info: TRAWReadInfo;
addr: int64;
length: int64;
begin
Writeln;
Writeln('Reading track ', AID);
//Calculate address and length of the track
addr := AddressToSectors(AToc.TrackData[AID - AToc.FirstTrack].Address);
length := AddressToSectors(AToc.TrackData[AID - AToc.FirstTrack + 1].Address) - addr;
info.TrackMode := CDDA;
s := sector_size * sector_count;
GetMem(buf, s);
try
c := length;
offs := addr * 2048;
while c > 0 do
begin
//Set the read offset
info.DiskOffset := offs;
if c > sector_count then
rc := sector_count
else
rc := c;
info.SectorCount := rc;
//Read the data
if not DeviceIoControl(ADev, IOCTL_CDROM_RAW_READ, @info, SizeOf(info), buf,
rc * 2352, read, nil) then
RaiseLastOSError;
//Write it to the memory stream
AStream.Write(buf^, read);
//Calculate the next read address
c := c - sector_count;
offs := offs + sector_count * 2048;
Write('Sectors remaining ', c, ' ', #13);
end;
finally
FreeMem(buf, s);
end;
Writeln;
end;
var
i: integer;
fs: TStream;
hndl: HFILE;
dummy: Cardinal;
toc: TCDROMTOC;
begin
//Open the CD-Audio (F: is the drive letter of the cd drive)
hndl := CreateFile('\\.\F:', GENERIC_READ,
FILE_SHARE_READ or FILE_SHARE_WRITE, nil, OPEN_EXISTING, 0, 0);
if hndl <> INVALID_HANDLE_VALUE then
begin
try
//Read the cd audio table of content
if not DeviceIoControl(hndl, IOCTL_CDROM_READ_TOC, nil, 0, @toc, SizeOf(toc), dummy,
nil) then
RaiseLastOSError;
//Read every track
for i := toc.FirstTrack to toc.LastTrack do
begin
fs := TFileStream.Create('track'+FormatFloat('00', i)+'.raw', fmCreate);
try
ReadTrackData(fs, i, toc, hndl);
finally
fs.Free;
end;
end;
finally
//Close the device
CloseHandle(hndl);
end;
end;
end.
Eine in Klassen gekapselte Version des Codes kann hier gefunden werden: http://audorra.svn.sourceforge.net/v...iew=markup#l_1
Ich hoffe, der Eine oder Andere kann den Code gebrauchen,
Andreas
Stichworte: cdrom, audio, rip, rippen, lesen, volume, direktzugriff, daten, cda, cdda, cdaudio, cd-audio
Andreas "Sollen sich auch alle schämen, die gedankenlos sich der Wunder der Wissenschaft und Technik bedienen, und nicht mehr davon geistig erfasst haben als die Kuh von der Botanik der Pflanzen, die sie mit Wohlbehagen frisst." - Albert Einstein
|