进阶音效控制与管理(转载)

junwong 发布于 2012/02/17 11:18
阅读 506
收藏 0

摘要

以 XNA 为基础的游戏程序可以利用 SoundEffect 类别的功能执行简单的音效播放,或是利用 SoundEffectInstance 类别进行进阶的音效播放控制,包括播放、暂停、恢复、结束、是否要播放 3D 的音效、控制声音从左边或右边的声道输出、控制音调高低、以及控制音量等等。在这一回的文章中,我们将介绍利用 SoundEffectInstance 类别进行进阶音效控制的做法,除此之外,我们也将会介绍支持组织和管理声音文件的 XACT(Cross-platform Audio Creation Tool) 工具。

有关 XNA Framework 提供的 SoundEffect 类别和 SoundEffectInstance 类别的基本功能和使用方法可以参考 [XNA 交互式游戏设计] 一文的说明。

进阶音效控制

Windows Phone 7 智能型手机并非只能播放一种音效,以 XNA 为基础的游戏程序可以同时播放 64 种声音,达成混合多种音效的效果。除此之外,XNA Framework 也支持动态播放音效,例如播放应用程序执行时期建立的音效,或是搭配麦克风播放由外界输入的音效。

[提示]

Windows Phone 7 智能型手机支持同时播放多达 64 种的音效,但是 Xbox 360 游戏机支持播放多达 300 种的音效,可以播放更丰富的声音效果,而 Windows 操作系统则是未限制可以同时播放的音效数目。

当游戏程序想要仿真环绕音效的时候,可以利用 SoundEffectInstance 类别的 Pan 属性控制音效要从左方发声,还是要从右方发声。Pan 属性是一个介于 -1.0 与 1.0 之间的数值,其值为 -1.0 表示要从左方发声,其值为 1.0 表示要从右方发声,而其值为 0 则表示要从中央发声,其默认值为 0。

当游戏程序需要控制所播放的音效的音调高低时,就可以利用 SoundEffectInstance 类别的 Pitch 属性进行控制。Pitch 属性是一个介于 -1.0 与 1.0 之间的数值,其值为 -1.0 表示音调最低,其值为 1.0 表示音调最高,其默认值为 0。

当游戏程序需要控制所播放的音效的音量时,就可以利用 SoundEffectInstance 类别的 Volume 属性进行控制。Volume 属性是一个介于 .0 与 1.0 之间的数值,其值为 0 表示音量最小 (静音),其值为 1 表示音量最大,其默认值为 1。请注意透过 SoundEffectInstance 类别控制的音量取决于 SoundEffect 类别的 MasterVolume 属性的内容值,换句话说将 SoundEffectInstance 类别的 Volume 属性的内容值设定为 1,所呈现的最大音量就是 SoundEffect 类别的 MasterVolume 属性设定的音量。

例如游戏程序想呈现环绕音效的效果,可以先把欲播放的声音文件加入到 Content Pipeline 项目中,然后于 Game1 类别宣告以下的变量,负责管理音效资源、SoundEffectInstance 类别的对象、以及记录音效移动的方向:

SoundEffect RingOut;										//管理音效資源的變數
SoundEffectInstance RingOutEffect;			//管理 SoundEffectInstance 類別的物件的變數
bool bPaneLeft = false;								//記錄音效移動方向的變數

宣告妥变量之后请于 Game1 类别的 LoadContent 方法加入以下的程序代码,负责加载音效资源和建立 SoundEffectInstance 类别的对象:

RingOut = Content.Load<SoundEffect>("RingOut");		//載入名稱為 RingOut 的音效資源
RingOutEffect = RingOut.CreateInstance();		//建立 SoundEffectInstance 類別的物件
RingOutEffect.IsLooped = true;							//設定音效要不斷地重覆播放

加载音效资源并建立妥 SoundEffectInstance 类别的对象之后,我们只要在 Game1 类别的 Update 方法中变更 SoundEffectInstance 类别的对象的 Pan 属性的内容值,就可以变更音效发声的位置,例如以下的程序:

