366 lines
10 KiB
C++
366 lines
10 KiB
C++
|
// cdread.cpp
|
||
|
//
|
||
|
|
||
|
#include <windows.h>
|
||
|
#include <windowsx.h>
|
||
|
#include <TCHAR.H>
|
||
|
#include <mmsystem.h>
|
||
|
#include "cdread.h"
|
||
|
#include "cddata.h"
|
||
|
#include "..\main\resource.h"
|
||
|
#include "..\main\sink.h"
|
||
|
#include "mmreg.h"
|
||
|
#include "msacm.h"
|
||
|
|
||
|
HANDLE hFile = NULL;
|
||
|
LPCDDATA pData = NULL;
|
||
|
TIMEDMETER tm;
|
||
|
DWORD dwTotalBytes = 0;
|
||
|
WAVEFORMATEX wfxPCM1, wfxPCM2;
|
||
|
|
||
|
DWORD cbOutBytes[3];
|
||
|
HACMSTREAM acmStream[3];
|
||
|
ACMSTREAMHEADER acmHeader[3];
|
||
|
BYTE sSample[CDDA_SECTOR_SIZE * SECTORS_PER_READ];
|
||
|
BYTE sCompBuffer[CDDA_SECTOR_SIZE * SECTORS_PER_READ];
|
||
|
|
||
|
// Write a WAV header for the selected format
|
||
|
BOOL writeHeader(int iSize, LPWAVEFORMATEX lpwfx)
|
||
|
{
|
||
|
DWORD dwBytesWritten = 0;
|
||
|
unsigned data, formatdata;
|
||
|
WORD wData;
|
||
|
|
||
|
WriteFile(hFile,"RIFF",4,&dwBytesWritten,NULL);
|
||
|
|
||
|
formatdata = 16;
|
||
|
|
||
|
if ((lpwfx->wFormatTag != WAVE_FORMAT_PCM) && (lpwfx->cbSize > 0))
|
||
|
{
|
||
|
formatdata += sizeof(WORD); //to write cdSize out
|
||
|
formatdata += lpwfx->cbSize;
|
||
|
}
|
||
|
|
||
|
data = 0x24 + iSize + (formatdata-16);
|
||
|
WriteFile(hFile,&data,sizeof(unsigned),&dwBytesWritten,NULL);
|
||
|
WriteFile(hFile,"WAVE",4,&dwBytesWritten,NULL);
|
||
|
WriteFile(hFile,"fmt ",4,&dwBytesWritten,NULL);
|
||
|
|
||
|
WriteFile(hFile,&formatdata,sizeof(unsigned),&dwBytesWritten,NULL);
|
||
|
|
||
|
WriteFile(hFile,lpwfx,formatdata,&dwBytesWritten,NULL);
|
||
|
|
||
|
/*
|
||
|
wData = lpwfx->wFormatTag;
|
||
|
WriteFile(hFile,&wData,sizeof(WORD),&dwBytesWritten,NULL);
|
||
|
|
||
|
wData = lpwfx->nChannels;
|
||
|
WriteFile(hFile,&wData,sizeof(WORD),&dwBytesWritten,NULL);
|
||
|
|
||
|
data = lpwfx->nSamplesPerSec;
|
||
|
WriteFile(hFile,&data,sizeof(unsigned),&dwBytesWritten,NULL);
|
||
|
|
||
|
data = lpwfx->nAvgBytesPerSec;
|
||
|
WriteFile(hFile,&data,sizeof(unsigned),&dwBytesWritten,NULL);
|
||
|
|
||
|
wData = lpwfx->nBlockAlign;
|
||
|
WriteFile(hFile,&wData,sizeof(WORD),&dwBytesWritten,NULL);
|
||
|
|
||
|
wData = lpwfx->wBitsPerSample;
|
||
|
WriteFile(hFile,&wData,sizeof(WORD),&dwBytesWritten,NULL);
|
||
|
|
||
|
if ((lpwfx->wFormatTag != WAVE_FORMAT_PCM) && (lpwfx->cbSize > 0))
|
||
|
{
|
||
|
wData = lpwfx->cbSize;
|
||
|
WriteFile(hFile,&wData,sizeof(WORD),&dwBytesWritten,NULL);
|
||
|
|
||
|
pData = (BYTE*)(&(lpwfx->cbSize) + sizeof(WORD));
|
||
|
WriteFile(hFile,pData,lpwfx->cbSize,&dwBytesWritten,NULL);
|
||
|
}
|
||
|
*/
|
||
|
|
||
|
WriteFile(hFile,"data",4,&dwBytesWritten,NULL);
|
||
|
|
||
|
data = iSize;
|
||
|
WriteFile(hFile,&data,sizeof(unsigned),&dwBytesWritten,NULL);
|
||
|
|
||
|
return TRUE;
|
||
|
}
|
||
|
|
||
|
|
||
|
BOOL readTOC( HANDLE hDevice, PCDROM_TOC pToc )
|
||
|
{
|
||
|
DWORD dwTocSize = sizeof(CDROM_TOC);
|
||
|
DWORD dwBytesReturned = 0;
|
||
|
DWORD dwNumTracks = 0;
|
||
|
|
||
|
if( !DeviceIoControl( hDevice,
|
||
|
IOCTL_CDROM_READ_TOC,
|
||
|
pToc, // pointer to inputbuffer
|
||
|
dwTocSize, // sizeof inputbuffer
|
||
|
pToc, // pointer to outputbuffer
|
||
|
dwTocSize, // sizeof outputbuffer
|
||
|
&dwBytesReturned, // pointer to number of bytes returned
|
||
|
FALSE
|
||
|
)
|
||
|
)
|
||
|
{
|
||
|
return FALSE;
|
||
|
}
|
||
|
|
||
|
dwNumTracks = pToc->LastTrack - pToc->FirstTrack;
|
||
|
|
||
|
//
|
||
|
// number of tracks plus zero-based plus leadout track
|
||
|
//
|
||
|
|
||
|
if ( (dwNumTracks+2) * sizeof(TRACK_DATA) != dwBytesReturned - 4 )
|
||
|
{
|
||
|
dwNumTracks = (dwBytesReturned - 4) / sizeof(TRACK_DATA);
|
||
|
}
|
||
|
|
||
|
// parse and print the information
|
||
|
|
||
|
PTRACK_DATA pTrack = (PTRACK_DATA) &(pToc->TrackData[0]);
|
||
|
|
||
|
return TRUE;
|
||
|
}
|
||
|
|
||
|
BOOL skipRead( BYTE* buffer, DWORD dwSize, int iPercent )
|
||
|
{
|
||
|
return TRUE;
|
||
|
}
|
||
|
|
||
|
BOOL writeRead( BYTE* buffer, DWORD dwSize, int iPercent )
|
||
|
{
|
||
|
DWORD dwBytesWritten = 0;
|
||
|
|
||
|
if (pData)
|
||
|
{
|
||
|
pData->UpdateMeter(&tm);
|
||
|
}
|
||
|
|
||
|
acmStreamConvert(acmStream[0],&acmHeader[0],0);
|
||
|
acmStreamConvert(acmStream[1],&acmHeader[1],0);
|
||
|
acmStreamConvert(acmStream[2],&acmHeader[2],0);
|
||
|
|
||
|
WriteFile(hFile,sCompBuffer,acmHeader[2].cbDstLengthUsed,&dwBytesWritten,NULL);
|
||
|
|
||
|
dwTotalBytes += dwBytesWritten;
|
||
|
|
||
|
return TRUE;
|
||
|
}
|
||
|
|
||
|
BOOL rawReadTrack(HANDLE device, PCDROM_TOC pTOC, int iTrack, LPREADFUNC lpReadFunc )
|
||
|
{
|
||
|
|
||
|
RAW_READ_INFO info; // fill in for the read request
|
||
|
DWORD dwBytesRead; // bytes returned
|
||
|
DWORD dwStartingLBA;
|
||
|
DWORD dwNumLBA;
|
||
|
DWORD dwEndingLBA;
|
||
|
DWORD dwSectorsToRead;
|
||
|
DWORD dwError;
|
||
|
PTRACK_DATA pTrack = (PTRACK_DATA) &(pTOC->TrackData[0]);
|
||
|
PTRACK_DATA pTrack2;
|
||
|
|
||
|
// Use VirtualAlloc so we get a page-aligned region since we're doing
|
||
|
// non-cached IO
|
||
|
/*
|
||
|
sSample = (BYTE*)VirtualAlloc(NULL, PAGE_VAL, MEM_COMMIT, PAGE_READWRITE );
|
||
|
if( !sSample )
|
||
|
{
|
||
|
//MessageBox( NULL, "Error allocating memory block.", "Error", MB_OK );
|
||
|
return FALSE;
|
||
|
}
|
||
|
*/
|
||
|
|
||
|
pTrack += (iTrack-1);
|
||
|
pTrack2 = pTrack + 1;
|
||
|
|
||
|
dwStartingLBA = MSF_TO_LBA( pTrack->Address[1], pTrack->Address[2], pTrack->Address[3] );
|
||
|
dwEndingLBA = MSF_TO_LBA( pTrack2->Address[1], pTrack2->Address[2], pTrack2->Address[3] );
|
||
|
dwNumLBA = dwEndingLBA-dwStartingLBA;
|
||
|
|
||
|
//
|
||
|
// round up the num sectors to read
|
||
|
//
|
||
|
dwSectorsToRead = ((dwNumLBA - 1) / SECTORS_PER_READ + 1) * SECTORS_PER_READ;
|
||
|
dwEndingLBA = dwStartingLBA + dwSectorsToRead;
|
||
|
|
||
|
// start the read loop
|
||
|
for ( DWORD i = dwStartingLBA; i < dwEndingLBA; i += SECTORS_PER_READ )
|
||
|
{
|
||
|
int iPercent;
|
||
|
|
||
|
info.DiskOffset.QuadPart = (unsigned __int64)(i*2048);
|
||
|
info.SectorCount = SECTORS_PER_READ;
|
||
|
info.TrackMode = CDDA;
|
||
|
|
||
|
if( !DeviceIoControl( device,
|
||
|
IOCTL_CDROM_RAW_READ,
|
||
|
&info, // pointer to inputbuffer
|
||
|
sizeof(RAW_READ_INFO), // sizeof inputbuffer
|
||
|
sSample, // pointer to outputbuffer
|
||
|
CDDA_SECTOR_SIZE * SECTORS_PER_READ, // sizeof outputbuffer
|
||
|
&dwBytesRead, // pointer to number of bytes returned
|
||
|
FALSE // ???
|
||
|
)
|
||
|
)
|
||
|
{
|
||
|
goto fail;
|
||
|
}
|
||
|
|
||
|
iPercent = (i-dwStartingLBA)/(dwEndingLBA-dwStartingLBA);
|
||
|
|
||
|
if( !((*lpReadFunc)(sSample, dwBytesRead, iPercent) ) )
|
||
|
{
|
||
|
goto fail;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
//VirtualFree( sSample, PAGE_VAL, MEM_DECOMMIT );
|
||
|
return TRUE;
|
||
|
|
||
|
fail:
|
||
|
VirtualFree( sSample, PAGE_VAL, MEM_DECOMMIT );
|
||
|
return FALSE;
|
||
|
|
||
|
}
|
||
|
|
||
|
// Find the byte size of a track
|
||
|
int getTrackSize( PCDROM_TOC pTOC, int iTrack )
|
||
|
{
|
||
|
PTRACK_DATA pTrack = &(pTOC->TrackData[0]);
|
||
|
DWORD dwLBA1, dwLBA2;
|
||
|
|
||
|
pTrack += (iTrack-1);
|
||
|
dwLBA1 = MSF_TO_LBA( pTrack->Address[1], pTrack->Address[2], pTrack->Address[3] );
|
||
|
pTrack++;
|
||
|
dwLBA2 = MSF_TO_LBA( pTrack->Address[1], pTrack->Address[2], pTrack->Address[3] );
|
||
|
|
||
|
return (dwLBA2-dwLBA1) * CDDA_SECTOR_SIZE;
|
||
|
}
|
||
|
|
||
|
BOOL StoreTrack(HWND hwndMain, TCHAR chDrive, int nTrack, TCHAR* pszFilename, LPWAVEFORMATEX lpwfxDest)
|
||
|
{
|
||
|
HANDLE hDevice;
|
||
|
TCHAR szDeviceName[MAX_PATH];
|
||
|
CDROM_TOC sTOC;
|
||
|
|
||
|
wsprintf( szDeviceName, TEXT("\\\\.\\%c:"), chDrive );
|
||
|
hDevice = CreateFile( szDeviceName, GENERIC_READ, FILE_SHARE_READ|FILE_SHARE_WRITE, NULL,
|
||
|
OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL );
|
||
|
if( INVALID_HANDLE_VALUE == hDevice )
|
||
|
{
|
||
|
return FALSE;
|
||
|
}
|
||
|
|
||
|
readTOC( hDevice, &sTOC );
|
||
|
|
||
|
int iSize = getTrackSize( &sTOC, nTrack );
|
||
|
dwTotalBytes = 0;
|
||
|
|
||
|
WAVEFORMATEX waveFormat;
|
||
|
|
||
|
waveFormat.wFormatTag = WAVE_FORMAT_PCM;
|
||
|
waveFormat.nChannels = 2;
|
||
|
waveFormat.nSamplesPerSec = 44100;
|
||
|
waveFormat.nAvgBytesPerSec = 176400;
|
||
|
waveFormat.nBlockAlign = 4;
|
||
|
waveFormat.wBitsPerSample = 16;
|
||
|
waveFormat.cbSize = sizeof(waveFormat);
|
||
|
|
||
|
wfxPCM1.wFormatTag = WAVE_FORMAT_PCM;
|
||
|
acmFormatSuggest(NULL, &waveFormat, &wfxPCM1, sizeof(WAVEFORMATEX),
|
||
|
ACM_FORMATSUGGESTF_WFORMATTAG);
|
||
|
|
||
|
wfxPCM2.wFormatTag = WAVE_FORMAT_PCM;
|
||
|
acmFormatSuggest(NULL, lpwfxDest, &wfxPCM2, sizeof(WAVEFORMATEX),
|
||
|
ACM_FORMATSUGGESTF_WFORMATTAG);
|
||
|
|
||
|
acmStreamOpen(&acmStream[0],NULL,&waveFormat,&wfxPCM1,NULL,NULL,0,ACM_STREAMOPENF_NONREALTIME);
|
||
|
acmStreamOpen(&acmStream[1],NULL,&wfxPCM1,&wfxPCM2,NULL,NULL,0,ACM_STREAMOPENF_NONREALTIME);
|
||
|
acmStreamOpen(&acmStream[2],NULL,&wfxPCM2,lpwfxDest,NULL,NULL,0,ACM_STREAMOPENF_NONREALTIME);
|
||
|
|
||
|
acmStreamSize(acmStream[0],CDDA_SECTOR_SIZE * SECTORS_PER_READ,&cbOutBytes[0],ACM_STREAMSIZEF_SOURCE);
|
||
|
acmStreamSize(acmStream[1],CDDA_SECTOR_SIZE * SECTORS_PER_READ,&cbOutBytes[1],ACM_STREAMSIZEF_SOURCE);
|
||
|
acmStreamSize(acmStream[2],CDDA_SECTOR_SIZE * SECTORS_PER_READ,&cbOutBytes[2],ACM_STREAMSIZEF_SOURCE);
|
||
|
|
||
|
acmHeader[0].cbStruct = sizeof(acmHeader);
|
||
|
acmHeader[0].fdwStatus = 0;
|
||
|
acmHeader[0].dwUser = 0;
|
||
|
acmHeader[0].pbSrc = sSample;
|
||
|
acmHeader[0].cbSrcLength = CDDA_SECTOR_SIZE * SECTORS_PER_READ;
|
||
|
acmHeader[0].pbDst = sCompBuffer;
|
||
|
acmHeader[0].cbDstLength = cbOutBytes[0];
|
||
|
acmHeader[0].dwDstUser = 0;
|
||
|
|
||
|
acmHeader[1].cbStruct = sizeof(acmHeader);
|
||
|
acmHeader[1].fdwStatus = 0;
|
||
|
acmHeader[1].dwUser = 0;
|
||
|
acmHeader[1].pbSrc = sCompBuffer;
|
||
|
acmHeader[1].cbSrcLength = cbOutBytes[0];
|
||
|
acmHeader[1].pbDst = sSample;
|
||
|
acmHeader[1].cbDstLength = cbOutBytes[1];
|
||
|
acmHeader[1].dwDstUser = 0;
|
||
|
|
||
|
acmHeader[2].cbStruct = sizeof(acmHeader);
|
||
|
acmHeader[2].fdwStatus = 0;
|
||
|
acmHeader[2].dwUser = 0;
|
||
|
acmHeader[2].pbSrc = sSample;
|
||
|
acmHeader[2].cbSrcLength = cbOutBytes[1];
|
||
|
acmHeader[2].pbDst = sCompBuffer;
|
||
|
acmHeader[2].cbDstLength = cbOutBytes[2];
|
||
|
acmHeader[2].dwDstUser = 0;
|
||
|
|
||
|
acmStreamPrepareHeader(acmStream[0],&acmHeader[0],0);
|
||
|
acmStreamPrepareHeader(acmStream[1],&acmHeader[1],0);
|
||
|
acmStreamPrepareHeader(acmStream[2],&acmHeader[2],0);
|
||
|
|
||
|
hFile = CreateFile(pszFilename,GENERIC_WRITE,FILE_SHARE_WRITE,NULL,CREATE_ALWAYS,FILE_ATTRIBUTE_NORMAL,NULL);
|
||
|
|
||
|
//write a temp header. we'll need to write a new one later when we know the right file size
|
||
|
if( !writeHeader( iSize, lpwfxDest ) )
|
||
|
{
|
||
|
CloseHandle( hFile );
|
||
|
return FALSE;
|
||
|
}
|
||
|
|
||
|
pData = GetCDData();
|
||
|
|
||
|
if (pData)
|
||
|
{
|
||
|
pData->CreateMeter(&tm,hwndMain,(iSize / (CDDA_SECTOR_SIZE * SECTORS_PER_READ)),5,IDS_RIPPING_CD);
|
||
|
}
|
||
|
|
||
|
rawReadTrack( hDevice, &sTOC, nTrack, writeRead );
|
||
|
|
||
|
if (pData)
|
||
|
{
|
||
|
pData->DestroyMeter(&tm);
|
||
|
}
|
||
|
|
||
|
acmStreamUnprepareHeader(acmStream[0],&acmHeader[0],0);
|
||
|
acmStreamUnprepareHeader(acmStream[1],&acmHeader[1],0);
|
||
|
acmStreamUnprepareHeader(acmStream[2],&acmHeader[2],0);
|
||
|
|
||
|
acmStreamClose(acmStream[0],0);
|
||
|
acmStreamClose(acmStream[1],0);
|
||
|
acmStreamClose(acmStream[2],0);
|
||
|
|
||
|
CloseHandle( hDevice );
|
||
|
|
||
|
SetFilePointer(hFile,0,NULL,FILE_BEGIN);
|
||
|
|
||
|
if( !writeHeader( dwTotalBytes, lpwfxDest ) )
|
||
|
{
|
||
|
CloseHandle( hFile );
|
||
|
return FALSE;
|
||
|
}
|
||
|
|
||
|
CloseHandle( hFile );
|
||
|
|
||
|
return TRUE;
|
||
|
}
|