#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;
//……后续略