[音樂] FMOD 快速上手

看板GameDesign (遊戲設計)作者 (我要加入劍道社!)時間18年前 (2006/12/30 13:48), 編輯推噓8(800)
留言8則, 7人參與, 最新討論串1/1
好像很少人討論到聲音這一塊,因此我就獻醜了。下面所說的是我使用 FMOD 第一天的小小成果,因為我並沒有聲音方面的專業知識,如有錯誤 請多多指教。 * * * 聲音一向是遊戲中不可或缺的一部份,不管是動人的背景音樂或營造氣 氛的音效,少了聲音就完全沒有玩遊戲的感覺,甚至許多遊戲的重點就 放在聲音上,比如說利用聲音來判斷敵人的位置等等。 從遊戲開發者的角度來看,在聲音方面至少有以下的需求: 1. 讀取音樂/音效檔案。當然,音樂資料不一定存在檔案上,也可能 放在 CD 音軌上,甚至使用 streaming 的方式由網路傳輸(很少 見,但也並非不可能)。 2. 背景播放。除了把聲音放出來,播放的同時也要能讓遊戲繼續執行。 3. 混音。對於硬體來說,同一時間只能播放一個聲音。有些硬體內建 混音的功能,因此可以同時播放多道聲音,不過數量還是有上限。 超過上限時就需要把所有正在播出的聲音進行混合後,再送到音效 卡上。 (在 Windows 上,送到音效卡之前似乎會自行幫你混音,所以這點 對 Windows 開發者也許不是太大的問題) 4. 各種聲音效果,比如設定聲源的位置以模擬方向與遠近的不同,或 是設定速度來模擬運動物體的都卜勒效應 (Dopplar effect),甚至 各種 DSP 處理等等。 而我今天要講的,稱之為 FMOD 的音效函式庫,正具備了以上所有功能。 除此之外,它也有跨平台的優點,除了 Windows 外,也支援 MacOS、 Linux 甚至所有的次世代主機,如 PS3、Xbox 360、Wii 等等。而且在 非商業用途下完全免費,是個很理想的音效解決方案。 廢話不多說,下面就來講 FMOD 的使用。 * * * 在 FMOD 中主要有三種物件:System、Sound 以及 Channel。因為我才 用一個晚上而已,所以像是 ChannelGroup、DSP 及 Geometry 的部份 就不深入了... * System 管理與系統相關的工作,比如說從檔案系統中讀取聲音檨本、 設定輸出的音效卡(FMOD 可以同時控制多張音效卡)、設定 DSP buffer 大小、或是載入其它的 plug-in 等。 * Sound 則是一段聲音的樣本 (sample),已經準備好送往音效卡播出。 Sound 的內部格式可能有三種:無壓縮、壓縮或串流: * 無壓縮 最單純的格式,直接把所有資訊存在記憶體中,播放 時幾乎不需要 CPU 資源,但也很吃記憶體。適合長度 短、會重覆播放許多次的音效。 * 壓縮 如果使用 mp3 或 ogg 之類的格式儲存聲音,可以把 資料以尚未解壓縮的方式先讀進記憶體中,播放時再 即時解壓縮。這會需要多一點 CPU 資源,但可以減少 記憶體用量,適合中等長度的聲音。 * 串流 在串流模式下,讀取和播放是同時進行的,而記憶體 中只會保留一小部分的樣本,因此幾乎不吃記憶體, 但缺點是無法重覆播放,必需重開檔案或重新連線才 能再播放一次。適合很長的背景音樂或是由網路傳輸 的聲音。 * Channel 代表正在播放聲音的實體。對於 Channel,你可以設定它 的音量、播放的時間點、或是它在 3D 空間中的位置與速度。一個 Channel 只能播放一個 Sound,但同一個 Sound 可以讓由不同的 Channel 共享並同時播放。 馬上就來寫一個簡單的音樂播放程式。 * * * 一開始我們要先產生一個 System 物件,這可以用 FMOD_Create_System 達成: FMOD_SYSTEM* sys; FMOD_RESULT r = FMOD_Create_System(&sys); if(r != FMOD_OK){ cerr << "Unable to create FMOD system: " << FMOD_ErrorString(r) << endl; exit(1); } 所有 FMOD 的函式都會傳回 FMOD_RESULT 作為結果,我們可以檢查它是 否等於 FMOD_OK 來判斷是否有錯誤發生。為了簡單起見,下面的 code 中我會把這些檢查省略。(開始寫遊戲時可別省啊!) 接下來是對 System 初始化,並且載入一段 mp3 聲音: FMOD_System_Init(sys, 32, FMOD_INIT_NORMAL, 0); FMOD_SOUND* sound; FMOD_System_CreateSound(sys, "test.mp3", FMOD_DEFAULT, 0, &sound); 在 FMOD_System_Init 中,第一個參數是先前產生的 System 物件,第 二個 32 則表示這個系統最多可以有 32 的 Channel,也就是最多可以 同時播放 32 道聲音。第三和第四個參數可以設定一些進階的選項,在 這個例子中都使用預設值即可。 而 FMOD_System_CreateSound 則會產生一個 Sound 物件。第一個參數 同樣是 System,第二個則是我們要載入的聲音檔名稱,FMOD 會自行判 斷檔案格式並把它解壓縮。如果想用壓縮或串流的方式讀檔,則需要設 定第三個參數,這邊我們就先使用預設值。 最後就是把聲音放出來: FMOD_CHANNEL* channel; FMOD_System_PlaySound(sys, FMOD_CHANNEL_FREE, sound, 0, &channel); FMOD_System_PlaySound 會讓某個 channel 開始播放聲音。其中第二個 參數可以指定我們要拿哪一個 Channel 來播放,傳入 FMOD_CHANNEL_FREE 則是叫 FMOD 自行找一個可使用的 Channel 來播放。 但,程式並非到此就結束,別忘了聲音播放是在背景執行的,如果在這 邊就結束程式,聲音也會馬上停止。因為這只是個簡單的播放程式,因 此只要進入一段迴圈等聲音播完即可: FMOD_BOOL playing = 1; while(playing){ #ifdef WIN32 Sleep(10); #else usleep(10000); #endif FMOD_Channel_IsPlaying(channel, &playing); FMOD_System_Update(sys); } 我使用了 unix 上的 usleep,因此迴圈中的程式碼每 0.01 秒會執行一 次。Windows 上則改用 Sleep。 FMOD_Channel_IsPlaying 可以拿來檢查 Channel 是否已經放完全部的 聲音,因此聲音播放完就可以跳出迴圈。FMOD_System_Update 則是更新 System,包括呼叫 callback 或是設定聲音的 3D 位置等。在這例子中 可能不太重要,但若使用到其它功能時就一定要呼叫 update 了。 最後播放完,則使用 FMOD_Sound_Release 與 FMOD_System_Release 釋 放系統資源: FMOD_Sound_Release(snd); FMOD_System_Release(sys); 這麼一來這個簡單的播放程式就完成了!接下來我們加上一點 3D 效果 吧。首先我們要在建立 Sound 時指定 3D 的功能: FMOD_System_CreateSound( sys, "test.mp3", FMOD_LOOP_OFF | FMOD_3D | FMOD_HARDWARE, 0, &sound ); 這邊看起來有點複雜,但其實只是指定這個聲音並不重覆播放 (FMOD_LOOP_OFF)、 加入 3D 效果 (FMOD_3D) 以及使用硬體加速 (FMOD_HARDWARE)。先前所 使用的 FMOD_DEFAULT 其實只是把 3D 改成 2D 而已,其它選項完全相同。 接下來我們可以用 FMOD_Channel_Set3DAttributes 來設定 Channel 在 空間中的位置及速度: FMOD_VECTOR pos; pos.x = 0.0f; pos.y = 0.0f; pos.z = 2.0f; FMOD_Channel_Set3DAttributes(channel, &pos, NULL); 第二個參數即為位置,使用者預設是位於 (0,0,0) 的地方,前方為正Z 軸,左方為正X,上方為正Y。第三個參數則是速度,如果不需要模擬 都卜勒效應,給 NULL 即可。 上面的程式碼會把音源放在使用者前方兩個單位的位置。當然,如果聲 源不會移動,就沒有意思了: while(playing){ #ifdef WIN32 Sleep(10); #else usleep(10000); #endif FMOD_Channel_IsPlaying(channel, &playing); unsigned int msec; FMOD_Channel_GetPosition(channel, &msec, FMOD_TIMEUNIT_MS); float angle = 3.1415926f * msec / 4000.0f; pos.x = 2.0f * sin(angle); pos.z = 2.0f * cos(angle); FMOD_Channel_Set3DAttributes(channel, &pos, NULL); FMOD_System_Update(sys); } 這邊我們會讓聲源繞著使用者轉圈圈,使用 FMOD_Channel_GetPosition 可以得到目前播放的時間點,由這個時間乘上速度(八秒鐘一圈,也就 是四秒鐘所轉動的弧度為 PI),即可得到轉動角,再套上 sin/cos 就 可以得到新的位置了。 完整的程式碼如下: http://nopa.csie.org/bd9c9 完整程式加了一些錯誤處理,並且使用命令列參數當作播放檔案。執行 時要先等一段時間(因為使用非壓縮的方式),然後應該能聽到聲音在 繞著使用者轉圈圈。 * * * FMOD 在使用上還滿簡單的,複雜的解壓縮、混音、硬體控制等全部都被 包裝起來,因此遊戲製作人員不需要再花額外的功夫處理。唯一不滿的 地方就是它的 C++ interface 實在設計不良,完全沒有用到 C++ 威力 (連 OOP 都沾不上邊),這也是為什麼我都使用 C interface 的原因: 兩者並沒有明顯的不同。 撇開這不談,FMOD 功能夠強、跨平台又免費,的確很適合製作遊戲。當然 早有許多商業或免費遊戲使用 FMOD 來播放聲音。 -- ※ 發信站: 批踢踢實業坊(ptt.cc) ◆ From: 61.62.3.35 ※ 編輯: littleshan 來自: 140.112.29.131 (12/30 17:14)

12/30 17:16, , 1F
這篇讚 推~
12/30 17:16, 1F

12/31 04:22, , 2F
感謝前輩的分享
12/31 04:22, 2F

12/31 11:13, , 3F
推 期待您的下一篇
12/31 11:13, 3F

12/31 20:50, , 4F
剛剛查了一下,如果商業話化的話要3000USD ._.a
12/31 20:50, 4F

01/01 00:10, , 5F
便宜啊 你找個programmer付他3000USD還不見得寫的出FMOD
01/01 00:10, 5F

01/01 20:22, , 6F
也是._.a
01/01 20:22, 6F

01/02 11:29, , 7F
push!!!
01/02 11:29, 7F

04/06 23:29, , 8F
push!
04/06 23:29, 8F
文章代碼(AID): #15bVsmdt (GameDesign)
文章代碼(AID): #15bVsmdt (GameDesign)