Ø Sound Manipulation
Ø Sound Looping
Ø SoundEffectInstance



相對於前一章的Cowbell 應用程式來說,本章的Trombone是一個更加專業的樂器應用。我們可以通過控制滑片的上下移動來發出對應的音階(應用程式中滑片的位置並非從F調開始,這一點與實際的trombone滑片位置有所不同)。本應用程式支援兩種不同的滑片模式。如果我們觸摸左邊螢幕的話,可以自由地移動滑片。如果我們觸摸右邊螢幕的話,它會對齊到已經標注好的音階。這款軟體除了操作更加簡便以外,還可以用來作為定音管。



Trombone可以在兩個八度音程的範圍內發音,如果我們想要將一個音聲提高八度,把另一個手指放在螢幕的任何地方就可以實現。本應用程式最有趣的一點在於,與真實的長號一樣,我們必須對著手機吹氣,才能使其發出聲音。



應用程式的後兩個特點需要的功能會在後面的章節中進行介紹(多點觸摸以及麥克風的使用),因此,與這部分功能相關的代碼這裡不做介紹。相反,本章內容關注于單個音效的音高和音長操作,使其能夠滿足本應用程式的需求。



The User Interface

Trombone具有一個主頁面、一個介紹頁面和一個設置頁面。設置頁面的代碼本章不作介紹,那是因為除了頁面標題以外,它與第34章「Bubble Blower」應用程式的設置頁面幾乎一致。設置頁面使得使用者可以在音量過大或者過小時,對麥克風進行調整。介紹頁面的代碼這裡也不作介紹,因為它沒有特殊的地方。

主頁面的初始化狀態如圖31.1所示,包含了可移動的滑片、標注的音階和指向另外兩個頁面的連結按鈕。


21151643_4IAO  
圖31.1 主頁面模仿了長號的實際外觀

注意:

➔ 圖31.1中標注的音階線通過該頁面背後的cs代碼實現。

➔ 應用程式欄會遮擋應用程式的使用者介面,所以就用兩個長方形的按鈕來代替。我們使用熟悉的不透明範本來確保它們在不同主題下的顯示效果達到一致。

21151643_LnQu  

圖31.2 長號的滑片通過靜態圖片上添加一個可移動的圖片來實現



The Code-Behind

注意:

➔ 本應用程式長號發音時採用的音訊檔只有一個,那就是F調時的音訊檔。其他聲調的聲音是通過動態改變F調的聲音訊率來實現的。

➔ 前一章內容中,我們直接使用了SoundEffect物件,本應用程式調用SoundEffect中的CreateInstance方法來獲取SoundEffectInstance物件。與SoundEffect 相比,SoundEffectInstance提供了更多的特性,因為它與單個聲音實例進行綁定,所以即便是聲音已經開始播放,仍舊可以對它進行操作。一方面,Trombone應用程式需要SoundEffectInstance來完成週期性的任務;另一方面,SoundEffectInstance可以動態改變已播放的聲音的音階。

➔ SoundEffectInstance提供了一個IsLooped屬性(預設設置為false),它使得使用者可以無限期地迴圈播放一段音訊檔,直到調用Stop方法為止。按照音訊原始檔案的不同,它可以由兩種方法來實現:

1.對於一個普通的音訊檔來說,這種迴圈是應用在整段音訊範圍的。所以,在前一段播放結束時,會無縫地開始再一次播放。

2.對於一個有迴圈區域的音訊檔來說,第一次播放時,程式會從頭開始播放,但接下來的迴圈中,只有迴圈區域會被播放。一旦程式調用預設的Stop方法,聲音就停止播放。但是,如果我們重寫該Stop方法,並傳入false參數時,它會停止當前的播放,然後跳出該迴圈,並播放該段音訊的剩餘部分。

圖31.3展示了這兩種行為。後一種行為對於本應用程式來說正合適,因為它使用了一段真實的長號F調音訊,並且從聲音的開始到結束進行了平滑的過渡。因此,工程中包含的「F.wav」檔定義了一個迴圈區域。雖然該音訊檔的長度還不到三分之一秒,但使用迴圈區域的話,只要使用者能夠維持他對手機吹氣的動作,應用程式就可以播放任意長的時間。



21151644_SRdA  

圖31.3 SoundEffectInstance.IsLooped的屬性值設置為true

注意我們定義的迴圈區域的長度!

如果我們不想立即停止聲音的播放,而是在調用Stop(false)方法以後,慢慢地停止下來,那麼,我們定義的迴圈區域(以及音效檔的剩餘部分)必須盡可能得短。否則,結束當前的播放迴圈會佔用較長的時間。

