DirectSound开发指南.docx

上传人:b****4 文档编号:11861998 上传时间:2023-04-06 格式:DOCX 页数:45 大小:127.58KB
下载 相关 举报
DirectSound开发指南.docx_第1页
第1页 / 共45页
DirectSound开发指南.docx_第2页
第2页 / 共45页
DirectSound开发指南.docx_第3页
第3页 / 共45页
DirectSound开发指南.docx_第4页
第4页 / 共45页
DirectSound开发指南.docx_第5页
第5页 / 共45页
点击查看更多>>
下载资源
资源描述

DirectSound开发指南.docx

《DirectSound开发指南.docx》由会员分享,可在线阅读,更多相关《DirectSound开发指南.docx(45页珍藏版)》请在冰豆网上搜索。

DirectSound开发指南.docx

DirectSound开发指南

DirectSound开发指南

曾经写过一份Directshow的相关开发资料,因为最近工作中使用到了DirectSound,所以整理了这样一份文档,如果对你有帮助,将不胜荣幸。

争取在6月份完成这个文档吧。

智慧的鱼(Leeqiang)

2005.6.20

1DirectSound简介(IntroductiontoDirectSound)

曾经学习过Directshow的开发,对于Dsound一直没有仔细的莱学习,以前只是知道Dsound是做音频开发的,我一直以为它和Dshow的结构体系差不多,经过仔细学习后,发现,其实他们完全两码事。

闲话少说,下面我们看看DirectSound到底能帮我们做些什么。

1播放WAVE格式的音频文件或者资源。

2可以同时播放多个音频。

3Assignhigh-prioritysoundstohardware-controlledbuffers

4播放3D立体声音

5在声音中添加特技效果,比如回声,动态的改变特技的参数等

6将麦克风或者其他音频输入设备的声音录制成wave格式的文件

呵呵,DirectSound就能做这么多事情,读到这里,我都有点怀疑DirectSound是不是就是封装了mmio系列和wav系列的函数。

因为这些底层的API也能够完成这些事情。

2DirectSound初体验(GettingStartedwithDirectSound)

在开始本节内容前,我会首先提醒一下,如果你想用Directsound开发,那么你首先要包含Dsound.h头文件,其实我可以实话告诉你,你仅仅包含dsound.h你的工程肯定调补通,其实下面的一些头文件也要包含,我第一次就搞了半天才搞好,

#include

#include

#include

#include

如果你还想使用Dsound的API的话,那么你就要在你的vc开发环境中添加Dsound..lib库,

如果你的程序还提示有很多的外部链接找不到,那么我建议你可以将下面的库都添加到你的工程中comctl32.libdxerr9.libwinmm.libdsound.libdxguid.libkernel32.libuser32.libgdi32.libwinspool.libcomdlg32.libadvapi32.libshell32.libole32.liboleaut32.libuuid.libodbc32.libodbccp32.lib,这些是我从Dsound提供的例子中得到的,肯定够你用的,ok,开发环境配置好了。

下面我们简单的来学习一下如果通过Directsound的API播放声音,既然是breifoverview,那么详细的内容你可以参考下面的一节内容,这里只是简单的介绍一下播放声音的步骤。

第一步,创建一个设备对象。

在你的代码中你可以通过调用DirectSoundCreat8函数来创建一个支持IDirectSound8接口的对象,这个对象通常代表缺省的播放设备。

当然你可以枚举可用的设备,然后将设备的GUID传递给DirectSoundCreat8函数。

注意,Directsound虽然基于COM,但是你并不需要初始化com库,这些Directsound都帮你做好了,当然,如果你使用DMOs特技,你就要自己初始化com库了,切记。

第二步,创建一个辅助Buffer,也叫后备缓冲区

你可以通过IDirectSound8:

:

CreateSoundBuffer来创建buffer对象,这个对象主要用来获取处理数据,这种buffer称作辅助缓冲区,以和主缓冲区区别开来,Direcsound通过把几个后备缓冲区的声音混合到主缓冲区中,然后输出到声音输出设备上,达到混音的效果。

第三步,获取PCM类型的数据

将WAV文件或者其他资源的数据读取到缓冲区中。

第四步,将数据读取到缓冲区

