<!-- /* Font Definitions */ @font-face {font-family:宋体; panose-1:2 1 6 0 3 1 1 1 1 1; mso-font-alt:SimSun; mso-font-charset:134; mso-generic-font-family:auto; mso-font-pitch:variable; mso-font-signature:3 135135232 16 0 262145 0;} @font-face {font-family:"/@宋体"; panose-1:2 1 6 0 3 1 1 1 1 1; mso-font-charset:134; mso-generic-font-family:auto; mso-font-pitch:variable; mso-font-signature:3 135135232 16 0 262145 0;} /* Style Definitions */ p.MsoNormal, li.MsoNormal, div.MsoNormal {mso-style-parent:""; margin:0cm; margin-bottom:.0001pt; mso-pagination:none; font-size:10.5pt; mso-bidi-font-size:12.0pt; font-family:"Times New Roman"; mso-fareast-font-family:宋体; mso-font-kerning:1.0pt;} p.MsoBodyText, li.MsoBodyText, div.MsoBodyText {margin-top:0cm; margin-right:0cm; margin-bottom:6.0pt; margin-left:0cm; mso-pagination:none; font-size:10.5pt; mso-bidi-font-size:12.0pt; font-family:"Times New Roman"; mso-fareast-font-family:宋体; mso-font-kerning:1.0pt;} p.MsoBodyTextFirstIndent, li.MsoBodyTextFirstIndent, div.MsoBodyTextFirstIndent {mso-style-update:auto; mso-style-parent:正文文本; mso-style-link:" Char Char"; margin:0cm; margin-bottom:.0001pt; text-indent:19.85pt; mso-pagination:none; font-size:10.5pt; font-family:"Times New Roman"; mso-fareast-font-family:宋体; mso-ansi-language:ZH-CN;} span.CharChar {mso-style-name:" Char Char"; mso-style-locked:yes; mso-style-link:正文首行缩进; mso-ansi-font-size:10.5pt; mso-bidi-font-size:10.5pt; font-family:宋体; mso-fareast-font-family:宋体; mso-ansi-language:ZH-CN; mso-fareast-language:ZH-CN; mso-bidi-language:AR-SA;} /* Page Definitions */ @page {mso-page-border-surround-header:no; mso-page-border-surround-footer:no;} @page Section1 {size:612.0pt 792.0pt; margin:72.0pt 90.0pt 72.0pt 90.0pt; mso-header-margin:36.0pt; mso-footer-margin:36.0pt; mso-paper-source:0;} div.Section1 {page:Section1;} -->
DirectX的音频处理在 8.0以前的版本中被单独分为两个部分: DirectSound和 DirectMusic。在 DirectX 8中,它们被整合一体并称为 DirectX Audio。但是在实际处理中还必须针对 DirectSound和 DirectMusic分别操作。
在 DirectAudio中,最基本的也是必需的元素是音频片断,它通常是一段声音,来自于资源或者音频文件。
要使用 DirectAudio,我们首先来定义一个基本的声音的类 SOUND,它包括了一段表示声音数据的音频片断 dmSegment,用于保存声音以便进行播放控制的声音缓冲区 ds3DBuffer,以及一个表示是否 3D声音的标志。
// 包含单一声音信息的类
class SOUND
{
public:
IDirectMusicSegment8* dmSegment; // 声音数据
IDirectSound3DBuffer* ds3DBuffer; //3D 声音缓冲区
bool is3DSound; // 是否3D 声音
void Set3DPos(float x, float y, float z){} // 设置3D 声音的位置
// 设置3D 声音的最大、最小距离
void Set3DDistances(float minDistance, float maxDistance){}
void Shutdown(void); // 关闭声音
SOUND() : dmSegment(NULL), ds3DBuffer(NULL), is3DSound(false)
{ }
~SOUND() { }
};
SOUND 类中的 Set3DPos 和 Set3DDistances 为空 , 表示在本例中我们的目的仅仅是使用 DirectSound , 对于声音的各种特效暂时不考虑。如果需要,只需进行针对性扩充即可,当然,你需要对 DirectSound有所了解。
接下来我们来使用 DirectMusic处理 SOUND对象,这里也需要定义几个接口变量。 dmLoader是一个 IDirectMusicLoader8的接口指针,用于查找、列举、加载和缓存声音对象。声音对象可以是资源,也可以是文件。 dmPerformance是一个 IDirectMusicPerformance8的接口指针,用于综合管理音乐的回放。包括增加、删除端口,映射演奏通道( performance channels),播放声音片断,调度消息流程,管理事件通知等等。 dm3DAudioPath是一个 IDirectMusicAudioPath的接口指针,它用于实现声音数据流从数据源到主声音缓冲区的过程。 ds3DListener则是一个 IDirectSound3DListener接口指针,用于描述听者( listener)在 3D空间中的位置、方向及其他环境参数。 dsListenerParams是一个 DS3DLISTENER结构,用于描述 3D空间参数和听者的位置。
IDirectMusicLoader8* dmLoader;
IDirectMusicPerformance8* dmPerformance;
IDirectMusicAudioPath* dm3DAudioPath;
IDirectSound3DListener* ds3DListener;
DS3DLISTENER dsListenerParams;
DMInit 是我们定义的 DirectMusic 的初始化函数 , 在 DMInit 中首 先使用 COM 方法创建一个 IDirectMusicLoader8 对象和一个 IDirectMusicPerformance8 对象 , 这是使用 DirectMusic 中是必须的步骤。然后使用 InitAudio初始化音频,并创建标准的音频路径。最后设置听者的参数和声音目标文件的查找路径。
bool DMInit(void)
{
HRESULT hr;
WCHAR wcharStr[MAX_PATH];
char pathStr[MAX_PATH];
dm3DAudioPath=NULL;
dmLoader=NULL;
dmPerformance=NULL;
ds3DListener=NULL;
CoInitialize(NULL);
// 创建IDirectMusicLoader8
hr= CoCreateInstance(CLSID_DirectMusicLoader, NULL, CLSCTX_INPROC,
IID_IDirectMusicLoader8, (void**)&dmLoader);
if(FAILED(hr))
{
return false;
}
// 创建IDirectMusicPerformance8
hr= CoCreateInstance(CLSID_DirectMusicPerformance, NULL, CLSCTX_INPROC,
IID_IDirectMusicPerformance8, (void**)&dmPerformance);
if(FAILED(hr))
{
DMShutdown();
return false;
}
// 初始化音频
dmPerformance->InitAudio(NULL, NULL, g_hWnd, DMUS_APATH_SHARED_STEREOPLUSREVERB, 64,
DMUS_AUDIOF_ALL, NULL);
// 创建音频路径
hr= dmPerformance->CreateStandardAudioPath(DMUS_APATH_DYNAMIC_3D,
64, TRUE, &dm3DAudioPath);
if(FAILED(hr))
{
DMShutdown();
return false;
}
// 获取听者信息
hr= dm3DAudioPath->GetObjectInPath(0, DMUS_PATH_PRIMARY_BUFFER, 0,
GUID_NULL, 0,
IID_IDirectSound3DListener8,
(void**)&ds3DListener);
if(FAILED(hr))
{
return false;
}
dsListenerParams.dwSize= sizeof(DS3DLISTENER);
ds3DListener->GetAllParameters(&dsListenerParams);
// 设置听者缺省位置
dsListenerParams.vPosition.x= 0.0f;
dsListenerParams.vPosition.y= 0.0f;
dsListenerParams.vPosition.z= 0.0f;
ds3DListener->SetAllParameters(&dsListenerParams, DS3D_IMMEDIATE);
// 取得当前工作路径
GetCurrentDirectory(MAX_PATH, pathStr);
// 将文件名字符串转换成unicode 字符串,COM 需要,没办法
MultiByteToWideChar(CP_ACP, 0, pathStr, -1, wcharStr, MAX_PATH);
// 设置查找路径
dmLoader->SetSearchDirectory(GUID_DirectMusicAllTypes, wcharStr, FALSE);
return true;
}
DMShutdown负责关闭 DirectMusic,代码如下。
void DMShutdown(void)
{
if(dmPerformance!=NULL)
{
dmPerformance->Stop(NULL, NULL, 0, 0);
dmPerformance->CloseDown();
dmPerformance->Release();
}
if(dm3DAudioPath!=NULL)
dm3DAudioPath->Release();
if(dmLoader!=NULL)
dmLoader->Release();
// 和COInitialize 对应
CoUninitialize();
}
DirectMusic初始化后还需要和 DirectSound结合,即使用 DirectMusic来管理声音。 DMCreate就是用于创建一个来自于文件的声音。
bool DMCreate(SOUND* audio, char* filename, bool is3DSound)
{
DS3DBUFFER dsBufferParams;
HRESULT hr;
WCHAR wcharStr[MAX_PATH];
//DirectAudio 需要unicode 字符串
MultiByteToWideChar(CP_ACP, 0, filename, -1, wcharStr, MAX_PATH);
// 加载音频片断
hr= dmLoader->LoadObjectFromFile(CLSID_DirectMusicSegment,
IID_IDirectMusicSegment8,
wcharStr,
(void**)&audio->dmSegment);
if(FAILED(hr))
{
return false;
}
// 如果是3D 声音
if(is3DSound)
{
// 取得路径3D Buffer 和音频
hr= dm3DAudioPath->GetObjectInPath(DMUS_PCHANNEL_ALL,
DMUS_PATH_BUFFER, 0,
GUID_NULL, 0, IID_IDirectSound3DBuffer,
(void**)&audio->ds3DBuffer);
if(FAILED(hr))
{
return false;
}
// 取得3D 缓冲区参数
dsBufferParams.dwSize= sizeof(DS3DBUFFER);
audio->ds3DBuffer->GetAllParameters(&dsBufferParams);
// 设置新的参数
dsBufferParams.dwMode= DS3DMODE_HEADRELATIVE;
audio->ds3DBuffer->SetAllParameters(&dsBufferParams, DS3D_IMMEDIATE);
// 重新设置3D 声音标志
audio->is3DSound = true;
}
// 如果不是3D 声音
// 非3D 声音通常作为背景音乐,本例使用的就是非3D 音乐
else
{
audio->ds3DBuffer= NULL;
audio->is3DSound= false;
}
return true;
}
接下来就是最关键的声音回放了。声音的回放主要是两个过程,首先使用 IDirectMusicSegment8::Download下载音乐,然后使用 IDirectMusicPerformance8::PlaySegmentEx播放音乐片断。下面是负责音乐回放的 DMPlay函数。
// 播放声音,重复次数为numRepeats,DMUS_SEG_REPEAT_INFINITE 表示重复播放
// 直到显式的被停止为止; 0 表示只播放一次,不再重复。
void DMPlay(SOUND* audio, DWORD numRepeats)
{
// 设置重复播放次数
audio->dmSegment->SetRepeats(numRepeats);
if(audio->is3DSound)
{
audio->dmSegment->Download(dm3DAudioPath);
// 播放3D 音乐
dmPerformance->PlaySegmentEx(audio->dmSegment, NULL, NULL,
DMUS_SEGF_SECONDARY, 0,
NULL, NULL, dm3DAudioPath);
}
else
{
audio->dmSegment->Download(dmPerformance);
// 播放非3D 音乐
dmPerformance->PlaySegmentEx(audio->dmSegment, NULL, NULL,
DMUS_SEGF_DEFAULT, 0,
NULL, NULL, NULL);
}
}
如果播放音乐时的循环次数是无限,要让音乐停止的办法就是显式的调用 IDirectMusicPerformance8::StopEx函数。当然,应用程序中止时,音乐也会自动停止播放。 下面是停止音乐播放的函数DMStop。
// 停止播放某一声音
void DMStop(SOUND* audio)
{
dmPerformance->StopEx(audio->dmSegment, 0, 0);
}
接下来,将对DirectAudio 初始化和关闭的过程集成到DirectX 的初始化函数和关闭函数中。
SOUND sound;
int DXInit()
{
……
// 上面是DirectInput 的初始化,包括键盘和鼠标设备
// 下面是DirectMusic 的初始化
DMInit();
// 以battle.mid 文件创建一个音频,非3D
DMCreate(&sound, "battle.mid", FALSE);
return TRUE;
}
void DXShutdown()
{
……
// 上面是DirectInput 的关闭部分,下面是增加的DirectAudio 的关闭部分
sound.Shutdown();
DMShutdown();
}