Wavosaur (www.wavosaur.com) 是一個免費而且非常強大的音訊編輯器,通過它,我們可以在一個.wav檔內部創建一個迴圈區域。選中一個音效檔的部分區域,點擊「Tools」功能表中的「Loop」選項,然後點擊「Create」來創建迴圈區域。在正常的環境下,展開的.wav檔仍舊可以直接播放,但是使用SoundEffectInstance實例,並且將其IsLooped屬性設置為true的情況下,就會根據設置的迴圈區域來播放了。



SoundEffect VS. SoundEffectInstance

SoundEffect可以播放音效檔,而SoundEffectInstance可以利用其Pause、 Resume 和 Stop方法對某一個制定的音效檔進行暫停、繼續和停止操作。每次調用SoundEffect的Play方法後,就開始播放聲音的一個新實例,我們無法對其進行停止操作(它有可能會對之前播放的聲音產生影響);而調用SoundEffectInstance的Play方法時,如果該聲音的實例當前現正播放,那麼它不會做任何動作。因為SoundEffectInstance與一個制定的聲音實例進行了綁定,所以它同樣也具有State屬性,用於指示該聲音目前的狀態是處於播放、暫停或者停止。

除了IsLooped屬性以外,SoundEffectInstance還具有三個控制聲音效果的屬性。我們可以在任何時候對其進行設置,甚至在播放過程中也可以:

➔ Volume (預設值為1):範圍為0~1,其中0表示靜音,1表示最大音量。

➔ Pitch (預設值為0):範圍為-1~1,其中-1表示低八度音階,1表示高八度音階,0表示按照其原來的聲調播放。

➔ Pan(預設值為0):範圍為-1~1,其中-1表示只用左揚聲器發音,1表示只用右揚聲器發音,0表示左右平衡發音。

SoundEffect還可以通過接受volume、pitch 和 pan 這三個參數的Play方法重載來進行控制。但是,這些值會經常導致聲音播放時間的延長(在前一章,SoundEffect中的Play方法不帶任何參數,它的volume屬性為1,pitch 和 pan的屬性值為0)。

SoundEffectInstance也具有兩個重載的Apply3D方法,使得我們可以將三維的位置應用到聲音的播放過程中去。該特性對於Xbox和PC遊戲來說是非常有趣的。對於手機來說,三維的定位(甚至是自訂的pan屬性值)沒有多大用武之地。

注意:

➔ 在CompositionTarget.Rendering事件處理中,不斷地將麥克風獲得的當前音量值與一個門限值(在設置頁面中可以調整)進行比較。如果其值足夠大,而且聲音沒有播放,那麼程式就調用Play方法(並沒有必要對State屬性進行嚴查,那是因為,與SoundEffect.Play方法不同,SoundEffectInstance.Play方法在聲音現正播放的情況下,並不會疊加播放)。如果聲音現正播放,而麥克風的音量值不夠大,那麼程式就會調用Stop(false)方法,跳出播放迴圈,直到聲音結束。

➔ 在使用者的一個手指與手機螢幕接觸的情況下,另一個手指也觸摸到了螢幕,這會觸發Touch_FrameReported事件(詳細參考Part VII中的「Touch and Multi-Touch」章節),程式對聲音的音調進行調整。startingPitch變數會跟蹤基調F處於哪個音程(0代表原來的音階,1代表高八度音階),手指與螢幕底部之間的距離決定了音階下調的度。我們可以在代碼開始的音階陣列中發現,下調F音階25%可以獲得D音階(在原音階的基礎上下調0.25或者是原音階的0.75),同樣,下調F音階50%可以獲得B音階(在原音階的基礎上下調0.5或者是原音階的0.5)。

在手機主音量靜音的情況下,我可以聽到聲音嗎?我是否可以播放比主音量更大的聲音?

答案是否定的,因為使用者允許選擇播放的最大音量需要經過授權。一個範圍為0~1的音效volume參數值是相對於主音量來說的。注意,SoundEffect具有靜態的MasterVolume屬性,它可以同步調整所有聲音的音量(無論是通過SoundEffect播放或者是SoundEffectInstance播放),但是這種音量不會超過使用者選擇的音量值。


原文連結:HTTP://www.cnblogs.com/dearsj001/archive/2012/08/19/101App4WP7_Trombone.html

 

創作者介紹
創作者 shadow 的頭像
shadow

資訊園

shadow 發表在 痞客邦 留言(0) 人氣()