你可以通过IDirectSoundBuffer8:

:

Lock.方法来准备一个辅助缓冲区来进行写操作,通常这个方法返回一个内存地址,见数据从你的私人buffer中复制到这个地址中,然后调用IDirectSoundBuffer8:

:

Unlock.

第五步,播放缓冲区中的数据

你可以通过IDirectSoundBuffer8:

:

Play方法来播放缓冲区中的音频数据,你可以通过IDirectSoundBuffer8:

:

Stop来暂停播放数据,你可以反复的莱停止,播放,音频数据,如果你同时创建了几个buffer,那么你就可以同时来播放这些数据,这些声音会自动进行混音的。

呵呵,简单介绍到这里的,如果想深入了解,请继续参考下一部分。

3DirectSound实用开发技巧UsingDirectSound

在进行这部分之前,我们首先学习一下Directsound中常用的几个对象,简单学习一下哦

对象

数量

作用

主要接口

设备对象

每个应用程序只有一个设备对象

用来管理设备,创建辅助缓冲区

IDirectSound8

辅助缓冲区对象

每一个声音对应一个辅助缓冲区,可以有多个辅助缓冲区

用来管理一个静态的或者动态的声音流,然后在主缓冲区中混音

IDirectSoundBuffer8,IDirectSound3DBuffer8,IDirectSoundNotify8

主缓冲区对象

一个应用程序只有一个主缓冲区

将辅助缓冲区的数据进行混音,并且控制3D参数.

IDirectSoundBuffer,IDirectSound3DListener8

特技对象

没有,或者

来辅助缓冲的声音数据进行处理

8个特技接口

IDirectSoundFXChorus8

首先,要创建一个设备对象,然后通过设备对象创建buffer对象。

辅助缓冲区由应用程序创建和管理,DirectSound会自动地创建和管理主缓冲区,一般来说,应用程序即使没有获取这个对象的接口也可以播放音频数据,但是,如果应用程序要想得到IDirectSound3DListener8接口,就必须要自己创建一个主缓冲区。

我们可以将短小的声音文件全部读取到辅助缓冲区中,然后通过一个简单的命令来播放。

如果声音文件很长,就必须采用数据流了。

3.1Dsound设备对象(DirectSoundDevices)

本节主要讲述下面的几个内容

1如何枚举系统输出声音的设备

2创建设备对象

3设置声音设备的协作度

下面首先看看如何枚举系统中的声音输出设备

1如何枚举系统输出声音的设备

如果你的应用程序使用用户首选的输出设备来输出声音,那么你就没有必要来枚举所有的输出设备,如果你通过DirectSoundCreat8函数来创建一个设备对象的同时,就给这个对象指定了一个缺省的设备,当然如果遇到下面的一些情形,你就要来枚举设备对象

例如,你的应用程序并不支持所有的输出设备,或者你的应用程需要两个或者多个设备,或者你希望用户自己来选择输出设备。

枚举设备,你首先要定义一个回调函数,这个回调函数可以被系统中的每个设备来调用,你可以在各函数做任何事情,这个函数的命名也没有任何的限制,但是函数应该以DSEnumCallback为原型,如果枚举没有结束,这个回调函数就返回TRUE,如果枚举结束,例如你找到合适的设备,这个函数就要返回FALSE。

下面是回调函数的一个例子,这个函数将枚举的每一个设备都添加到一个combox中,将设备的GUID保存到一个item中,这个函数的前三个参数由设备的驱动程序提供,第四个参数有DirectSoundEnumerate函数提供,这个参数可以是任意的32位值,这个例子里是combox的句柄,

BOOLCALLBACKDSEnumProc(LPGUIDlpGUID,

LPCTSTRlpszDesc,

LPCTSTRlpszDrvName,

LPVOIDlpContext)

{

HWNDhCombo=(HWND)lpContext;

LPGUIDlpTemp=NULL;

if(lpGUID!

=NULL)//NULLonlyfor"PrimarySoundDriver".

{

if((lpTemp=(LPGUID)malloc(sizeof(GUID)))==NULL)

{

return(TRUE);

}

memcpy(lpTemp,lpGUID,sizeof(GUID));

}

ComboBox_AddString(hCombo,lpszDesc);

ComboBox_SetItemData(hCombo,

ComboBox_FindString(hCombo,0,lpszDesc),

lpTemp);

free(lpTemp);

return(TRUE);

}

