// cdread.cpp // #include #include #include #include #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; }