C++实现CD抓轨转WAV

王朝vc·作者佚名  2006-01-17
窄屏简体版  字體: |||超大  

C++实现CD抓轨转WAV

作者:黄利龙

下载源代码

现在介绍一下C++实现CD抓轨转WAV,CD抓轨的方法有好几种,现在介绍其中一种。我们可以通过API函数CreateFile获得设备句柄,再用API函数DeviceIoControl来实现对设备的访问获取信息。再此还会用到WAVE文件结构WAVEFORMATEX,再把读到的信息写到文件里生成WAVE格式的文件。

我们要用到的头文件有: ntddcdrm.h(NTDDK开发包) winioctl.h

Mmreg.h

1、搜索光驱

我们可以用GetDriveType来判断设备类型,5为CDROM类型。返回类型可以参看MSDN,里面有详细介绍。

2、打开设备

用CreateFile获得设备句柄,例子如下:

HANDLE m_hDevice;

CString FileName=”F:”;

m_hDevice =CreateFile("\\\\.\\"+FileName, // 文件名路径

GENERIC_READ, // 读写方式

FILE_SHARE_READ | FILE_SHARE_WRITE, // 共享方式

NULL, // 默认的安全描述符

OPEN_EXISTING, // 创建方式

0, // 不需设置文件属性

NULL); // 不需参照模板文件

3、读取CD参数

得到了设备句柄,我们就可以用DeviceIoControl来获息相关信息.

DeviceIoControl函数原型:

BOOL DeviceIoControl(

HANDLE hDevice, // 设备句柄

DWORD dwIoControlCode, // 控制码

LPVOID lpInBuffer, // 输入数据缓冲区指针

DWORD nInBufferSize, // 输入数据缓冲区长度

LPVOID lpOutBuffer, // 输出数据缓冲区指针

DWORD nOutBufferSize, // 输出数据缓冲区长度

LPDWORD lpBytesReturned, // 输出数据实际长度单元长度

LPOVERLAPPED lpOverlapped // 重叠操作结构指针

);

4、获取曲目

使用IOCTL_CDROM_READ_TOC控制码输出CDROM_TOC结构

BOOL bResult;

DWORD dwOutBytes;

CDROM_TOC CdromTOC; //曲目信息结构,详细请看MSDN

bResult=DeviceIoControl(m_hDevice,

IOCTL_CDROM_READ_TOC,NULL,0,

&CdromTOC,

sizeof(CdromTOC),

&dwOutBytes,

(LPOVERLAPPED)NULL);

5、获取曲目始点

DWORD CCdToWavDlg::GetStartSector(int track)

{

return (CdromTOC.TrackData[track-1].Address[1]*60*75 +

CdromTOC.TrackData[track-1].Address[2]*75 +

CdromTOC.TrackData[track-1].Address[3])-150;

}

6、获取曲目终点

DWORD CCdToWavDlg::GetEndSector(int track)

{

return (CdromTOC.TrackData[track].Address[1]*60*75 +

CdromTOC.TrackData[track].Address[2]*75 +

CdromTOC.TrackData[track].Address[3])-151;

}

7、读取曲目信息

使用IOCTL_CDROM_RAW_READ输入RAW_READ_INFO结构信息,输出来获取区域内容

BOOL CCdToWavDlg::ReadSector(int sector,BYTE Buffer[], int NumSectors)

{

DWORD dwOutBytes;

RAW_READ_INFO rri; //结构详细请看MSDN

rri.TrackMode =(TRACK_MODE_TYPE)2;

rri.SectorCount = (DWORD)NumSectors;

rri.DiskOffset =(DWORD64)(sector*CB_CDROMSECTOR);

if (DeviceIoControl(m_hDevice,IOCTL_CDROM_RAW_READ,

&rri,

sizeof(rri),

Buffer,

(DWORD)NumSectors*CB_AUDIO,&dwOutBytes,

(LPOVERLAPPED)NULL)) return true;

return false;

}

8、

文件生成

WAVE文件是非常简单的一种RIFF文件,它的格式类型为"WAVE"。RIFF块包含两个子块,这两个子块的ID分别是"fmt"和"data",其中"fmt"子块由结构WAVEFORMATEX所组成,其子块的大小就是sizeofof(WAVEFORMATEX),数据组成就是WAVEFORMATEX结构中的数据。WAVE文件的结构如下图所示:

