[DirectSound] 基于DirectSound的音频均衡器实现

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/felicityWSH/article/details/70230041
什么是音频均衡器?

通过均衡器 可以让声音达到不同的听觉效果:古典、爵士、流行、增强重低音、摇滚等等。如图是酷狗音乐播放器的均衡器界面:


在讨论均衡器的实现原理之前 先要介绍几个音频相关的名词:

频率
声音在一个周期的震动次数 单位是赫兹(hz)不同频率的声音 其音色是不一样的,频率越低声音就越低沉
人的耳朵能听到的频繁范围是20Hz~20000Hz

音色
不同频率的声音 听起来有不同的听觉感受
频段
以某个频率为中心、向两边延伸的频率范围 称之为频段
增益

标识衰减或增强声音的大小。单位是db,0代表不衰减也不增强,每6db为一个声压级,即6db标识声音增大一倍,-6db标识声音衰减到原来的一半

均衡器的实现原理  通过设置特定频段的增益,达到不同的播放效果。比如前面那张图片 是酷狗的古典效果设置图 从图中可以知道需要设置的各频段及增益值为:

60 hz为中心的频段:增益为 0db
170 hz为中心的频段:增益为 0db
370 hz为中心的频段:增益为 0db
600 hz为中心的频段:增益为 0db
1000 hz为中心的频段:增益为 0db
3000 hz为中心的频段:增益为 0db
6000 hz为中心的频段:增益为 -4db
12000 hz为中心的频段:增益为 -4db
14000 hz为中心的频段:增益为 -4db
1500 hz为中心的频段:增益为 -6db

如何通过DirectSound设置这些参数?使用DirectSound中的结构体:

typedef struct _DSFXParamEq
{
    FLOAT   fCenter;
    FLOAT   fBandwidth;
    FLOAT   fGain;
} DSFXParamEq, *LPDSFXParamEq;
FLOAT   fCenter;       中心频率,单位hz,取值范围是20Hz~20000Hz
FLOAT   fBandwidth;    频宽, 表示以fCenter为中心向两边延伸这么多的一个频段 取值范围是 1.0f~36.0f, 通常用12
FLOAT   fGain;         增益值 单位db,取值范围 -15.fdb~15.fdb, 0表示原音 建议不大于12db或小于-12db 否则会有杂音

DSound中有一个类 LPDIRECTSOUNDFXPARAMEQ8  可以用这个类 设置各频段的增益,以下是相关的代码

头文件中声明了如下数据成员:

IDirectSound8* m_pDS8;
IDirectSoundBuffer8* m_pDSBuffer8;
LPDIRECTSOUNDFXPARAMEQ8	m_pParamEQ8; // 用来设置频段的增益

注意:如果想使用均衡器功能 初始化DSound对象时 需要包含标识符DSBCAPS_CTRLFX,以下是初始化DSound的函数:

