| |
用DirectSound实现增强的音频特技效果 |
|
时间: 2005-12-28 来自:天极开发 |
 |
|
摘要
:本文介绍了DirectSound提供的几个基本的音频特技以及其应用方法,并通过一个程序实例演示了如何应用这些特技为你的程序实现增强的音频效果。
关键词:
DirectSound 音频特技
前段时间写三篇关于DirectSound的文档,包括录音,混音,以及3D音效,也基本上将DirectSound的开发主要内容涉及到了,因为关于特技这部分在DirectSound的开发文档中介绍的就很简单,加上应用起来也不是很难,本来不想介绍这部分的内容,但是,当我体验过DirectSound的音频特技后,我改变了想法,我觉得DirectSound提供的几个音频特技效果很好,很有震撼力,如果你将这些特技添加到你的程序中,肯定能为你的程序增色不少,况且,接口这么简单,应用起来这么容易。所以这篇文档我给大家介绍一下DirectSound的基本特技。
DirectSound提供8个基本的音频特技。
1、Chorus
和声,这里说的和声不是指很多人合唱,而是指声音的重叠,即通过原声和回声的重叠,使得声音加宽,加厚。
2、Compression
压限,是针对声音不同部分的音量进行增减也就是说,可以对某段音频中音量低于某一限度的部分进行平滑的音量提升(其余部分不变);对音量高于某一限度的部分进行平滑的音量衰减(其余部分不变),或二者同时作用,简单说,就是平衡音量。
3、Distortion
失真。
4、Echo 回声,模拟声音被远处的平面反射回来的效果。
5、Environmental
Reverberation反射(混响),简单说就是声音余韵,音源在空间反射出来的声音。适当设置混响,可以更真实、更有现场感的再现声音源,也可以起到修饰、美化的作用。表现宽阔的,传声真实的效果。
6、Flange,一般翻译为波浪特技,用于设置变调效果,通过拷贝失调的声音,或者把某个频率点改变,调节声音分离的时间、音调深度。可以用来产生颤动、急促的声音。
7、Gargle
,咕噜效果处理。一种可以试音源产生咕噜声的调幅处理模式。
8、Parametric
Equalizer参数平衡,用于为音频设置参数均衡器。强化或衰减指定的频率。对于增强音乐的效果特别有效。
DiectSound对于每一种特技,都提供了一个接口
,通过这个接口,我们可以调整特技的参数,接口定义如下:
·IDirectSoundFXChorus8
和声特技接口
·IDirectSoundFXCompressor8
压限特技接口
·IDirectSoundFXDistortion8 失真特技接口
·IDirectSoundFXEcho8
回声特技接口
·IDirectSoundFXWavesReverb8混响特技接口
·IDirectSoundFXFlanger8 波浪特技接口
·IDirectSoundFXGargle8
咕噜特技接口
·IDirectSoundFXParamEq8
参数平衡特技接口
我们可以通过DirectSound缓冲区接口,即IDirectSoundBuffer8的GetObjectInPath方法获得所支持音频特技的接口。
下面先说一下DirectSound中的音频特技实现的过程。
1、首先创建
DirectSound对象和辅助缓冲区,辅助缓冲区一定要设置DSBCAPS_CTRLFX标志。
2、通过辅助缓冲区buffer即IDirectSoundBuffer8的SetFX方法设置特效;
3、IDirectSoundBuffer8的GetObjectInPath方法获得特效的接口;
4、特效接口的SetAllParameters方法设置参数;
5、然后就是通过缓冲区的play方法来播放音频文件。在播放音频的同时我们也可以调整特技的参数。
下面开始我们的例子吧,关于例子的界面很简单,都是通过MFC
自动提供的,我没有做什么修饰,呵呵,我们只关心功能,所以其他的我就不详细讲,具体你可以参见例子代码,例子的源码会随着本文一起发布,例子的界面如下
 图
