123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394 |
- // conv.cpp
- //
- // convert a PCM wave to some other format
- //转换一个PCM格式的wav到其他格式
- #include "stdafx.h"
- #include <windows.h> //包含头文件 windows.h
- #include <mmsystem.h>//包含头文件mmsystem.h
- #include <mmreg.h> // Multimedia registration多媒体注册
- #include <msacm.h> // Audio Compression Manager音频压缩管理器
- #include <stdio.h>
- #include <math.h>
- #include "conv.h"
- #include "Global.h"
- #pragma comment(lib,"MSAcm32.Lib")
- #pragma comment(lib,"winmm.lib")
- // Locate a driver that supports a given format and return its ID
- //寻找一个支持给定格式的驱动并返回其ID
- typedef struct
- {
- HACMDRIVERID hadid;//指向HACMDRIVERID的句柄
- WORD wFormatTag;//32位无符号整型 格式标签
- } FIND_DRIVER_INFO;//结构FIND_DRIVER_INFO包含2个元素:HACMDRIVERID hadid 和WORD wFormatTag
- // callback function for format enumeration
- //用来枚举格式的回调函数
- BOOL CALLBACK find_format_enum(HACMDRIVERID hadid, LPACMFORMATDETAILS pafd, DWORD dwInstance, DWORD fdwSupport)//LPACMFORMATDETAILS pafd指向ACM格式详情的指针
- {
- FIND_DRIVER_INFO* pdi = (FIND_DRIVER_INFO*) dwInstance;//FIND_DRIVER_INFO类型的指针 指向驱动信息
- if (pafd->dwFormatTag == (DWORD)pdi->wFormatTag) //如果详情中的格式标签==驱动信息指针pdi中的格式标签
- {
- // found it如果能找到
- pdi->hadid = hadid;
- return FALSE; // stop enumerating停止枚举
- }
- return TRUE; // continue enumerating继续枚举
- }
- // callback function for driver enumeration
- //用来枚举驱动的回调函数
- BOOL CALLBACK find_driver_enum(HACMDRIVERID hadid, DWORD dwInstance, DWORD fdwSupport)
- {
- FIND_DRIVER_INFO* pdi = (FIND_DRIVER_INFO*) dwInstance;
- // open the driver打开驱动
- HACMDRIVER had = NULL;//HACMDRIVER类型的变量 had 指向ACM驱动的句柄
- MMRESULT mmr = acmDriverOpen(&had, hadid, 0);
- if (mmr)
- {
- // some error错误
- return FALSE; // stop enumerating停止枚举
- }
- // enumerate the formats it supports枚举它支持的格式
- DWORD dwSize = 0;
- mmr = acmMetrics((HACMOBJ)had, ACM_METRIC_MAX_SIZE_FORMAT, &dwSize);
- if (dwSize < sizeof(WAVEFORMATEX)) dwSize = sizeof(WAVEFORMATEX); // for MS-PCM
- WAVEFORMATEX* pwf = (WAVEFORMATEX*) malloc(dwSize);
- memset(pwf, 0, dwSize);
- pwf->cbSize = LOWORD(dwSize) - sizeof(WAVEFORMATEX);
- pwf->wFormatTag = pdi->wFormatTag;
- ACMFORMATDETAILS fd;
- memset(&fd, 0, sizeof(fd));
- fd.cbStruct = sizeof(fd);
- fd.pwfx = pwf;
- fd.cbwfx = dwSize;
- fd.dwFormatTag = pdi->wFormatTag;
- mmr = acmFormatEnum(had, &fd, find_format_enum, (DWORD)(VOID*)pdi, 0);
- free(pwf);
- acmDriverClose(had, 0);
- if (pdi->hadid || mmr)
- {
- // found it or some error找到了 或 有错误
- return FALSE; // stop enumerating停止枚举
- }
- return TRUE; // continue enumeration继续枚举
- }
- // locate the first driver that supports a given format tag
- //寻找支持给定格式标签的第一个驱动
- HACMDRIVERID find_driver(WORD wFormatTag)
- {
- FIND_DRIVER_INFO fdi;
- fdi.hadid = NULL;
- fdi.wFormatTag = wFormatTag;
- MMRESULT mmr = acmDriverEnum(find_driver_enum, (DWORD)(VOID*)&fdi, 0);
- if (mmr) return NULL;
- return fdi.hadid;
- }
- // get a description of the first format supported for a given tag
- //获取驱动的描述 这个驱动是第一个支持给定标签的驱动。
- WAVEFORMATEX* get_driver_format(HACMDRIVERID hadid, WORD wFormatTag)
- {
- // open the driver打开驱动
- HACMDRIVER had = NULL;
- MMRESULT mmr = acmDriverOpen(&had, hadid, 0);
- if (mmr) {
- return NULL;
- }
- // allocate a structure for the info
- //为信息分配一个结构
- DWORD dwSize = 0;
- mmr = acmMetrics((HACMOBJ)had, ACM_METRIC_MAX_SIZE_FORMAT, &dwSize);
- if (dwSize < sizeof(WAVEFORMATEX)) dwSize = sizeof(WAVEFORMATEX); // for MS-PCM
- WAVEFORMATEX* pwf = (WAVEFORMATEX*) malloc(dwSize);
- memset(pwf, 0, dwSize);
- pwf->cbSize = LOWORD(dwSize) - sizeof(WAVEFORMATEX);
- pwf->wFormatTag = wFormatTag;
- ACMFORMATDETAILS fd;
- memset(&fd, 0, sizeof(fd));
- fd.cbStruct = sizeof(fd);
- fd.pwfx = pwf;
- fd.cbwfx = dwSize;
- fd.dwFormatTag = wFormatTag;
- // set up a struct to control the enumeration
- //建立一个结构用于控制枚举
- FIND_DRIVER_INFO fdi;
- fdi.hadid = NULL;
- fdi.wFormatTag = wFormatTag;
- mmr = acmFormatEnum(had, &fd, find_format_enum, (DWORD)(VOID*)&fdi, 0);
- acmDriverClose(had, 0);
- if ((fdi.hadid == NULL) || mmr)
- {
- free(pwf);
- return NULL;
- }
- return pwf;
- }
- int PcmToALow(char *pFileName, char *pDescFileName)
- {
- FILE *fp,*fpCopy;
- MMRESULT mmr;
- HEADER *pPcmHEADER = new HEADER[sizeof(HEADER)];
- FMT *pPcmFMT = new FMT[sizeof(FMT)];
- DATA *pWaveHeaderData = new DATA[sizeof(DATA)];
- int nLen = sizeof(HEADER) + sizeof(FMT) + sizeof(DATA) + 2;
- int nReadNum;
- int nFileSize;
- if((fp = fopen(pFileName, "rb")) == NULL) //读取文件
- {
- return -1;
- }
- if((fpCopy = fopen(pDescFileName, "wb+")) == NULL) //为转换建立一个新文件
- {
- return -1;
- }
- fseek(fp, 0, SEEK_SET);
- fseek(fp, 0, SEEK_END);
- nFileSize = ftell(fp);
- fseek(fp, 0, SEEK_SET);
- fread(pPcmHEADER,sizeof(unsigned short), sizeof(HEADER), fp );
- DWORD nWaveFileSize = pPcmHEADER->dwSize;
- fseek(fp, sizeof(HEADER), SEEK_SET);
- fread( pPcmFMT, sizeof(unsigned short), sizeof(FMT), fp );
- fseek(fp, sizeof(HEADER) + sizeof(FMT) + 2, SEEK_SET); //注意,+2是跳过保留的两位
- fread(pWaveHeaderData,sizeof(unsigned short), sizeof(DATA), fp );
- DWORD nPcmDataSize = pWaveHeaderData->dwSize;
- BYTE* pSrcData = new BYTE [nFileSize - nLen]; // 1 second duration
- memset(pSrcData, 0, nFileSize - nLen);
- fseek(fp, nLen, SEEK_SET);
- //nReadNum = fread(pSrcData, sizeof(unsigned short), pWaveHeaderData->dwSize, fp);
- nReadNum = fread(pSrcData, 1, nFileSize - nLen, fp);
- if( nReadNum == 0 ) //读文件错误
- {
- return -1;
- }
- WAVEFORMATEX wfSrc;
- memset(&wfSrc, 0, sizeof(wfSrc));
- wfSrc.cbSize = pPcmFMT->dwSize;
- wfSrc.wFormatTag = pPcmFMT->wFormatTag; // pcm
- wfSrc.nChannels = pPcmFMT->wChannels; // mono单声道
- wfSrc.nSamplesPerSec = pPcmFMT->dwSamplesPerSec; // 8000 kHz
- wfSrc.wBitsPerSample = pPcmFMT->uiBitsPerSample; // 8 bit
- wfSrc.nBlockAlign = pPcmFMT->wBlockAlign;
- wfSrc.nAvgBytesPerSec = pPcmFMT->dwAvgBytesPerSec;
- // 选择一个要转换的格式
- WORD wFormatTag = WAVE_FORMAT_ALAW;
- //现在我们选取一个支持目标格式的编码器(CODEC)
- HACMDRIVERID hadid = find_driver(wFormatTag);
- if (hadid == NULL)
- {
- exit(1);
- }
- //显示这个驱动的一些信息
- ACMDRIVERDETAILS dd;
- dd.cbStruct = sizeof(dd);
- mmr = acmDriverDetails(hadid, &dd, 0);
- // 取得格式的详情
- //注意:也许有多个目标格式支持给定的格式,而这只是第一个。
- WAVEFORMATEX* pwfDrv = get_driver_format(hadid, wFormatTag);
- if (pwfDrv == NULL)
- {
- exit(1);
- }
- //取得一个驱动支持的PCM格式标签
- //注意:我们只是选取了第一个支持PCM格式的,也许这个不是最好的选择。
- WAVEFORMATEX* pwfPCM = get_driver_format(hadid, WAVE_FORMAT_PCM);
- if (pwfPCM == NULL)
- {
- exit(1);
- }
- ////////////////////////////////////////////////////////////////////////////////
- //转换源wave到编码器支持的PCM格式
- //我们使用任何可以完成PCM到PCM转换的驱动
- HACMSTREAM hstr = NULL;
- mmr = acmStreamOpen(&hstr,
- NULL, // 任意驱动
- &wfSrc, // 源格式
- pwfPCM, // 目标格式
- NULL, // 无过滤
- NULL, // 无回调
- 0, // 实例数据(未使用)
- ACM_STREAMOPENF_NONREALTIME); // flags
- if (mmr)
- {
- exit(1);
- }
- // 为转换结果开辟一个缓冲区
- int nFileData = (nFileSize - nLen) * 2 - 6000;
- BYTE* pDst1Data = new BYTE [nFileData]; // 填写转换信息
- memset(pDst1Data, 0, nFileData);
- // fill in the conversion info
- ACMSTREAMHEADER strhdr;
- memset(&strhdr, 0, sizeof(strhdr));
- strhdr.cbStruct = sizeof(strhdr);
- strhdr.pbSrc = pSrcData; // the source data to convert
- strhdr.cbSrcLength = nFileSize - nLen;
- strhdr.pbDst = pDst1Data;
- strhdr.cbDstLength = nFileData;
- // prep the header
- mmr = acmStreamPrepareHeader(hstr, &strhdr, 0);
- // convert the data
- mmr = acmStreamConvert(hstr, &strhdr, 0);
- if (mmr)
- {
- exit(1);
- }
- // close the stream
- acmStreamClose(hstr, 0);
- ///////////////////////////////////////////////////////////////////////////////////
- // 将中间格式转换为最终的压缩格式
- // 打开驱动程序
- HACMDRIVER had = NULL;
- mmr = acmDriverOpen(&had, hadid, 0);
- if (mmr)
- {
- exit(1);
- }
-
- // 打开转换流
- // 注意使用了ACM_STREAMOPENF_NONREALTIME标志.
- // 没有此标志一些软件压缩程序会报告512号错误--即不可能
- mmr = acmStreamOpen(&hstr,
- had, // driver handle
- pwfPCM, // source format
- pwfDrv, // destination format
- NULL, // no filter
- NULL, // no callback
- 0, // instance data (not used)
- ACM_STREAMOPENF_NONREALTIME); // flags
- if (mmr)
- {
- exit(1);
- }
- // 为转换结果分配一个缓冲区
- // 根据以字节计的平均速率计算输出缓冲区的尺寸
- // 并加上一机动位(bit)
- // 没有此额外的空间IMA_ADPCM驱动程序将不能转换
- DWORD dwDst2Bytes ;//= pwfDrv->nAvgBytesPerSec * dwDst1Bytes / pwfPCM->nSamplesPerSec;
- //dwDst2Bytes = (nFileSize - nLen) * 3 / 2; // 增加一点空间
- dwDst2Bytes = nFileSize - nLen; // 增加一点空间
- BYTE* pDst2Data = new BYTE [dwDst2Bytes];
- #ifdef _DEBUG
- // 用0填充目标缓冲,由此我们可以在调试中看到转换了的东西
- memset(pDst2Data, 0, dwDst2Bytes);
- #endif
- // 填充转换信息
- ACMSTREAMHEADER strhdr2;
- memset(&strhdr2, 0, sizeof(strhdr2));
- strhdr2.cbStruct = sizeof(strhdr2);
- strhdr2.pbSrc = pDst1Data; // the source data to convert
- strhdr2.cbSrcLength = nFileData;
- strhdr2.pbDst = pDst2Data;
- strhdr2.cbDstLength = dwDst2Bytes;
- // prep the header准备wav头
- mmr = acmStreamPrepareHeader(hstr, &strhdr2, 0);
- // convert the data
- mmr = acmStreamConvert(hstr, &strhdr2, 0);
- if (mmr)
- {
- exit(1);
- }
- fclose(fp);
- // close the stream and driver关闭流和驱动
- mmr = acmStreamClose(hstr, 0);
- mmr = acmDriverClose(had, 0);
- //生成转换完的ccitt格式文件
- fseek(fpCopy, 0, SEEK_SET);
- strcpy(pPcmHEADER->fccID,"RIFF");
- strcpy(pPcmHEADER->fccType,"WAVE");
- pPcmHEADER->dwSize = nWaveFileSize;
- fseek(fpCopy,sizeof(HEADER),1); //跳过HEADER的长度,以便下面继续写入wav文件的数据;
- pPcmFMT->dwSamplesPerSec = 8000;
- pPcmFMT->dwAvgBytesPerSec = 8000;//wfSrc.nAvgBytesPerSec;//pPcmFMT->dwSamplesPerSec * sizeof(DATA);
- pPcmFMT->uiBitsPerSample = 8;
-
- strcpy(pPcmFMT->fccID, "fmt ");
- pPcmFMT->dwSize = wfSrc.cbSize;
- pPcmFMT->wBlockAlign = wfSrc.nBlockAlign;
- pPcmFMT->wChannels = 1;
- pPcmFMT->wFormatTag = WAVE_FORMAT_ALAW;
- //以上是创建wav头的FMT;
-
- fwrite(pPcmFMT,sizeof(FMT),1,fpCopy); //将FMT写入.wav文件;
- WORD nExBit = 0;
- fwrite(&nExBit,2, 1, fpCopy);
- //写入保留两位字节
- //以下是创建wav头的DATA; 但由于DATA.dwsize未知所以不能写入.wav文件
- strcpy(pWaveHeaderData->fccID,"data");
-
- //以上是创建wav头的DATA;
-
- // fwrite(&pcmDATA,sizeof(DATA),1,fpCpy);
- pWaveHeaderData->dwSize = nPcmDataSize; //给pcmDATA.dwsize 0以便于下面给它赋值
- //pWaveHeaderData->dwSize = nFileSize - nLen; //给pcmDATA.dwsize 0以便于下面给它赋值
- fseek(fpCopy,sizeof(DATA),1); //跳过DATA的长度,以便以后再写入wav头的DATA;
- fwrite(pDst2Data, 1, dwDst2Bytes, fpCopy);
-
- pPcmHEADER->dwSize = 46 + nFileSize - nLen; //根据pcmDATA.dwsize得出pPcmHEADER->dwsize的值
-
- rewind(fpCopy); //将fpCpy变为.wav的头,以便于写入HEADER和DATA;
- fwrite(pPcmHEADER,sizeof(HEADER),1,fpCopy); //写入HEADER
- fseek(fpCopy,sizeof(FMT) + 2,1); //跳过FMT,因为FMT已经写入
- fwrite(pWaveHeaderData,sizeof(DATA),1,fpCopy); //写入DATA;
-
- fclose(fpCopy); //关闭文件
- delete[] pDst1Data;
- delete[] pDst2Data;
- delete[] pSrcData;
- delete[] pWaveHeaderData;
- delete[] pPcmFMT;
- delete[] pPcmHEADER;
- return 0;
- }
|