xiaoxiaoling

C++博客 首页 新随笔 联系 聚合 管理
  17 Posts :: 2 Stories :: 9 Comments :: 0 Trackbacks

导言

FMOD Ex API被设计得非常直观和灵活,本教程将简要介绍引擎的使用方法,并对使用中涉及的相关问题做出解释。

配置——What to include and what to link.

查阅文档中的"Platform specific issues",找出指定平台上要使用FMOD Ex函数所需链接的文件。

在C/C++中,如果只须使用C接口,则包含"fmod.h",要使用C++接口则须包含"fmod.hpp"。
注意:常量、回调函数、宏定义和枚举类型都在fmod.h中,所以fmod.hpp也包含fmod.h,如果你使用C++的话就必须交叉使用。

对于Delphi、C#和Visual Basic,都有其对应的头文件可供在程序中使用。

初始化

要初始化fmod,最简单的方法就是调用System::init函数,FMOD会使用默认参数来配置声卡和其他设置。

在查看文档中的System::init函数时,要记住maxchannels参数是你在游戏中可以同时播放声音的最大数量,该数与声卡或软件混合器无关。

这些声音是 虚拟声音(virtual voices)。这意味着你可以同时播放任意多的声音,而不用担心硬件或软件资源问题。
你可以在游戏中安全地播放每个声音,而无须担心System::playSound超出播放上限或抢占其它声音。因此只要你喜欢,你可以将maxchannels设置为任意大的数,如1,100,200,1000。
注意:同时播放1000个声音并不会音像性能,因为它们中的大部分是听不见的 (听不见的声音被“虚拟化”了)。而FMOD Ex虚拟声音管理器决定哪些声音能听见,哪些听不见只需要很小的系统开销。
下面我们看一个初始化FMOD Ex的例子。

 

FMOD_RESULT result;

FMOD::System *system;

 

result =system);               // 创建主system对象

if (result != FMOD_OK)

{

    printf("FMOD error! (%d) %s\n", result, FMOD_ErrorString(result));

    exit(-1);

}

 

result = system->init(100, FMOD_INIT_NORMAL, 0);     // 初始化FMOD

if (result != FMOD_OK)

{

    printf("FMOD error! (%d) %s\n", result, FMOD_ErrorString(result));

    exit(-1);

}

 

这是最基本的初始化FOMD引擎的方法,使用了100个虚拟声音。
注意:mod、s3m、xm、it和midi格式的文件播放时只使用一个声音,不要以为在这里增大数量就可以使用多个声音来播放这些格式的文件。这些格式的都使用它们自己的internal pool voices。

配置选项

如果你不想使用默认设置的话,可以自行设定输出硬件、FOMD资源使用和其他配置选项。
这些操作都必须在System::init函数调用前进行。
常用配置如下:

·  System::setOutput – 选择输出方式。例如你可以在Windows上选择DirectSound、WinMM、ASIO、no-sound、wave-writer或其他输出选项,每个平台都有不同的选择。如果你只是要使用默认配置,就不需要调用它。

·  System::setDriver – 选择用于播放的设备驱动。当你拥有不止一块声卡并且不想使用默认声卡的时候,这个函数就很有用了。你需要用System::getNumDrivers函数来获取设备数,用System::getDriverName函数来获取驱动名称以供用户选择。

·  System::setHardwareChannels – 使用这个函数来限制硬件声音的数量,或设定在reverting to 100% software mixed voice support之前的最小硬件声音数量。“minimum”选项用于保证同时至少能听到的声音数量。

·  System::setSoftwareChannels – 使用这个函数来设定FMOD通道使用的软件混合声音的数量。 This will be purely for polyphony reasons or CPU / memory resource usage reasons. 使用mod/s3m/xm/it/midi这些格式时,不要指望使用它来增加声音的数量,它们不使用通道的pool而使用自己的。

·  System::setSoftwareFormat – 用于改变FMOD软件混合器的设置。包括采样率、输出模式(如integer vs float)、输出通道数(如multi-output channel ASIO devices)、内存使用和混合质量。

·  System::setDSPBufferSize – 如果在很慢的机器上或非良好的声卡驱动上出现声音抖动,就需要使用这个函数。它可以改变软件混合器的响应时间,但误用的话也可能影响性能。一些人可能想让用户在“低响应时间”和“高兼容性”两种模式间做出选择,可以通过调整缓冲大小来达到牺牲响应时间换取稳定性的目的。