if (bPaneLeft)								//判斷音效發聲的位置是否為往左移動
{
    if (RingOutEffect.Pan - 0.1 <= -1)					//如果已經無法往左移動
    {
        RingOutEffect.Pan = -1f;							//設定音效從左方發聲
        bPaneLeft = true;								//設定移動方向為往右移動
    }
    else
        RingOutEffect.Pan -= 0.1f;						//設定發聲位置往左移動 0,1
}
else												//音效發聲的位置為往右移動
{
    if (RingOutEffect.Pan + 0.1 >= 1)					//如果已經無法往右移動
    {
        RingOutEffect.Pan = 1f;							//設定音效從右方發聲
        bPaneLeft = false;							//設定移動方向為往左移動
    }
    else
        RingOutEffect.Pan += 0.1f;						//設定發聲位置往右移動 0,1
}

做好之后请执行程序,游戏程序播放的音效就会从逐渐移至右方发声,移至最右方之后再逐渐移至左方进行发声,移至最左方之后再逐渐移至右方进行发声,周而复始,仿真音效环绕的效果。

[提示]

以 XNA 为基础的游戏程序可以使用类似的技巧控制所播放的音效的音调和音量,仿真音量由大变小,由小变大,或是音调由高变低,或是由低变高的效果。

动态音效支持

XNA Game Studio 4.0 在支持音效控制方面加入了一些新的控制功能,包括支持从 PCM 格式的音效数据流建立 SoundEffect 类别的对象,直接从 PCM 格式的音效数据流进行播放动态音效的功能,以及录制从麦克风输入的声音的功能,详细说明如下:

  • XNA Game Studio 4.0 支持的 SoundEffect 类别的建构函式允许接受 PCM 格式的数据流型态的参数,建立能够从 PCM 格式的数据流播放音效的 SoundEffect 类别的对象。以下就是一个能够利用第一个参数指定 PCM 格式的音效数据流用来建立 SoundEffect 类别的对象的建构函式:
public SoundEffect (
         byte[] buffer,
         int sampleRate,
         AudioChannels channels
)

以下就是利用 TitleContainer 类别的 OpenStream 方法从扩展名为 .wav 格式的声音文件读入 PCM 格式的音效数据流,再据以建立 SoundEffect 类别的对象:

SoundEffect soundFromFile = SoundEffect.FromStream(TitleContainer.OpenStream(
@"Content\Sample.wav")); 		//利用 WAV 格式音效檔案的內容建立 SoundEffect 類別的物件
soundFromFile.Play();					//播放 SoundEffect 類別的物件管理的音效資料

使用上述的方式播放音效数据流,以 XNA 为基础的游戏程序仍然需要将欲播放的 WAV 格式的声音文件预先加入到 Content Pipeline 项目,但是必须将 WAV 格式的声音文件的 [Build Action] 属性的内容值从默认的 Compile 改成 Content,再将 [Copy to Output Directory] 属性的内容值改成:Copy always,表示不要将 WAV 格式的声音文件建置成 XNB 格式的二进制数据,而要随着游戏程序一起部署到 Windows Phone 7 智能型手机,供游戏程序执行时期加载使用,并直接从 WAV 格式的声音文件加载欲播放的音效。

[注意]

第一个参数限制必须为 PCM 格式、频率为 8KHz 或 48KHz、单声道或立体声的音效数据。

  • 除了 SoundEffect 类别能够支持播放格式为音效数据流的音效之外,XNA Game Studio 4.0 提供的 DynamicSoundEffectInstance 类别也支持游戏程序于运行时间建立音效数据,供游戏程序执行的时候播放。DynamicSoundEffectInstance 类别常用的属性请参考表1 的说明:
表1:DynamicSoundEffectInstance 类别常用的属性
属性名称 说明
IsLooped 控制音效是否要不断地重复播放的属性。
Pan 控制音效发声位置的属性。
PendingBufferCount 查询放置播放音效数据的缓冲区数目。
Pitch 控制音调高低的属性。
State 表示音效播放状态的属性,可能状态为:playing (播放中)、paused (暂停)、stopped (停止)。
Volume 控制音量大小的属性。

DynamicSoundEffectInstance 类别常用的方法请参考表2 的说明:

表2:DynamicSoundEffectInstance 类别常用的方法
方法名称 说明
Apply3D 播放 3D 效果的音效。
GetSampleDuration 依据存放音效数据的缓冲区的数据量计算音效长度。
GetSampleSizeInBytes 依据存放音效数据的缓冲区的时间长度计算数据量。
Pause 暂停播放音效。
Play 执行播放音效的动作。
Resume 恢复播放音效的动作。
Stop 停止播放音效。
SubmitBuffer 指定存放音效数据的缓冲区为欲播放的音效。

