#include "PcmPlayer.h" //#define LENGTH 10240 BOOL getOutNumDrive()//音频数量 { int count = waveOutGetNumDevs(); return count < 1 ? FALSE : TRUE;//1 音频输入数量 } BOOL getOutDevCaps() { WAVEOUTCAPS waveOutcaps; int i = 0; MMRESULT mmResult; mmResult = waveOutGetDevCaps(0, &waveOutcaps, sizeof(WAVEINCAPS));//2 设备描述 if (MMSYSERR_NOERROR != mmResult) { return FALSE; } return TRUE; } BOOL openOutFile(const TCHAR *cFileName, FILE **fp) { FILE *fpRead = NULL; fpRead = fopen(cFileName, "rb"); if (NULL == fpRead) { fp = NULL; return FALSE; } *fp = fpRead; fclose(fpRead); return TRUE; } BOOL initOutDrive()//BOOL initDrive(const TCHAR * cFileName) { if (FALSE == getOutNumDrive()) { return FALSE; } //if (FALSE == getOutDevCaps()) //{ // return FALSE; //} return TRUE; } BOOL openOutPcm(LPHWAVEOUT phwo, LPCWAVEFORMATEX pwfx, DWORD_PTR dwCallback) { if (MMSYSERR_NOERROR != waveOutOpen(0, 0, pwfx, 0, 0, WAVE_FORMAT_QUERY)) { //fprintf(stderr, "不支持文件格式!\n"); return FALSE; } if (MMSYSERR_NOERROR != waveOutOpen(phwo, WAVE_MAPPER, pwfx, 0, 0, CALLBACK_NULL)) { //fprintf(stderr, "文件打开失败!\n"); return FALSE; } return TRUE; } LPSTR loadOutAudioBlock(const TCHAR * filename, DWORD* blockSize) { HANDLE hFile = INVALID_HANDLE_VALUE; DWORD size = 0; DWORD readBytes = 0; void* block = NULL; //LPCWSTR name = L"D:\\sdktest\\config\\ttsTest1.pcm"; if ((hFile = CreateFile(filename, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL)) == INVALID_HANDLE_VALUE) { int rest = GetLastError(); return NULL; } do { if ((size = GetFileSize(hFile, NULL)) == 0) { break; } if ((block = HeapAlloc(GetProcessHeap(), 0, size)) == NULL) { break; } ReadFile(hFile, block, size, &readBytes, NULL); } while (0); CloseHandle(hFile); *blockSize = size; return (LPSTR)block; } BOOL writeOutAudioBlock(HWAVEOUT phwo, LPSTR block, DWORD size) { WAVEHDR wHdr = { 0 }; wHdr.dwBufferLength = size; wHdr.lpData = block; if (MMSYSERR_NOERROR != waveOutPrepareHeader(phwo, &wHdr, sizeof(WAVEHDR))) { //fprintf(stderr, "文件缓冲区准备失败!\n"); return FALSE; } if (MMSYSERR_NOERROR != waveOutWrite(phwo, &wHdr, sizeof(WAVEHDR))) { //fprintf(stderr, "写文件缓冲区失败!\n"); return FALSE; } Sleep(500); while (WAVERR_STILLPLAYING == waveOutUnprepareHeader(phwo, &wHdr, sizeof(WAVEHDR))) { Sleep(100); } return TRUE; } BOOL closeOutAudioBlock(HWAVEOUT phwo) { if (MMSYSERR_NOERROR != waveOutClose(phwo)) { //fprintf(stderr, "写文件缓冲区失败!\n"); return FALSE; } return TRUE; } int playPcmFile(const char * cFileName) { //int iLength; //TCHAR * tcharName=""; //iLength = MultiByteToWideChar(CP_ACP, 0, cFileName, strlen(cFileName) + 1, NULL, 0); //MultiByteToWideChar(CP_ACP, 0, cFileName, strlen(cFileName) + 1, tcharName, iLength); //char strUsr[10] = "Hello"; TCHAR tcharName[100]; #ifdef UNICODE MultiByteToWideChar(CP_ACP, 0, cFileName, -1, tcharName, 100); #else strcpy(tcharName, cFileName); #endif LPSTR block; DWORD blockSize; if (NULL == (block = loadOutAudioBlock(tcharName, &blockSize))) { fprintf(stderr, "文件初始化失败!\n"); return -1; } if (FALSE == initOutDrive(tcharName)) { fprintf(stderr, "设备初始化失败!\n"); return -1; } WAVEFORMATEX pwfx = { WAVE_FORMAT_PCM,// wFormatTag,格式标志 1, // nChannels,通道数,单声道数据用单通道,立体声通道用双通道 16000, // nSamplesPerSec,采样率(HZ),每秒钟采取样本的次数 32000, // nAvgBytesPerSec,每秒转换数据的字节数,for WAVE_FORMAT_PCM,nAvgBytesPerSec = nSamplesPerSec * nBlockAlign,此处的大小与waveInOopen回调函数中写入数据的大小应该一直,否则会出现问题 2, // nBlockAlign,每个样本的字节数,for WAVE_FORMAT_PCM,nBlockAlign = (nChannels × wBitsPerSample) / 8 16, // wBitsPerSample,每个样本的位数,for WAVE_FORMAT_PCM,wBitsPerSample必须等于8或者16 0 // cbSize,附加在该结构体后面的格式信息的大小 }; HWAVEOUT phwo; if (FALSE == openOutPcm(&phwo, &pwfx, NULL)) { fprintf(stderr, "文件打开失败!\n"); return -1; } if (FALSE == writeOutAudioBlock(phwo, block, blockSize)) { fprintf(stderr, "写音频设备失败!\n"); return -1; } if (FALSE == closeOutAudioBlock(phwo)) { fprintf(stderr, "关闭音频设备失败!\n"); return -1; } return 0; }