枚举设备通常都是在对话框初始化的时候才进行的,我们假设hCombo就是combox句柄,hDlg就对话框的句柄,看看我们怎么来枚举设备的吧

if(FAILED(DirectSoundEnumerate((LPDSENUMCALLBACK)DSEnumProc,

(VOID*)&hCombo)))

{

EndDialog(hDlg,TRUE);

return(TRUE);

}

在这个例子中,combox的句柄作为参数传递到DirectSoundEnumerate函数中,然后又被传递到回调函数中,这个参数你可以是你想传递的任意的32位值。

注:

第一个被枚举的设备通常称为Primarysounddriver,并且回调函数的lpGUID为NULL,这个设备就是用户通过控制面板设置的缺省的输出声音设备,

2创建设备对象

创建设备对象最简单的方法就是通过DirectSoundCreate8函数,这个函数的第一个参数指定了和这个对象邦定的设备的GUID,你可以通过枚举设备来获取这个设备的GUID,你可以传递一个下面的参数来指定一个缺省的设备

DSDEVID_DefaultPlayback缺省的系统的声音输出设备,这个参数也可以为NULL

SDEVID_DefaultVoicePlayback,缺省的声音输出设备,通常指第二缺省设备,例如USB耳机麦克风

如果没有声音输出设备,这个函数就返回error,或者,在VXD驱动程序下,如果声音输出设备正被某个应用程序通过waveform格式的api函数所控制,该函数也返回error,

下面是创建对象的代码,及其简单

LPDIRECTSOUND8lpds;

HRESULThr=DirectSoundCreate8(NULL,&lpds,NULL));

如果你想通过表准的COM调用来创建设备对象,下面我就给出代码,你可以比较一下

HRESULThr=CoInitializeEx(NULL,0);

if(FAILED(hr))

{

ErrorHandler(hr);//Adderror-handlinghere.

}

LPDIRECTSOUND8lpds;

hr=CoCreateInstance(&CLSID_DirectSound8,

NULL,

CLSCTX_INPROC_SERVER,

IID_IDirectSound8,

(LPVOID*)&lpds);

if(FAILED(hr))

{

ErrorHandler(hr);//Adderror-handlinghere.

}

hr=lpds->Initialize(NULL);

if(FAILED(hr))

{

ErrorHandler(hr);//Adderror-handlinghere.

}

CoUninitialize();

3设置声音设备的协作度

因为Windows是一个多任务操作环境,在同一个时刻有可能多个应用程序共用同一个设备,通过协作水平,DirectX就可以保证这些应用程序在访问设备的时候不会冲突,每个Directsound应用程序都有一个协作度,用来确定来接近设备的程度,

当你创建完设备对象后,一定要调用IDirectSound8:

:

SetCooperativeLevel来设置协作度,否则,你不会听到声音的,

HRESULThr=lpDirectSound->SetCooperativeLevel(hwnd,DSSCL_PRIORITY);

if(FAILED(hr))

{

ErrorHandler(hr);//Adderror-handlinghere.

}

Hwnd参数代表了应用程序的窗口。

DirectSound定义了三种水平,DSSCL_NORMAL,DSSCL_PRIORITY,andDSSCL_WRITEPRIMARY

在NORMAL水平的协作度下,应用程序不能设置主缓冲区的格式,也不能对主缓冲区进行写操作,所有在这个层次的应用程序使用的媒体格式都是22kHZ,立体声,采样精度8位,所以,设备可以在各个应用程序中任意的切换。

在Priority层次的协作度下,应用程序可以有优先权使用硬件资源,比如使用硬件进行混音,当然也可以设置主缓冲区的媒体格式,游戏程序应该采用这个层次的协作度,这个层次的协作度在允许应用程序控制采用频率和位深度的同时,也给应用程序很大的权力,这个层次的协作度允许其他应用程序的声音和游戏的音频同时被听到,不影响。

最高层次的协作度就是Write_primary,当采用这个层次的协作度来使用一个dsound设备时,在非WDM模式驱动下,你的应用程序可以直接操作主缓冲区,在这个模式下,应有程序必须直接的操作主缓冲区。