标志符(RIFF)

数据大小

格式类型("WAVE")

"fmt"

Sizeof(WAVEFORMATEX)

WAVEFORMATEX

"data"

声音数据大小

声音数据

WAVEFORMATEX结构原型:

typedef struct

{

WORD wFormatTag; //编码格式,包括WAVE_FORMAT_PCM,WAVEFORMAT_ADPCM等

WORD nChannels; //声道数,单声道为1,双声道为2

DWORD nSamplesPerSec; //采样频率

DWORD nAvgBytesPerSec; //每秒的数据量

WORD nBlockAlign; //块对齐

WORD wBitsPerSample; //WAVE文件的采样大小

WORD cbSize;

} WAVEFORMATEX; *PWAVEFORMATEX;

9、定义WAVE文件结构 DWORD m_WaveHeaderSize = 38;

DWORD m_WaveFormatSize = 18;

DWORD m_AudioDataSize =0;

DWORD m_WrittenBytes = 0;

WAVEFORMATEX m_WaveFormatEx;

m_WaveFormatEx.wFormatTag=WAVE_FORMAT_PCM ;

m_WaveFormatEx.nSamplesPerSec=48000;

m_WaveFormatEx.wBitsPerSample=16;

m_WaveFormatEx.nChannels=2;

m_WaveFormatEx.cbSize=0;

m_WaveFormatEx.nBlockAlign=m_WaveFormatEx.nChannels*(m_WaveFormatEx.wBitsPerSample/8);

m_WaveFormatEx.nAvgBytesPerSec=m_WaveFormatEx.nSamplesPerSec*m_WaveFormatEx.nBlockAlign;

10、创建新文件

CFile m_file;

CFileException fileException;

CString m_csFileName= m_SavePath;

m_file.Open(m_csFileName,CFile::modeCreate|CFile::modeReadWrite, &fileException);

int StartSect=GetStartSector(m_List.GetCurSel()+1);

int EndSect=GetEndSector(m_List.GetCurSel()+1);

DWORD Bytes2Read=(EndSect - StartSect)*CB_AUDIO;

m_AudioDataSize=Bytes2Read;

BYTE Data[CB_AUDIO*NSECTORS];

11、写入WAV文件头

WAV文件头一定要按顺序写入

m_file.SeekToBegin();

m_file.Write("RIFF",4);

unsigned int Sec=(m_AudioDataSize + m_WaveHeaderSize);

m_file.Write(&Sec,sizeof(Sec));

m_file.Write("WAVE",4);

m_file.Write("fmt ",4);

m_file.Write(&m_WaveFormatSize,sizeof(m_WaveFormatSize));

m_file.Write(&m_WaveFormatEx.wFormatTag,sizeof(m_WaveFormatEx.wFormatTag));

m_file.Write(&m_WaveFormatEx.nChannels,sizeof(m_WaveFormatEx.nChannels));

m_file.Write(&m_WaveFormatEx.nSamplesPerSec,sizeof(m_WaveFormatEx.nSamplesPerSec));

m_file.Write(&m_WaveFormatEx.nAvgBytesPerSec,sizeof(m_WaveFormatEx.nAvgBytesPerSec));

m_file.Write(&m_WaveFormatEx.nBlockAlign,sizeof(m_WaveFormatEx.nBlockAlign));

m_file.Write(&m_WaveFormatEx.wBitsPerSample,sizeof(m_WaveFormatEx.wBitsPerSample));

m_file.Write(&m_WaveFormatEx.cbSize,sizeof(m_WaveFormatEx.cbSize));

m_file.Write("data",4);

m_file.Write(&m_AudioDataSize,sizeof(m_AudioDataSize));

12、写入音频数据

把音频数据放到WAV文件头后写入

DWORD m_seek=46; //文件头长度为46个字,必须从46后写入

for (int sector = StartSect; (sector

详细请看源代码。以上在 VC7+Window2000+NTDDK 测试通过。

 
 
 
免责声明:本文为网络用户发布,其观点仅代表作者个人观点,与本站无关,本站仅提供信息存储服务。文中陈述内容未经本站证实,其真实性、完整性、及时性本站不作任何保证或承诺,请读者仅作参考,并请自行核实相关内容。
 
 
© 2005- 王朝網路 版權所有 導航