表3:DynamicSoundEffectInstance 类别常用的事件
方法名称 说明
BufferNeeded 当存放音效数据以供播放的缓冲区数目小于或等于 2 时引发的事件。

欲使用 DynamicSoundEffectInstance 类别执行动态音效播放,您可以于 Game1 类别宣告以下的变量:

DynamicSoundEffectInstance dynamicSound;			//管理 DynamicSoundEffectInstance 類別
//的物件的變數
int position;							   //指定從第幾個位元組的音效資料開始播放
int count;										//指定欲播放的音效的位元組數
byte[] byteArray;								//存放音效資料的位元組陣列

然后于 Game1 类别的 LoadContent 方法加入以下的程序代码,从声音文件读入欲播放的音效数据:

Stream waveFileStream = TitleContainer.OpenStream(
@"Content\RingOut.wav"); 			//依據欲播放的音效檔案建立 Stream 類別的物件
BinaryReader reader = 
new BinaryReader(waveFileStream);//為 Stream 類別的物件建立 BinaryReader 類別的物件

int chunkID = reader.ReadInt32();								//讀取 Chunk ID
int fileSize = reader.ReadInt32();								//讀取檔案大小
int riffType = reader.ReadInt32();								//讀取 riff 型態
int fmtID = reader.ReadInt32();									//讀取 fmt ID
int fmtSize = reader.ReadInt32();								//讀取 fmt 大小
int fmtCode = reader.ReadInt16();								//讀取 fmt code
int channels = reader.ReadInt16();							    //讀取 channel 數目
int sampleRate = reader.ReadInt32();							//讀取 Sample Rate
int fmtAvgBPS = reader.ReadInt32();							   //讀取 fmt 的平均 BPS
int fmtBlockAlign = reader.ReadInt16();					//讀取 fmt Block Align 數據
int bitDepth = reader.ReadInt16();								//讀取位元深度

if (fmtSize == 18)										    //如果 fmt 大小為18
{
      int fmtExtraSize = reader.ReadInt16();					  //讀取 fmt 額外的大小
      reader.ReadBytes(fmtExtraSize);			       //讀入等同於 fmt 額外大小的資料
}

int dataID = reader.ReadInt32();								//讀取音效資料 ID
int dataSize = reader.ReadInt32();							   //讀取音效資料大小

byteArray = reader.ReadBytes(dataSize);	         //將音效資料大小的音效資料讀入到緩衝區
dynamicSound = new DynamicSoundEffectInstance(sampleRate, (AudioChannels)
channels);		//依據 Sample Rate 和 Channel 建立 DynamicSoundEffectInstance 類別的物件
count = dynamicSound.GetSampleSizeInBytes(
TimeSpan.FromMilliseconds(100));		//依據依據存放音效資料時間長度計算資料量
dynamicSound.BufferNeeded += new EventHandler<EventArgs>(
DynamicSound_BufferNeeded);			//指定處理 BufferNeeded 事件的事件處理程序
dynamicSound.Play();				//播放 DynamicSoundEffectInstance 類別的物件管理的音效

接下来请为 Game1 类别加入以下的方法,负责处理 DynamicSoundEffectInstance 类别的对象的 BufferNeeded 事件:

void DynamicSound_BufferNeeded(object sender, EventArgs e)
{
    dynamicSound.SubmitBuffer(byteArray, position, 
count);			//從 byteArray 陣列第 position 位元組開始,取出 count 個位
//元組供 DynamicSoundEffectInstance 類別的物件進行播放
    position += count;								//遞增 position 變數的內容值
    if (position + count > byteArray.Length)	  //如果 byteArray 陣列的內容已全部播放完畢
    {
        position = 0;							//將 position 變數的內容值歸零
    }
}

[注意]