如果你想直接把音频数据直接写入到主缓冲区,你就要将你的协作度模式设置为writeprimary,如果你的应用程序没有设置到这个层次,那么所有的对主缓冲区的IDirectSoundBuffer:

:

Lock都会失败。

当你的应用程序的协作度设置为wirte_primary水平时,并且你的应用程序gainstheforeground,那么其他应用程序的辅助缓冲区就会停止,并且标示为lost,当你的应用程序转到background,那么它的主缓冲区就会标示为lost,当它再次回到foreground的时候会恢复到原来的状态,如果你的设备没有出现在你的系统中,那么你就没法设置wirteprimary协作度了,所以,在设置协作度之前,可以通过IDirectSound8:

:

GetCaps方法来查询一下设备是否可用。

4设置声音设备(扬声器)

在windowos98或者2000系统中,用户可以通过控制面板来设置扬声器的属性,应用程序可以通过IDirectSound8:

:

GetSpeakerConfig.函数来获取这些属性,我们不建议应用程序通过IDirectSound8:

:

SetSpeakerConfig函授来设置扬声器的属性,因为这些设置的改动会影响到其他用户或者应用程序。

5查询输出设备的性能

你的应用程序可以通过Directsound来检查声音设备的性能,然而许多应用程序并不需要这么做,因为Directsound会自动地利用硬件提供的较好的性能,并不需要你手动地来选择。

但是,However,high-performanceapplicationscanusetheinformationtoscaletheirsoundrequirementstotheavailablehardware.Forexample,anapplicationmightchoosetoplaymoresoundsifhardwaremixingisavailablethanifitisnot.

当你调用DirectSoundCreate8创建一个设备对象后,你的应用程序就可以通过IDirectSound8:

:

GetCaps函数来获取设备的性能属性,下面的代码演示了这个过程

DSCAPSdscaps;

dscaps.dwSize=sizeof(DSCAPS);

HRESULThr=lpDirectSound->GetCaps(&dscaps);

if(FAILED(hr))

{

ErrorHandler(hr);//Adderror-handlinghere.

}

通过DSCAPS结构,该函数就给我返回硬件设备的一些性能,但是在调用这个函数之前一定要初始化这个结构的dwSize成员。

如果你的应用程序能够操作硬件设备,比如你的协作度是Write_primory级别的,那么你在硬件设备上分配内存的时候,就要调用IDirectSoudn8:

:

GetCaps来查看一下硬件的资源是否满足你的要求。

3.2Dsound的buffer对象(DirectSoundBuffers)

在存储和播放几个音频流的时候,你的应用程序要给每一个音频流都要创建一个辅助缓冲区(buffer)对象。

辅助缓冲区可以和应用程的生命期一样的长,也可以在不需要的时候销毁。

辅助缓冲区可以是一个包含了整个声音数据的静态缓冲区,也是可以只包含声音数据的一部份,然后再播放时不断更新数据的流缓冲区。

为了限制内存开销,在播放比较长的声音文件时要采用流缓冲区,这些缓冲区只包含几秒钟的数据量。

你可以通过同时播放几个辅助缓冲区中的声音来对他们进行混音,至于同时可以播放几个辅助缓冲区则有硬件设备的性能决定。

辅助缓冲区的格式并不完全一样,一般用来描述缓冲格式的参数如下

Format,缓冲区的format必须要所播放音频的waveformat一致。

Controls,不同的缓冲区的控制参数的值可以不一样,比如音量,频率,以及在不同方向的移动,当创建buffer时,你就要指定你需要的控制参数的值,例如,不要为一个不支持3D的音频创建一个3D缓冲区

Location,你创建的缓冲区可以在硬件管理的内存中,也可以在软件管理的内存中,当然,硬件缓冲区比软件缓冲区速度要快。

你可以调用IDirectSound8:

:

CreateSoundBuffer函数来创建一个缓冲区(buffer)对象。

这个函数返回一个指向IDrectSoundBuffer接口的指针,通过这个接口,应用程序可以获取

IDirectSoundBuffer8interface.

下面的一段代码演示了如何创建一个辅助缓冲区,并且返回一个IDirectSoundBuffer8接口

