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.nB lockAlign;

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 < EndSect); sector+=NSECTORS)
  {
     int Sectors2Read = ( (sector + NSECTORS) < EndSect )?NSECTORS: (EndSect-sector);
     if (ReadSector(sector, Data, Sectors2Read))
     {
        m_file.Write(Data,CB_AUDIO*Sectors2Read);
        m_file.Seek(m_seek+=CB_AUDIO*Sectors2Read,CFile::begin);
     }
  }
  m_file.Close();

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

下载源代码:http://www.vckbase.net/code/viewcode.asp?id=2278

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值