使用上述的方式播放音效数据流,以 XNA 为基础的游戏程序仍然需要将欲播放的 WAV 格式的声音文件预先加入到 Content Pipeline 项目,但是必须将 WAV 格式的声音文件的 [Build Action] 属性的内容值从默认的 Compile 改成 Content,再将 [Copy to Output Directory] 属性的内容值改成:Copy always,表示不要将 WAV 格式的声音文件建置成 XNB 格式的二进制数据,而要随着游戏程序一起部署到 Windows Phone 7 智能型手机,供游戏程序执行时期加载使用,并直接从 WAV 格式的声音文件加载欲播放的音效。

做好之后请按下 Ctrl+F5 组合键执行游戏程序,就可以听到 DynamicSoundEffectInstance 类别的对象播放的动态音效。

  • XNA Game Studio (4.0) 提供的 Microphone 类别可以协助程序利用 Windows Phone 7 内建的麦克风录制外界输入的声音。有关 Microphone 类别常用的属性可以参考表4 的说明:
表4:Microphone 类别常用的属性
属性名称 说明
All 取得所有可用的麦克风。
BufferDuration 存放从麦克风输入的音频数据的时间长度。
Default 取得默认使用的麦克风。
IsHeadset 判断是否为耳机式麦克风。
SampleRate 取得使用麦克风执行录音时的 Sample Rate。
State 取得麦克风录音的状态。

Microphone 类别常用的方法可以参考表5 的说明:

表5:Microphone 类别常用的方法
方法名称 说明
GetData 从麦克风取得最新录制的声音资料。
GetSampleDuration 查询缓冲区中待播放的音效数据的时间长度。
GetSampleSizeInBytes 查询利用麦克风录制指定时间长度的声音需要的字节数。
Start 开始录制声音的动作。
Stop 结束录制声音的动作。

Microphone 类别常用的事件请参考表6的说明:

表6:Microphone 类别常用的事件
方法名称 说明
BufferReady 当存放录制声音数据的缓冲区准备好可供播放时引发的事件。

接下来我们就要利用 Microphone 类别提供的类别,录制透过 Windows Phone 7 内建的麦克风输入的声音,供程序进行播放。

首先请于 Game1 类别宣告以下的变量,负责管理 DynamicSoundEffectInstance 类别的对象:

DynamicSoundEffectInstance sound;

然后于 Game1 类别的 Initialize 方法加入以下的程序代码,负责启动录音的动作:

sound = new DynamicSoundEffectInstance(Microphone.Default.SampleRate, 
AudioChannels.Mono);			//利用麥克風預設的 Sample Rate 錄製單聲道的聲音

//處理錄製妥透過麥克風輸入的聲音引發的 BufferReady 事件
Microphone.Default.BufferReady += (a, b) =>
{
    byte[] data = new byte[Microphone.Default.GetSampleSizeInBytes(
Microphone.Default.BufferDuration)];		//建立存放聲音資料的位元組陣列
    Microphone.Default.GetData(data);		//取得錄製的聲音,並儲存到 data 位元組陣列中
    sound.SubmitBuffer(data);		//將位元組陣列的內容交給 DynamicSoundEffectInstance 類
//別的物件進行播放
};
Microphone.Default.Start();					//啟動麥克風執行錄製聲音的工作

最后我们只要在 Game1 类别的 Update 方法中加入以下的程序代码,在录制5秒钟的声音之后停止录制的动作,并将录制妥的声音交由 DynamicSoundEffectInstance 类别的对象进行播放:

if (gameTime.TotalGameTime.TotalSeconds > 5)			//如果錄製的時間是否超過 5 秒
{
    Microphone.Default.Stop();							//關閉麥克風錄音的功能
    sound.Play();	//將錄製妥的聲音交由 DynamicSoundEffectInstance 類別的物件進行播放
}

做好之后请执行程序,然后对麦克风讲话,5 秒钟之后,程序就会播放刚刚录制的声音。

范例下载:AdvSoundEffect.zip

认识 XACT (Cross-platform Audio Creation Tool) 声音组识与管理工具

XNA Game Studio 除了提供类别库供游戏程序制作所需要的功能以外,也提供了一系列辅助游戏开发的工具,包括:Microsoft Cross-Platform Audio Creation Tool 3 (XACT3)、XACT Auditioning Utility、和 XNA Framework Remote Performance Monitor,其中的 Microsoft Cross-Platform Audio Creation Tool 3 是一个支持声音组识与管理的工具,可以将游戏程序需要使用的音效事先组织妥当,并设定好必要的属性,降低游戏程序制作因管理音效的播放衍生的复杂性。