BOOL CDSoundPlayer::Init(HWND hWnd, int nSampleRate, int nChannel, int nBitsPerSample)
{
	assert(!m_bInited);

	IDirectSoundBuffer*	pDSBuffer = NULL;
	IDirectSoundNotify8* pDSNotify = NULL;
	 
	do 
	{
		BREAK_IF_FAILED(DirectSoundCreate8(NULL, &m_pDS8, NULL));
		BREAK_IF_FAILED(m_pDS8->SetCooperativeLevel(hWnd, DSSCL_PRIORITY));

		DSBUFFERDESC desc = {};
		WAVEFORMATEX wf = {};
		desc.dwSize = sizeof(desc);
		desc.dwFlags = DSBCAPS_GLOBALFOCUS | DSBCAPS_CTRLPOSITIONNOTIFY | DSBCAPS_GETCURRENTPOSITION2 | DSBCAPS_CTRLFX | DSBCAPS_CTRLVOLUME;
		desc.dwBufferBytes = MAX_AUDIO_BUF * BUFFERNOTIFYSIZE;
		desc.lpwfxFormat = &wf;
		desc.lpwfxFormat->wFormatTag = WAVE_FORMAT_PCM;
		desc.lpwfxFormat->nChannels = nChannel;
		desc.lpwfxFormat->nSamplesPerSec = nSampleRate;
		desc.lpwfxFormat->nAvgBytesPerSec = nSampleRate * (nBitsPerSample / 8) * nChannel;
		desc.lpwfxFormat->nBlockAlign = (nBitsPerSample / 8) * nChannel;
		desc.lpwfxFormat->wBitsPerSample = nBitsPerSample;

		// 如果要使用DSound的某个功能 设置desc.dwFlags时 需要包含对应的标识符
		BREAK_IF_FAILED(m_pDS8->CreateSoundBuffer(&desc, &pDSBuffer, NULL));
		BREAK_IF_FAILED(pDSBuffer->QueryInterface(IID_IDirectSoundBuffer8, (LPVOID*)&m_pDSBuffer8));
	
		// 设置事件通知
		ResetEvents();
		DSBPOSITIONNOTIFY aDSPosNotify[MAX_AUDIO_BUF] = {};
		for (int i = 0; i < MAX_AUDIO_BUF; i++)
		{ 
			aDSPosNotify[i].dwOffset = i * BUFFERNOTIFYSIZE;
			aDSPosNotify[i].hEventNotify = m_hEvents[i];
		}
		BREAK_IF_FAILED(m_pDSBuffer8->QueryInterface(IID_IDirectSoundNotify, (LPVOID*)&pDSNotify));
		BREAK_IF_FAILED(pDSNotify->SetNotificationPositions(MAX_AUDIO_BUF, aDSPosNotify));

		// 获取均衡器对象
		DWORD dwResult;
		DSEFFECTDESC effectdesc = {};
		effectdesc.dwSize = sizeof(DSEFFECTDESC);
		effectdesc.dwFlags = 0;
		effectdesc.guidDSFXClass = GUID_DSFX_STANDARD_PARAMEQ;
		BREAK_IF_FAILED(m_pDSBuffer8->SetFX(1, &effectdesc, &dwResult));
		BREAK_IF_FAILED(m_pDSBuffer8->GetObjectInPath(GUID_DSFX_STANDARD_PARAMEQ, 0, IID_IDirectSoundFXParamEq8, (LPVOID*)&m_pParamEQ8));

		m_bInited = TRUE;
		return TRUE;
	} while (0);

	SAFE_DELETE_COM(pDSBuffer);
	SAFE_DELETE_COM(pDSNotify);

	SAFE_DELETE_COM(m_pParamEQ8);
	SAFE_DELETE_COM(m_pDSBuffer8);
	SAFE_DELETE_COM(m_pDS8);

	return FALSE;
}

设置频段增益的函数:
BOOL CDSoundPlayer::SetEQ(float fFrequency, float fBandWidth, float fGain)
{
	assert(m_pParamEQ8);
	if (!m_pParamEQ8)
		return FALSE;

	DSFXParamEq paramsParamEq;
	paramsParamEq.fCenter = fFrequency;
	paramsParamEq.fBandwidth = fBandWidth;
	paramsParamEq.fGain = fGain;

	return SUCCEEDED(m_pParamEQ8->SetAllParameters(&paramsParamEq)); 
}
如果要设置前面酷狗的古典效果 函数调用如下:
	CDSoundPlayer player;
	player->Init(....); // 初始化DSound

	player->SetEQ(60, 12, 0); 
	player->SetEQ(170, 12, 0);
	player->SetEQ(370, 12, 0);
	player->SetEQ(600, 12, 0);
	player->SetEQ(1000, 12, 0);
	player->SetEQ(3000, 12, 0);
	player->SetEQ(6000, 12, -4);
	player->SetEQ(12000, 12, -4);
	player->SetEQ(14000, 12, -4);
	player->SetEQ(15000, 12, -6); 

	player->Play();

是不是很简单?其他均衡器效果的各频段增益值 大家可参考酷狗或者qq音乐,也可以自行在网上搜索。

DSound还有其他很多稀奇古怪的特效 大家可参考这里自己尝试去实现这些功能。

猜你喜欢

转载自blog.csdn.net/felicityWSH/article/details/70230041