#pragma once #include <stdio.h> #include <stdlib.h> #include <math.h> #include <limits.h> #include <mmsystem.h> #include <mmreg.h> #include <msacm.h> #include <dsound.h> #pragma comment(lib, "dsound") #pragma comment(lib, "uuid") #pragma comment(lib, "winmm") #pragma comment(lib, "dxguid") static void OutDbgMsg(LPCTSTR format, ...) { TCHAR szMsg[256]; memset(szMsg, 0, sizeof(szMsg)); va_list va; va_start(va, format); _vstprintf_s(szMsg, format, va); va_end(va); _tcscat_s(szMsg, _T("\r\n")); OutputDebugString(szMsg); } template<typename srcDataType>class CDirectSoundPlay { private: HWND m_hWnd; LPDIRECTSOUND gpds; LPDIRECTSOUNDBUFFER pMainDSB; protected: class CDirectSoundPlayBuffer { protected: LPDIRECTSOUNDBUFFER pDSB; LPDIRECTSOUND lgpds; HRESULT Release() { HRESULT hr = Stop(); if(pDSB != NULL) { IDirectSoundBuffer_Release(pDSB); pDSB = NULL; } return hr; } public: CDirectSoundPlayBuffer(LPDIRECTSOUND gpds) { lgpds = gpds; pDSB = NULL; } virtual ~CDirectSoundPlayBuffer() { Release(); } public: HRESULT Play(BOOL bLoop) { HRESULT hr = DSERR_INVALIDCALL; if(pDSB != NULL) { hr = IDirectSoundBuffer_Play(pDSB, 0, 0, bLoop ? DSBPLAY_LOOPING : 0); if(hr != DS_OK) { OutDbgMsg(_T("Failed to DirectSoundBuffer Play (%ld)"), hr); } } return hr; } HRESULT Stop() { HRESULT hr = DS_OK; if(pDSB != NULL) { hr = IDirectSoundBuffer_Stop(pDSB); if(hr != DS_OK) { OutDbgMsg(_T("Failed to DirectSoundBuffer Stop (%ld)"), hr); } } return hr; } HRESULT CreateDSoundBuffer(srcDataType *pChnL, srcDataType *pChnR, LONG iSampFreq, LONG iPtLength, double fGain=1) { HRESULT hr = S_OK; if(hr == S_OK) { hr = Release(); } //检查参数 if(hr == S_OK) { if(!(pChnL || pChnR) || iPtLength <= 0 || iSampFreq < DSBFREQUENCY_MIN || iSampFreq > DSBFREQUENCY_MAX) { OutDbgMsg(_T("Invalid Param")); hr = DSERR_INVALIDPARAM; } } //检查gpds是否有效 if(hr == S_OK) { if(lgpds == NULL) { OutDbgMsg(_T("lgpds Can't be empty")); hr = DSERR_UNINITIALIZED; } } DWORD cbSize = iPtLength * 2 * 2; //数据总长度 (字节 = N × 两声道 × 16位) if(hr == S_OK) { WAVEFORMATEX waveFormatEx; { LPWAVEFORMATEX pwfx = &waveFormatEx; memset(pwfx, 0, sizeof(WAVEFORMATEX)); pwfx->wFormatTag = WAVE_FORMAT_PCM; pwfx->nChannels = 2; //两通道 pwfx->nBlockAlign = 4; pwfx->wBitsPerSample = 16; //16位 pwfx->nSamplesPerSec = 44100; //采样频率(PCM) //8.0kHz, 11.025kHz 22.05kHz 44.1 kHz pwfx->nAvgBytesPerSec = pwfx->nSamplesPerSec * pwfx->nChannels * pwfx->wBitsPerSample/8; //每秒钟数据量(字节) pwfx->cbSize = 0; //后续扩展数据 } // Set up the direct sound buffer. DSBUFFERDESC dsbd; { memset(&dsbd, 0, sizeof(dsbd)); dsbd.dwSize = sizeof(dsbd); dsbd.dwFlags = 0; dsbd.dwFlags |= DSBCAPS_STATIC; dsbd.dwFlags |= DSBCAPS_CTRLPAN; dsbd.dwFlags |= DSBCAPS_CTRLPAN; dsbd.dwFlags |= DSBCAPS_CTRLVOLUME; dsbd.dwFlags |= DSBCAPS_CTRLFREQUENCY; dsbd.dwFlags |= DSBCAPS_GETCURRENTPOSITION2; dsbd.dwFlags |= DSBCAPS_STICKYFOCUS; dsbd.dwBufferBytes = cbSize; dsbd.lpwfxFormat = &waveFormatEx; } hr = IDirectSound_CreateSoundBuffer(lgpds, &dsbd, &pDSB, NULL ); if(hr != DS_OK || pDSB == NULL) { OutDbgMsg(_T("Failed to Create play SoundBuffer (%ld)"), hr); if(pDSB == NULL) hr = S_FALSE; } } BYTE *pbData = NULL, *pbData2 = NULL; DWORD dwLength = 0, dwLength2 = 0; // Ok, lock the sucker down if(hr == S_OK) { hr = IDirectSoundBuffer_Lock(pDSB, 0, cbSize, (LPVOID*)&pbData, &dwLength, (LPVOID*)&pbData2, &dwLength2, 0L); if(hr == S_OK) { if(pbData != NULL && dwLength > 0) memset(pbData, 0, dwLength); } else { OutDbgMsg(_T("Failed to SoundBuffer_Lock (%ld)"), hr); } } //create wave data memory if(hr == S_OK) { LONG dwPt = (LONG)min((DWORD)iPtLength, dwLength/4); typedef struct _WAVEDATA { SHORT chnL; SHORT chnR; }WAVEDATA, *LPWAVEDATA; LPWAVEDATA pWaveData = (LPWAVEDATA)pbData; double valL, valR; for(LONG i=0; i<dwPt; i++) { valL = valR = 0; #define CutShort(v) ( (v)>SHRT_MAX ? SHRT_MAX : ((v)<SHRT_MIN ? SHRT_MIN : (v)) ) if(pChnL && pChnR) { valL = CutShort(pChnL[i] * fGain); valR = CutShort(pChnR[i] * fGain); } else if(pChnL) { valL = valR = CutShort(pChnL[i] * fGain); } else if(pChnR) { valL = valR = CutShort(pChnR[i] * fGain); } else { } pWaveData[i].chnL = (SHORT)valL; pWaveData[i].chnR = (SHORT)valR; } } // Ok, now unlock the buffer, we don't need it anymore. if(pDSB && pbData) { HRESULT hr2 = IDirectSoundBuffer_Unlock(pDSB, pbData, cbSize, NULL, 0); if(hr2 != S_OK) { OutDbgMsg(_T("Falied to SoundBuffer_Unlock (%ld)"), hr); hr = hr2; } } //最大音量 if(hr == S_OK) { hr = IDirectSoundBuffer_SetVolume(pDSB, DSBVOLUME_MAX); if(hr != S_OK) OutDbgMsg(_T("Failed to SoundBuffer_SetVolume (%ld)"), hr); } //左右声道平衡 if(hr == S_OK) { hr = IDirectSoundBuffer_SetPan(pDSB, DSBPAN_CENTER); if(hr != S_OK) OutDbgMsg(_T("Failed to SoundBuffer_SetPan (%ld)"), hr); } //新采样频率 if(hr == S_OK) { hr = IDirectSoundBuffer_SetFrequency(pDSB, iSampFreq);//= DSBFREQUENCY_ORIGINAL) if(hr != S_OK) OutDbgMsg(_T("Falied to SoundBuffer_SetFrequency (%ld)"), hr); } // if(hr == S_OK) { DSBCAPS dsbc; memset(&dsbc, 0, sizeof(dsbc)); dsbc.dwSize = sizeof(dsbc); hr = IDirectSoundBuffer_GetCaps(pDSB, &dsbc); if(hr != S_OK) { OutDbgMsg(_T("Failed to IDirectSoundBuffer_GetCaps (%ld)"), hr); } if (dsbc.dwFlags & DSBCAPS_LOCHARDWARE) { //hardware support } else { //support } } if(hr != S_OK) Release(); return hr; } }; protected: typedef struct _DsndBuffer_t { CDirectSoundPlayBuffer *pDsndBuffer; _DsndBuffer_t *pNext; _DsndBuffer_t(LPDIRECTSOUND gpds=NULL) { pDsndBuffer = new CDirectSoundPlayBuffer(gpds); pNext = NULL; } ~_DsndBuffer_t() { if(pDsndBuffer) { delete pDsndBuffer; pDsndBuffer = NULL; } } HRESULT Stop() { return pDsndBuffer ? pDsndBuffer->Stop() : DSERR_INVALIDCALL; } HRESULT Play(BOOL bLoop) { return pDsndBuffer ? pDsndBuffer->Play(bLoop) : DSERR_INVALIDCALL; } }DSNDBUFFER; DSNDBUFFER m_DsndBufferRoot; public: HRESULT ReleaseDsndBuffer() { Stop(); while(m_DsndBufferRoot.pNext != NULL) { _DsndBuffer_t *pNode = m_DsndBufferRoot.pNext; m_DsndBufferRoot.pNext = pNode->pNext; delete pNode; } return DS_OK; } HRESULT Stop(int iIndex = -1) { int iPos=0; _DsndBuffer_t *pNode = m_DsndBufferRoot.pNext; while(pNode != NULL) { if(iIndex < 0 || iPos == iIndex) pNode->Stop(); pNode = pNode->pNext; } return DS_OK; } HRESULT Play(BOOL bLoop, int iIndex = -1) { int iPos = 0; _DsndBuffer_t *pNode = m_DsndBufferRoot.pNext; while(pNode != NULL) { if(iIndex < 0 || iPos == iIndex) pNode->Play(bLoop); pNode = pNode->pNext; } return DS_OK; } HRESULT AddDSoundBuffer(srcDataType *pChnL, srcDataType *pChnR, DWORD uSampFreq, DWORD uPtLength, double fGain=1) { HRESULT hr = DS_OK; if(gpds == NULL) { hr = DSERR_UNINITIALIZED; OutDbgMsg(_T("gpds not valid")); } if(hr == DS_OK) { _DsndBuffer_t *pNewNode = new _DsndBuffer_t(gpds); hr = pNewNode->pDsndBuffer->CreateDSoundBuffer(pChnL, pChnR, uSampFreq, uPtLength, fGain); if(hr == DS_OK) { _DsndBuffer_t *pNode = &m_DsndBufferRoot; while(pNode->pNext) pNode = pNode->pNext; //找到最后一个节点 pNode->pNext = pNewNode; //连接到尾部 } else { delete pNewNode; } } return hr; } public: CDirectSoundPlay() { //initialize m_hWnd = NULL; gpds = NULL; pMainDSB = NULL; } virtual ~CDirectSoundPlay() { //Free All List ReleaseDsndBuffer(); // Destroy the direct sound buffer. if(pMainDSB != NULL) { IDirectSoundBuffer_Stop(pMainDSB); IDirectSoundBuffer_Release(pMainDSB); pMainDSB = NULL; } //Destroy the direct sound object. if (gpds != NULL) { IDirectSound_Release(gpds); gpds = NULL; } CoUninitialize(); } public: HRESULT Initilaize(HWND hWnd) { HRESULT hr = S_OK; m_hWnd = hWnd; //initialize COM library if(hr == S_OK) { hr = CoInitialize(NULL); if (!SUCCEEDED(hr)) { OutDbgMsg(_T("Failed to initialize COM library(%ld)"), hr); } } //Create the direct sound object if(hr == S_OK) { // Create the direct sound object. hr = CoCreateInstance(CLSID_DirectSound, NULL, CLSCTX_INPROC_SERVER, IID_IDirectSound, (void **)&gpds); if(hr != S_OK || gpds == NULL) { OutDbgMsg(_T("Failed to Initialize DirectSound object(%ld)"), hr); if(hr == S_OK) hr = S_FALSE; } } //initializes the DirectSound object if(hr == S_OK) { hr = IDirectSound_Initialize(gpds, NULL); if(hr != DS_OK) { OutDbgMsg(_T("Failed to initializes the DirectSound object(%ld)"), hr); } } //SetCooperativeLevel if(hr == S_OK) { hr = IDirectSound_SetCooperativeLevel(gpds, m_hWnd, DSSCL_PRIORITY); if(hr != DS_OK) { OutDbgMsg(_T("Failed to SetCooperativeLevel (%ld)"), hr); } } //Create primary buffer if (hr == S_OK) { DSBUFFERDESC dsbd; memset(&dsbd, 0, sizeof(dsbd)); // Set up the primary direct sound buffer. ZeroMemory(&dsbd, sizeof(dsbd)); dsbd.dwSize = sizeof(dsbd); dsbd.dwFlags = DSBCAPS_PRIMARYBUFFER; hr = IDirectSound_CreateSoundBuffer(gpds, &dsbd, &pMainDSB, NULL); if(hr != DS_OK || pMainDSB == NULL) { OutDbgMsg(_T("Cannot Create primary buffer (%ld)"), hr); if(hr != DS_OK) hr = S_FALSE; } } //specifies the speaker configuration if(hr == S_OK) { hr = IDirectSound_SetSpeakerConfig(gpds, DSSPEAKER_STEREO); if(hr != DS_OK) { OutDbgMsg(_T("Failed to Specifies the speaker configuration (%ld)"), hr); } } //Play primary buffer if(hr == S_OK) { hr = IDirectSoundBuffer_Play(pMainDSB, 0, 0, DSBPLAY_LOOPING); if(hr != DS_OK) { OutDbgMsg(_T("Cannot play primary buffer (%ld)"), hr); } } return hr; } public: LPDIRECTSOUND Get_gpds() { return gpds; } };
CDirectSoundPlay <double> dsd; LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) { //…… switch (message) { case WM_CREATE: //播放2秒钟纯音数据 if(dsd.Initilaize(hWnd) == S_OK) { DWORD uSampFreq = 100000U; //采样频率 DWORD dwPtLen = (DWORD)(uSampFreq * 2.0); //2秒采样 double *pBuffL = new double [dwPtLen]; double fAngle = 0, fGain = SHRT_MAX,//SHRT_MAX, dAngle = 1000.0 * (atan(1.0) * 8.0) / (double)uSampFreq; //正弦波 2πf/fs for(DWORD i=0; i<dwPtLen; i++) { pBuffL[i] = fGain * sin(fAngle); fAngle += dAngle; } dsd.AddDSoundBuffer(pBuffL, NULL, uSampFreq, dwPtLen); delete []pBuffL; dsd.Play(false); } break; //……后续略