[注意]

Windows Phone 7 平台目前尚未支持使用 Microsoft Cross-Platform Audio Creation Tool 3 工具建立的声音文件,所以使用 Microsoft Cross-Platform Audio Creation Tool 3 工具建立的声音文件只能供在 Windows 平台和 Xbox 360 游戏平台上执行的游戏程序使用。

要使用 Microsoft Cross-Platform Audio Creation Tool 3 工具组识和管理游戏程序执行时期欲播放的音效,请执行 [所有程序 | Microsoft Game Studio 4.0 | Tools | Microsoft Cross-Platform Audio Creation Tool 3 (XACT3)] 功能,启动 XACT3 工具,然后执行 [File | New Project] 功能建立新项目。项目建立成功之后请使用鼠标的右键点中名称为 [Wave Banks] 的项目,从出现的菜单选择 [New Wave Bank] 功能,执行建立 Wave Bank 的工作,然后从档案总管将欲管理的 .WAV 格式的声音档案拖曳至新建立的 Wave Bank 中。做好之后请使用鼠标的右键点中名称为 [Sound Banks] 的项目,从出现的菜单选择 [New Sound Bank],执行建立 Sound Bank 的工作,建立好 Sound Bank 之后,请从 Wave Bank 窗口将欲管理的声音文件拖曳至新建立的 Sound Bank 窗口的下方窗口中,得到一个预设的 Cue Name,请注意 Cue Name 即为游戏程序播放 XACT3 管理的音效的名称。当我们从 Wave Bank 窗口将欲管理的声音文件拖曳至新建立的 Sound Bank 窗口的下方窗口时,Sound Bank 窗口的上方窗口也会自动加入一个新项目,您可以点选这个项目,再利用 XACT3 工具左下角的窗口设定音效的属性,例如您可以设定音效重复播放的次数 (设定 Looping 属性,勾选 Infinite 字段表示要不断地重复播放),如图1 所示:

图1:使用 XACT3 工具管理游戏程序欲使用的音效的画面

设定完成后请储存项目,然后将 XACT3 工具关闭,所储存的项目是一个扩展名为 .xap 的档案,我们只要将这个档案加入到游戏程序的 Content Pipeline 项目中,就可以供游戏程序执行的时候加载播放。

要使用 Content Pipeline 项目中利用 XACT3 工具建立的声音文件,游戏程序可以在 Game1 类别中宣告下列的变量:

AudioEngine audioEngine;								//管理音效播放工作的變數
WaveBank waveBank;									//管理 Wave Bank 內容的變數
SoundBank soundBank; 								//管理 Sound Bank 內容的變數

然后在 Game1 类别的 Initialize 方法中加入以下的程序代码,建立管理音效播放工作的对象、管理 Wave Bank 内容的对象、以及管理 Sound Bank 内容的对象:

audioEngine = new AudioEngine("Content\\MyAudio.xgs");	    //建立 AudioEngine 類別的物件
waveBank = new WaveBank(audioEngine, 
"Content\\Wave Bank.xwb");				      //建立 Wave Bank 類別的物件
soundBank = new SoundBank(audioEngine, 
"Content\\Sound Bank.xsb"); 					//建立 Sound Bank 類別的物件

请注意建立 AudioEngine 类别对象时指定的是 XACT3 的项目名称,其扩展名为 .xgs,建立 WaveBank 类别的对象时指定的是 Wave Bank 的名称,其扩展名为 .xwb,而建立 SoundBank 类别的对象时指定的是 Sound Bank 的名称,其扩展名为 .xsb。

建立好必要的对象之后,请于 Game1 类别的 Update 方法加入以下的程序代码,准备欲播放的音效内容,并呼叫 AudioEngine 类别对象的 PlayCue 方法执行播放音效的动作:

audioEngine.Update();
soundBank.PlayCue("RingOut");

请注意呼叫 AudioEngine 类别对象的 PlayCue 方法所传入的是 Cue Name,意即要播放 Cue Name 所代表的声音文件。做好之后只要执行程序就可以听到程序播放 XACT3 工具管理的音效。

原文链接: http://msdn.microsoft.com/zh-cn/windowsphone/gg491392.aspx

加载中
返回顶部
顶部