■ 新・ゲーム開発講座 |
■ へっぽこプログラミング入門♪ |
■第37夜:MP3の再生 今回はMP3再生のリクエストがありましたので、BBSで教えていただいたMCIコマンド(大山さん感謝♪^^;)でお手軽再生を行う方法をご紹介したいと思います。方法は第34夜のMIDI再生と殆ど同じですので、アルゴリズムの詳細に関しては第34夜を読んでいただくこととして、エッセンスの部分を中心に行きたいと思います。スクリプトのコマンドとしては以下の書式で実装することに致しましょう。ゲームのBGM再生を想定していますのでMIDI同様にループ再生専用とし、またMP3ファイルの置き場所はMIDIファイルと同じフォルダにします(同じ音楽ファイルとゆーことで ^^)。
|
■MP3演奏について 既に第34夜で解説したMIDIと同様に、MP3もマルチメディアライブラリの使用で演奏可能です。winmm.lib と mmsystem.h をプロジェクトに加えればOKです。ここでは第34夜と同様に mciSendString() 関数でMCIコマンド文字列を送出することによって演奏を行います。要領は以下の通りです。 【MP3ファイルのOPEN】 |
mciSendString("open ABC.MP3 type mpegvideo alias _MP3_",NULL,0,NULL); |
MIDIの場合は type が sequencer でしたが、MP3 はなんと mpegvideo の範疇に入るようです。MP3 = Mpeg Layer 3 だそうですのでMCIコマンドではそういう扱いになっているようです。なお上記コマンド文字列中の _MP3_ は演奏するファイルを内部的に識別するためのシンボル名で、好きな名前に変更可能です。またファイルOPENに成功したかどうか確かめるには、以下のようにします(MIDIと同じですね)。成功していればバッファ buf に "true" の文字列が入ります。 |
char buf[32]; mciSendString("capability _MP3_ can play wait",buf,31,NULL); |
【演奏開始】 演奏の開始はMIDIと同じ要領で play 命令で行います。下の例ではループ演奏を前提に、演奏終了通知指定(notify)つきでコマンドを発行しています(ループ演奏しない場合は "notify" の文字をとってしまえばOKです)。 |
mciSendString("play _MP3_ notify",NULL,0,hwnd); |
notify オプションをつけた場合は、演奏終了時に hwnd で指定したウィンドウのイベントハンドラに MM_MCINOTIFY というイベントメッセージが降ってきます。イベントハンドラの引数 wprm の内容が MCI_NOTIFY_SUCCESSFUL だったら演奏が正常終了したことを示します。演奏終了を検知したところでもういちど演奏を開始すればループ再生になるのはMIDIと一緒です。 ただし、MM_MCINOTIFY というイベント名は演奏がMIDIだろうがMP3だろうがCD-DAだろうが全部一緒(このへんのセンスのなさがMS的とゆーか何と言うか・・・ ^_^;) なので、MIDIと同居させるときは注意が必要です。プログラム側で「何のデバイスを演奏していたのか」という情報を把握していないときちんとしたループ再生はできません。 【演奏停止】 |
mciSendString("stop _MP3_",NULL,0,NULL); |
なお演奏が終了したら、開いたMP3ファイルは以下のようにクローズしておきましょう。 |
mciSendString("close _MP3_",NULL,0,NULL); |
要領としてはMIDIとほとんど同じなので、第34夜の記事を理解できればそれほど難しくはないと思います(^^)。
さて、基礎的なことが分かったところで、これをスクリプトコマンドの形で実装してみましょう。MIDI演奏と要領はまったく一緒なので、ここでは第34夜で作成したMIDI演奏関数をコピー&ペーストしてMP3版に改造することにします(なんて安易 ^^;)。なおソースはこちらになります。曲を提供して頂いた某所の某氏(最近はアフガンで神の声を聞いているそうですが… ^^;)に感謝の意を表しつつ、以下の解説を参考にしながら内容を確認してみてください。 |
#define _MIDI 0 struct _MIDI_stat {
extern _MIDI_stat MIDI_stat; |
そしてMP3演奏とごちゃまぜにならないよう、あらかじめMIDI演奏部にこのフラグのチェック/操作部分を設けておきます(Text_Com_03.cpp)。 |
//----------------------------------------------------------- _MIDI_stat MIDI_stat; //MIDI演奏のステータス保持用 int Com_play_midi()
//----------------------------------------------------------- int Com_restart_midi()
//----------------------------------------------------------- int Com_stop_midi()
|
MIDI演奏部分の改造(・・・というほどのものでもないですが:笑)が終わったら、これらの3関数をコピー&ペーストしてしまいます。面倒ですので同じソースファイル Text_Com_03.cpp の末尾に貼り付けちゃいましょう。そして各関数名の Com_play_midi() Com_stop_midi() Com_stop_midi() をそれぞれ Com_play_mp3() Com_stop_mp3() Com_stop_mp3() に変更します。関数の内容を変更する箇所は コマンド文字列 とフラグ設定くらいで、あとはコメント部分を MIDI → MP3 に直すくらいです。うーん、簡単ですね(^0^) |
//----------------------------------------------------------- int Com_play_mp3()
} //----------------------------------------------------------- int Com_restart_mp3()
//----------------------------------------------------------- int Com_stop_mp3()
|
さて、安直に関数本体をコピー&ペーストで作ったら、この関数を呼び出す部分を作成しましょう。TextEngine.cpp のコマンド処理呼び出し関数 Command_call() に、以下のような追加を行います。 |
void Command_call() {
} |
さらに、ループ再生を行うためにイベントハンドラ WndProc() を以下のように書き換えます(main.cpp)。いままでMIDI用のループ再生関数を呼んでいた部分を、フラグによって MIDI/MP3 の判定をしながら適切な処理を呼び出すように変更する訳ですね。 |
LRESULT WndProc(HWND hwnd,UINT msg,WPARAM
wprm,LPARAM lprm) {
} |
そして仕上げに終了処理関数 Sys_exit() にMP3の後始末を書き加えます(quit.cpp)。この関数はプログラムの終了時に呼び出されるもので、演奏デバイスをOPENしたまま強制終了することを防ぐ意味合いがあります。(詳細はMIDI再生の項を参照願います) |
void Sys_exit() {
|
さて、如何でしたでしょうか。MCIコマンドでこんなに簡単にMP3の演奏が出来るとは私も知らなかったので、自分でも感心することしきりです(笑)。統一した手法でマルチメディアを扱えるように、というMCIの設計意図はたしかに恩恵があるわけですね。願わくばこーゆー(誰もが関心を持つであろう)情報はHELPで簡単に解説が出てくるようにして欲しいのですが、残念ながらコンパイラ付属のCD-ROMでは検索しても情報は得られませんでした。・・・まあ、MSの商魂を考えれば 「別途リファレンスマニュアル(途方も無く高額)を買え」 とゆーことなのかも知れませんが♪(爆 ^0^) とゆーことで、今回はこのへんで・・・♪ |