·  System::setSpeakerMode – 设置扬声器输出模式。此函数只对FMOD软件混合引擎起作用,默认值为stereo (5.1 on xbox and xbox360 and 7.1 on ps3),可以按需要任意更改。注意:声道数越多,占用的内存也越多。

下面的例子使用了一些配置项来初始化FMOD。 要记住这些选项都是可选的,如果不需要就不用设置,在你没有弄懂其真正含义前,千万不要仅仅将下面的代码复制再粘贴! 例如,如果用户没有5.1声道的系统,你就不能仅仅将扬声器模式设定为5.1。

 

FMOD_RESULT result;

FMOD::System *system;

 

result =system);               //创建主system对象

ERRCHECK(result);

 

// 设置扬声器模式为5.1声道

result = system->setSpeakerMode(FMOD_SPEAKERMODE_5POINT1);   ERRCHECK(result);

 

// 允许同时播放100个软件混合声音

result = system->setSoftwareChannels(100);           ERRCHECK(result);

 

// 要求声卡至少要有32个2D和3D硬件声音,如果声音数超过64,就限制为64

result = system->setHardwareChannels(32, 64, 32, 64); ERRCHECK(result);

 

// 初始化FOMD,使用100个虚拟声音

result = system->init(200, FMOD_INIT_NORMAL, 0);            

ERRCHECK(result);

加载与播放

要播放声音,你必须先加载!
使用System::createSoundSystem::createStream就可以完成这项工作。
默认情况下,系统会尝试将整个声音解压到内存中(如果使用 System::createSound函数),而和sample不同的是stream(用 System::createStream创建)是在运行时解码,仅使用很少的内存作为缓冲,这就是为什么大文件最好用stream的原因。
更多请参见术语/基本原理

下面是一个加载MP3文件的例子,默认条件下System::createSound函数将整个MP3解压成16bit的PCM格式,这就意味着将占用比文件本身大许多倍的内存。

 

FMOD::Sound *sound;
// FMOD_DEFAULT等效于FMOD_LOOP_OFF | FMOD_2D | FMOD_HARDWARE.

result = system->createSound("../media/wave.mp3", FMOD_DEFAULT, 0, &sound);       

ERRCHECK(result);



下面是一个用stream打开MP3文件的例子。System::createStream函数将打开文件并预缓冲小部分数据,然后就可以在System::playSound调用时直接播放了。

 

FMOD::Sound *sound;
// FMOD_DEFAULT等效于FMOD_LOOP_OFF | FMOD_2D | FMOD_HARDWARE.

result = system->createStream("../media/wave.mp3", FMOD_DEFAULT, 0, &sound);              

ERRCHECK(result);



指定用软件混合就必须使用FMOD_SOFTWARE标记。如果你想要使用如DSP effects、spectrum analysis、getwavedata、point to point looping和其它更多的高级技术,就必须使用软件混合。

 

FMOD::Sound *sound;
// 使用软件混合

result = system->createSound("../media/wave.mp3", FMOD_SOFTWARE, 0, &sound);             

ERRCHECK(result);



下一个例子是将MP3以sample的形式载入内存而不解压,使用 FMOD_CREATECOMPRESSEDSAMPLE标记。此时如果没有指定FMOD_HARDWAREFMOD_SOFTWARE,将默认为软件混合。硬件声音回放不支持这个标记,除非格式为ADPCM on Xbox、VAG on PS2/PSP或GCADPCM on Gamecube/Wii。 Platforms like PS3 and Xbox 360 are all done one the cpu (usually a different core to the main cpu so it does not affect performance).

 

FMOD::Sound *sound;
// FMOD_CREATECOMPRESSEDSAMPLE标记让sample先尝试直接播放(不解压到内存),但仅限于IMA ADPCM、MP2、MP3和XMA格式

result = system->createSound("../media/wave.mp3", FMOD_CREATECOMPRESSEDSAMPLE, 0, &sound);

ERRCHECK(result);

警告! 必须谨慎使用这种模式,它看上去和PCM sample很相似,但它会在运行时导致巨大CPU开销。FMOD按照声音的压缩格式,在播放时对其进行解码。


现在,要播放sound或stream只需简单地调用System::playSound就行了。

 

FMOD::Channel *channel;

result = system->playSound(FMOD_CHANNEL_FREE, sound, false, &channel);

ERRCHECK(result);

 

此时,声音已经在后台播放了!而你的程序将继续执行。

关于playSound的注意事项:

