El código mostrado a continuación muestra los pasos básicos para extraer la información de un CD de Audio, convirtiéndolo al formato mp3 sin el uso de librerías de terceros (bajadas de Internet).
En lugar de arrastrar librerías (Ej. LAME), que habrían de estar coladas en nuestros créditos, utiliza los mismos CODECS del S.O. utilizando su servicio ACM (Audio Compression Manager), produciendo MP3 con solo ~100 líneas de código.
program ripCDDA; // by cHackAll uses Windows, MMSystem; const Drive = 'H'; // Sectors = 446; // ~1 Mb. type TAcmStreamHeader = packed record cbStruct, fdwStatus, dwUser: Cardinal; pbSrc: PByte; cbSrcLength, cbSrcLengthUsed, dwSrcUser: Cardinal; pbDst: PByte; cbDstLength, cbDstLengthUsed, dwDstUser: Cardinal; dwReservedDriver: array [0..9] of Cardinal; end; function acmStreamOpen(var phas: Cardinal; had: Cardinal; pwfxSrc, pwfxDst: PWaveFormatEx; pwfltr: Pointer; dwCallback, dwInstance, fdwOpen: Cardinal): Cardinal; stdcall external 'msacm32'; function acmStreamSize(has, cbInput: Cardinal; var pdwOutputBytes: Cardinal; fdwSize: Cardinal): Cardinal; stdcall external 'msacm32'; function acmStreamPrepareHeader(has: Cardinal; var pash: TAcmStreamHeader; fdwPrepare: Cardinal): Cardinal; stdcall external 'msacm32'; function acmStreamConvert(has: Cardinal; var pash: TAcmStreamHeader; fdwConvert: Cardinal): Cardinal; stdcall external 'msacm32'; function _itoa(Value: Integer; lpBuffer: PChar; Radix: Integer): PChar; cdecl external 'ntdll'; var TOC: record Length: Word; FirstTrack, LastTrack: Byte; TrackData: array [1..100] of packed record Reserved, ControlAdr, TrackNumber, Reserved1: Byte; Address: packed record case Integer of 0: (Value: Cardinal); 1: (Bytes: array [0..3] of Byte); end; end; end; Info: record DiskOffset: Int64; SectorCount, TrackMode: Cardinal; end = (SectorCount: Sectors; TrackMode: 2{CDDA}); Buffer: array [1..2352{RAW_SECTOR_SIZE} * Sectors] of Byte; hDevice, Dummy, Index, Count, hFile, hStream: Cardinal; Header: TAcmStreamHeader = (cbStruct: SizeOf(Header); pbSrc: @Buffer); src: TWaveFormatEx = (wFormatTag: WAVE_FORMAT_PCM; nChannels: 2{Stereo}; nSamplesPerSec: 44100{44.1 kHz}; nAvgBytesPerSec: 176400; nBlockAlign: 4; wBitsPerSample: 16); dst: record wfx: TWaveFormatEx; wID: Word; fdwFlags: Cardinal; nBlockSize, nFramesPerBlock, nCodecDelay: Word; end = (wfx: (wFormatTag: 85{WAVE_FORMAT_MPEGLAYER3}; nChannels: 2; nSamplesPerSec: 44100; nAvgBytesPerSec: 24000; nBlockAlign: 1; cbSize: 12); wID: 1{MPEGLAYER3_ID_MPEG}; fdwFlags: 2{MPEGLAYER3_FLAG_PADDING_OFF}; nBlockSize: 626; nFramesPerBlock: 1); { TODO : acm+VBR ? } begin if GetDriveType(Drive + ':') <> DRIVE_CDROM then Exit; hDevice := _lopen('\\.\' + Drive + ':', OF_READ); if not DeviceIoControl(hDevice, $2D4800{IOCTL_STORAGE_CHECK_VERIFY}, nil, 0, nil, 0, Dummy, nil) then DeviceIoControl(hDevice, $2D4808{IOCTL_STORAGE_EJECT_MEDIA}, nil, 0, nil, 0, Dummy, nil) else if DeviceIoControl(hDevice, $90018{FSCTL_LOCK_VOLUME}, nil, 0, nil, 0, Dummy, nil) then begin Dummy := 1{True}; DeviceIoControl(hDevice, $2D4804{IOCTL_STORAGE_MEDIA_REMOVAL}, @Dummy, 1, nil, 0, Dummy, nil); DeviceIoControl(hDevice, $24000{IOCTL_CDROM_READ_TOC}, nil, 0, @TOC, SizeOf(TOC), Dummy, nil); for Index := TOC.FirstTrack to TOC.LastTrack + 1 do with TOC.TrackData[Index] do Address.Value := (Address.Bytes[1] * 4500 + Address.Bytes[2] * 75 + Address.Bytes[3]) - 150; acmStreamOpen(hStream, 0, @src, @dst, nil, 0, 0, 4{ACM_STREAMOPENF_NONREALTIME}); acmStreamSize(hStream, SizeOf(Buffer), Header.cbDstLength, 0{ACM_STREAMSIZEF_SOURCE}); Header.pbDst := Ptr(LocalAlloc(0, Header.cbDstLength)); for Index := TOC.FirstTrack to TOC.LastTrack do with TOC.TrackData[Index] do if ControlAdr = $12 then // See specification T10/1363-D Revision-02A, by [url]http://www.incits.org/[/url] begin Info.DiskOffset := Address.Value * 2048{COOKED_SECTOR_SIZE}; Count := TOC.TrackData[Index + 1].Address.Value - Address.Value; _itoa(Index, @lstrcpy(@Buffer, 'Track')[6], 10); hFile := _lcreat(lstrcat(@Buffer, '.mp3'), 0); repeat if Count < Sectors then Info.SectorCount := Count; DeviceIoControl(hDevice, $2403E{IOCTL_CDROM_RAW_READ}, @Info, SizeOf(Info), @Buffer, SizeOf(Buffer), Header.cbSrcLength, nil); acmStreamPrepareHeader(hStream, Header, 0); acmStreamConvert(hStream, Header, 4{ACM_STREAMCONVERTF_BLOCKALIGN}); _lwrite(hFile, PChar(Header.pbDst), Header.cbDstLengthUsed); Inc(Info.DiskOffset, 2048{COOKED_SECTOR_SIZE} * Info.SectorCount); Dec(Count, Info.SectorCount); until Count = 0; end; Dummy := 0; DeviceIoControl(hDevice, $2D4804{IOCTL_STORAGE_MEDIA_REMOVAL}, @Dummy, 1, nil, 0, Dummy, nil); end; end { TODO : MemoryLeak } .
Enjoy!