音频特技的示例 | 界面很简单,流程也不复杂,我在这里主要是用来演示如何来实现音频特技的,所以下面我们一起看看如何来实现音频的特技。这里我要说明一下,因为8个特技实现过程基本是一样,所以我这里只是以chorus(回声)特技
举例,其他特技的实现和chorus类似,避免代码重复,就不一一列出,具体的可以参见例子的源码。
第1步:
首先要定义我们用到的一些变量,这里我定义的全是全局的变量,你可以根据自己的情况来定义这些变量。
LPDIRECTSOUNDBUFFER8 g_pDSBuffer8 = NULL; //缓冲区对象 LPDIRECTSOUND8
g_pDsd = NULL; ///Directsound对象 CWaveFile *g_pWaveFile= NULL; //
操作wave文件的 对象 //下面的8个指针接口对应着8个音频特技 LPDIRECTSOUNDFXCHORUS8 g_pChorus =
NULL; LPDIRECTSOUNDFXCOMPRESSOR8 g_pCompressor =
NULL; LPDIRECTSOUNDFXDISTORTION8 g_pDistortion =
NULL; LPDIRECTSOUNDFXECHO8 g_pEcho = NULL; LPDIRECTSOUNDFXFLANGER8
g_pFlanger = NULL; LPDIRECTSOUNDFXGARGLE8 g_pGargle =
NULL; LPDIRECTSOUNDFXPARAMEQ8 g_pParamEq =
NULL; LPDIRECTSOUNDFXWAVESREVERB8 g_pReverb =
NULL; //用于设置特技的参数,每种音频特技对应着一个参数。 DSFXChorus
g_paramsChorus; DSFXCompressor g_paramsCompressor; DSFXDistortion
g_paramsDistortion; DSFXEcho g_paramsEcho; DSFXFlanger
g_paramsFlanger; DSFXGargle g_paramsGargle; DSFXParamEq
g_paramsParamEq; DSFXWavesReverb
g_paramsReverb; | 定义完这些变量,就可以开始我们的工作了
第2步
初始化Directsound,获取IDrectSoundBuffer8的接口。这一步骤的工作可以放到程序的初始化的地方。
CoInitialize( NULL ); HRESULT hr; if(FAILED(hr =
DirectSoundCreate8(NULL,&g_pDsd,NULL))) return
FALSE; if(FAILED(hr =
g_pDsd->SetCooperativeLevel(m_hWnd,DSSCL_PRIORITY))) return
FALSE; // for(int i =0; i< MAX_AUDIO_BUF; i++) g_event[i] =
CreateEvent(NULL, FALSE, FALSE, NULL); //设置音频的格式 WAVEFORMATEX
waveformat; waveformat.wFormatTag =
WAVE_FORMAT_PCM; waveformat.nChannels = 2; waveformat.nSamplesPerSec
= 48000; waveformat.wBitsPerSample = 16; waveformat.nBlockAlign =
waveformat.nChannels * waveformat.wBitsPerSample
/8; waveformat.nAvgBytesPerSec = waveformat.nBlockAlign *
waveformat.nSamplesPerSec;
DSBUFFERDESC dsbd; ZeroMemory(
&dsbd, sizeof(DSBUFFERDESC) ); dsbd.dwSize =
sizeof(DSBUFFERDESC); dsbd.dwFlags = DSBCAPS_GLOBALFOCUS |
DSBCAPS_CTRLFX| DSBCAPS_CTRLPOSITIONNOTIFY
|DSBCAPS_GETCURRENTPOSITION2; //
创建缓冲区的时候,一定不要忘了设置DSBCAPS_CTRLFX标志 dsbd.dwBufferBytes = MAX_AUDIO_BUF *
BUFFERNOTIFYSIZE ; dsbd.lpwfxFormat =
&waveformat; LPDIRECTSOUNDBUFFER lpbuffer; if(FAILED(hr =
g_pDsd->CreateSoundBuffer(&dsbd,&lpbuffer,NULL))) return
FALSE;
if( FAILED( hr = lpbuffer->QueryInterface(
IID_IDirectSoundBuffer8, (LPVOID*) &g_pDSBuffer8) ) ) return
FALSE;
lpbuffer->Release(); | 需要注意的几个地方:
·DirectX通过DirectX
Media
Objects(DMOs)来支持在声音中添加特技。因为特技使用到了COM组件,所以首先要通过CoInitialize()来初始化Com库,当然,你别忘了在退出程序时调用CoUninitialize()
。
·创建缓冲区的时候,一定不要忘了对
DSBUFFERDESC结构的dwFlages设置DSBCAPS_CTRLFX标志,如果忘了设置这个标志,那么你后面的音频特技全是无效的。但是,在设置这个标志时,buffer一定要处于停止状态并且没有被锁定。在DiectX
9.0中,特技不是依靠硬件来实现的。当然也可以在硬件缓冲区中设置特技,但这样做没有任何的好处。
·最后一个要注意的问题,就是缓冲区的大小,缓冲区的size过小,特技并不能好好工作,DirectSound建议缓冲区的大小应该在小于150毫秒的数据数据量,缓冲区中使用特技,这个值被定义为DSBSIZ_FX_MIN。
在上面的例子中,waveformat.nAvgBytesPerSec
= waveformat.nBlockAlign * waveformat.nSamplesPerSec; = 2*16*4800/8 = 19200
bytes/m
那么dsbd.dwBufferBytes 的最小值应该大于 19200*0.15 =
2880字节。
我刚开始就没有注意这个问题,结果后面总是出错,我一直纳闷不已,因为代码没有问题的,后来重新看了一下帮助才发现这个问题。
第3步 通过缓冲区对象IDirectSoundBuffer8设置缓冲区支持的具体特技,并通过IDirectSoundBuffer8
对象的GetObjectInPath方法获得具体的音频特技的接口;这里以chorus特技为例:如下
DSEFFECTDESC effectdesc; ZeroMemory( &effectdesc, sizeof(
DSEFFECTDESC ) ); effectdesc.dwSize =
sizeof(DSEFFECTDESC); effectdesc.dwFlags =
0; effectdesc.guidDSFXClass = GUID_DSFX_STANDARD_CHORUS; DWORD
dwResult; if(g_pDSBuffer8) { hr =
g_pDSBuffer8->SetFX(1,&effectdesc,&dwResult); if( FAILED(
hr = g_pDSBuffer8->GetObjectInPath( GUID_DSFX_STANDARD_CHORUS, 0,
IID_IDirectSoundFXChorus8,(LPVOID*) &g_pChorus ) ) ) return
; g_pChorus->GetAllParameters(&g_paramsChorus); } | 第4步
通过特效接口的SetAllParameters方法设置参数,手动拖动滑动条,来设置特技参数,可以在例子中看到如下的代码,以chorus为例:
void CDsoundEffectDemoDlg::OnEffectChanged() { switch(
g_dwCurrentFXType ) { case
eSFX_chorus: { //下面的代码主要是为了获取滑动条上参数的数值。 SaveSingleParameter(
IDC_PARAM_NAME1, &g_paramsChorus.fWetDryMix, DSFXCHORUS_WETDRYMIX_MIN,
DSFXCHORUS_WETDRYMIX_MAX ); SaveSingleParameter( IDC_PARAM_NAME2,
&g_paramsChorus.fDepth, DSFXCHORUS_DEPTH_MIN, DSFXCHORUS_DEPTH_MAX
); SaveSingleParameter( IDC_PARAM_NAME3,
&g_paramsChorus.fFeedback, DSFXCHORUS_FEEDBACK_MIN,
DSFXCHORUS_FEEDBACK_MAX ); SaveSingleParameter( IDC_PARAM_NAME4,
&g_paramsChorus.fFrequency, DSFXCHORUS_FREQUENCY_MIN,
DSFXCHORUS_FREQUENCY_MAX ); SaveSingleParameter( IDC_PARAM_NAME5,
&g_paramsChorus.fDelay, DSFXCHORUS_DELAY_MIN, DSFXCHORUS_DELAY_MAX
);
if( ((CButton*)GetDlgItem(IDC_RADIO_TRIANGLE
))->GetCheck() == BST_CHECKED ) g_paramsChorus.lWaveform =
DSFXCHORUS_WAVE_TRIANGLE; else g_paramsChorus.lWaveform =
DSFXCHORUS_WAVE_SIN
if( ((CButton*)GetDlgItem(IDC_RADIO_NEG_180
))->GetCheck() == BST_CHECKED ) g_paramsChorus.lPhase =
DSFXCHORUS_PHASE_NEG_180; else if(
((CButton*)GetDlgItem(IDC_RADIO_NEG_90 ))->GetCheck() == BST_CHECKED
) g_paramsChorus.lPhase = DSFXCHORUS_PHASE_NEG_90; else if(
((CButton*)GetDlgItem( IDC_RADIO_ZERO ))->GetCheck() == BST_CHECKED
) g_paramsChorus.lPhase = DSFXCHORUS_PHASE_ZERO; else if(
((CButton*)GetDlgItem(IDC_RADIO_90))->GetCheck() == BST_CHECKED
) g_paramsChorus.lPhase =
DSFXCHORUS_PHASE_90; else g_paramsChorus.lPhase =
DSFXCHORUS_PHASE_180;
if( g_pChorus)
//设置合生特技的参数 g_pChorus->SetAllParameters( &g_paramsChorus
);
break; } ......//下面是其他特技的参数设置
,略,具体可以见例子中的代码。 } | 注:
在音频播放的同时拖动滑动条调解音频特技的参数,可以随时调整音频特技的效果。
第5步
一切都ok了,下面就是调用IDRIRECTSOUNDBUFFER8 的play函数来播放音频文件了。
DWORD res; LPVOID lplockbuf; DWORD len; DWORD
dwWrite;
g_pDSBuffer8->Lock(0,0,&lplockbuf,&len,NULL,NULL,DSBLOCK_ENTIREBUFFER); g_pWaveFile->Read((BYTE*)lplockbuf,len,&dwWrite); g_pDSBuffer8->Unlock(lplockbuf,len,NULL,0); g_pDSBuffer8->SetCurrentPosition(0); g_pDSBuffer8->Play(0,0,DSBPLAY_LOOPING); | 上面讲了Directsound音频特技开发的主要流程,其中的设置音频过程我只是用chorus为例,其实其他的几个特技的使用方法跟chorus很类似,唯一不同的就是参数结构的不同,限于篇幅,对于其他特技的代码就不一一列出了,具体的可一参看本文实例的代码。
下面我们看看每个特技的参数都需要设置什么。
|
|
|
|
|
|
|
|