·  如果不需要的话,可以不必获取channel句柄,可以将其设为0或NULL。如果你不需要更改这个sound实例,或者这个声音很短(不循环),就可以省去它。例如:

 

 

  result = system->playSound(FMOD_CHANNEL_FREE, sound, false, 0);

  ERRCHECK(result);

 

·  可以在开始播放时暂停,这样就可以更改声音的属性而不会被用户听见,这就是“paused”参数的用处所在。例如,如果你将paused设为true,再设置音量为0.5,然后解除暂停,此时声音就会一一般的音量播放。但如果你是将paused设为false,而其它操作相同的话,你会听见声音开始时瞬间是全音量播放的,用户可不希望听到。

 

 

  result = system->playSound(FMOD_CHANNEL_FREE, sound, true, &channel);

  ERRCHECK(result);

  // 暂停时设定音量

  result = channel->setVolume(0.5f);           

  ERRCHECK(result);

  // 声音从这里才开始播放

  result = channel->setPaused(false);          

  ERRCHECK(result);

 

·           一个“channel”就是一个声音的实例。一个声音你可以同时播放多次,每次播放都会得到一个新的channel句柄,但stream除外,它只能同时播放一次,如果你尝试多次播放,只会重复播放当前stream并返回同上次一样的channel句柄。这是因为stream只有一个缓冲和一个文件句柄。要同时播放两个stream就必须打开两次再播放两次。

·           始终使用FMOD_CHANNEL_FREE。FMOD会使用通道管理器自动为你选择一个未使用的channel。如果希望使用一个现有的channel来播放,就使用FMOD_CHANNEL_REUSE标记,这样可以避免每次调用System::playSound函数都产生一个新的实例。

·           不需要“free”或“release”一个channel句柄。所有的channel都位于你使用System::init所创建的一个pool中。当声音停止后,channel可以被复用;如果所有的channel都处于播放状态,那么其中一个优先级最低的会被抢占。其实只需增大System::init中的通道数就可以避免发生这样的情况。

·           一个channel会在播放结束时即刻失效。这意味着你不能再对其进行更改,即使做了也没有实际意义,因为它不可能再播放了。绝大多数情况下,引用一个已失效的channel会导致一个FMOD_ERR_INVALID_HANDLE错误。

Update. (This is important!)

在每一帧中调用System::update函数是很重要的,但不需要多次调用,那样只会影响效率。
该函数用于更新FMOD Ex的以下内容:

·           Platform specific routines 例如向PS2的IOP发送一个frame command packet。在这个平台上,不调用update的话就听不到声音。

·           Virtual voice emulation 不调用update,虚拟声音就不会播放。

·           3D voice calculation 如果不调用update,就算channel或listener已经正确设置,也无法听到声音移动的3D音效。

·           Geometry engine FMOD的polygon/geometry引擎需要通过update来启用。否则用户定义的occlusion/obstruction特性将无法呈现。

·           Non realtime output FMOD_OUTPUTTYPE_NOSOUND_NRTFMOD_OUTPUTTYPE_WAVWRITER_NRT标记需要此函数才能更新到输出(如用FMOD_OUTPUTTYPE_WAVWRITER_NRT写出到文件)。

·           Streaming engine 如果指定了FMOD_INIT_STREAM_FROM_UPDATE标记,如果用户希望在主线程中自己驱动流引擎,就必须有规律地调用update,否则会导致抖动和缓冲溢出。

关闭

调用System::release函数来关闭输出设备并释放对象关联的内存。
你不必人工关闭channel和sound,这些都在System::release中自动完成。
当然,你也可以手动关闭它们,这是个很好的编程练习(虽然是多余的)。
如果你要释放system对象就不需要调用System::close函数了,在System::release中已经包含了对System::close的调用。

资源使用配制

在程序开发中,一些开发人员希望和其它程序一样用自己的函数来访问所有的磁盘或内存。
在FMOD Ex中你可以通过System::setFileSystem函数来设置FMOD文件系统使你自己的文件程序。

要让FMOD使用你的内存系统,或将FMOD限制在一个内存块中,使用Memory_Initialize

注意! 在Xbox和XBox 360中,必须给FMOD提供一个块内存。Xbox 360上必须使用XPhysicalAlloc来分配这块内存。更多参见"Platform specific issues"。

posted on 2008-09-26 10:21 clcl 阅读(1601) 评论(0)  编辑 收藏 引用

只有注册用户登录后才能发表评论。
网站导航: 博客园   IT新闻   BlogJava   知识库   博问   管理