HRESULTCreateBasicBuffer(LPDIRECTSOUND8lpDirectSound,LPDIRECTSOUNDBUFFER8*ppDsb8)

{

WAVEFORMATEXwfx;

DSBUFFERDESCdsbdesc;

LPDIRECTSOUNDBUFFERpDsb=NULL;

HRESULThr;

//SetupWAVformatstructure.

memset(&wfx,0,sizeof(WAVEFORMATEX));

wfx.wFormatTag=WAVE_FORMAT_PCM;

wfx.nChannels=2;

wfx.nSamplesPerSec=22050;

wfx.nBlockAlign=4;

wfx.nAvgBytesPerSec=wfx.nSamplesPerSec*wfx.nBlockAlign;

wfx.wBitsPerSample=16;

//SetupDSBUFFERDESCstructure.

memset(&dsbdesc,0,sizeof(DSBUFFERDESC));

dsbdesc.dwSize=sizeof(DSBUFFERDESC);

dsbdesc.dwFlags=

DSBCAPS_CTRLPAN|DSBCAPS_CTRLVOLUME|DSBCAPS_CTRLFREQUENCY;//流buffer

dsbdesc.dwBufferBytes=3*wfx.nAvgBytesPerSec;

dsbdesc.lpwfxFormat=&wfx;

//Createbuffer.

hr=lpDirectSound->CreateSoundBuffer(&dsbdesc,&pDsb,NULL);

if(SUCCEEDED(hr))

{

hr=pDsb->QueryInterface(IID_IDirectSoundBuffer8,(LPVOID*)ppDsb8);

pDsb->Release();

}

returnhr;

}

这个例子中创建了一个可以持续播放3秒钟的流缓冲区,如果你要创建静态的缓冲区,你就要创建的buffersize正好能够容下你的音频数据即可。

如果缓冲区的位置没有指定,DirectSound在条件允许的情况下将你的缓冲区设置为硬件控制,因为硬件缓冲区的混音是通过声卡的加速器来进行的,受应用程序的影响较小。

如果你想自己控制你创建的缓冲区(buffer)的位置,那么你一定要将DSBUFFERDESC中的dsbdesc.dwFlags成员变量设置为DSBCAPS_LOCHARDWARE或者设置为DSBCAPS_LOCSOFTWARE,如果设置为DSBCAPS_LOCHARDWARE,此时硬件设备的资源不足时,缓冲区创建失败。

如果你想使用DirectSound的管理声音的特性,那么你创建缓冲区的时候一定要设置DSBCAPS_LOCDEFER标志,这个标志表示只有在播放的时候才分配内存,更多的细节,你可以参考动态的声音管理一节。

你可以通过IDirectSoundBuffer8:

:

GetCaps方法来探明已经存在的缓冲区,并且可以检查该buffer的dwFlags设置情况。

缓冲区对象属于创建它的设备对象。

当设备对象销毁时,它所创建的buffer对象也全部被销毁,没法被引用了。

你可以通过IDirectSound8:

:

DuplicateSoundBuffer同时创建两个或者多个包含相同数据的辅助缓冲区,当然不允许复制主缓冲区。

因为复制的缓冲区和原始的缓冲区共享内存,改变复制的缓冲区的数据的同时,也改变了原始缓冲区的内容。

下面我们看看buffer的控制属性

当你创建了缓冲区的时候,你的应用程序设置该缓冲区的控制属性,这是由DSBUFFERDESC结构的dwFlags成员来控制的。

下面我们来看看dwFlags的取值

DSBCAPS_CTRL3D表示声音可以在3个方向上进行移动

DSBCAPS_CTRLFX,表示可以在缓冲区中添加特技

DSBCAPS_CTRLFREQUENCY,表示声音的频率可以被改动

DSBCAPS_CTRLPAN,表示声音可以从左声道被移动到右声道

DSBCAPS_CTRLPOSITIONNOTIFY,可以在buffer中设置通知的位置。

展开阅读全文
相关资源
猜你喜欢
相关搜索
资源标签

当前位置:首页 > IT计算机

copyright@ 2008-2022 冰豆网网站版权所有

经营许可证编号:鄂ICP备2022015515号-1