音声再生
目次
はじめに
HGIMG4を使って作ったゲームにも音をつけたいですよね。 少し困ったことがあったので、HSP3での音まわりも含めて情報を整理してみます。
HSP3での音の再生
HGIMG4を使って作ったゲームにも音をつけたいですよね。 少し困ったことがあったので、HSP3での音まわりも含めて情報を整理してみます。
まずHSP3で音声を再生する場合、標準では3種類の方法が用意されています。
- mci命令
- mmplay命令などmm系命令
- dmmplay命令などdmm系命令
特徴を整理してみました。
mci | mm系 | dmm系 | |
---|---|---|---|
プラグイン※ | 不要 | 不要 hsp3dish.as hgimg4.as | hspogg.as hgimg3.as |
プラットフォーム | |||
win | ● | ● | ● |
dish | × | ● | × |
フィル形式 | |||
WAV | ● | ● | ● |
MIDI | ● | ● | × |
CD-DA | ● | ● | × |
AVI | ● | ● | × |
MP3 | ● | ● | × |
ASF(ASF,WMV,WMA) | ● | ● | × |
MPEG | ● | ● | × |
OGG | × | × | ● |
その他 | |||
dpm | ? | ? | ● |
※ プラグインは、書いてあるどれか1つを導入すれば使用できます。
さらに、mm系とdmm系命令は同じような機能の命令が多いので比較してみました。 機能や使い方はどちらもよく似ており、命令名も頭にdがあるかないかの違いしかありません。 相互に乗り換えがしやすい作りになっています。hgimg3からhgimg4へ、またその逆も移植作業の負担が小さくて済みますね。
mm系 | dmm系 | |
---|---|---|
読み込み | mmload | dmmload |
再生 | mmplay | dmmplay |
再生停止 | mmstop | dmmstop |
パン設定 | mmpan | dmmpan |
状態取得 | mmstat | dmmstat |
音量設定 | mmvol | dmmvol |
初期化 | - | dmmini |
終了処理 | - | dmmbye |
設定をリセット | - | dmmreset |
削除 | - | dmmdel |
ループ設定 | - | dmmloop |
MCI
MCIは、HSP3で昔から使われている機能です。 コマンド文字列を与えて操作するのですが、資料が少なくてついこなせなかった記憶しか…。 詳しくは他のサイトにお任せします。
HSP3命令入門講座 <mci命令> - Let's HSP!
http://lhsp.s206.xrea.com/command/mci.html
以降はmm系/dmm系命令について記述していきます。
mm系命令
hgimg4を使用する場合は、mm系命令を使います。
hgimg4.asとhspogg.asは同時にinclude
することができないため、dmm系命令は使用することができません。
「#Error 38 外部DLLの呼び出しに失敗しました」が出てしまいます。
プラグインなしでも利用できるので、hgimg3を使用する場合もmm系命令を使用することができます。
使い方は簡単で、次のような手順です。
mmload
命令で音声ファイルを読み込んで メディアバッファID に割り当てる。mmplay
命令で メディアバッファID を指定して再生する。
基本的なサンプルを書いてみました。
;
; hsptvのSE素材を再生
; mm系命令
;
;#include "hsp3dish.as"
;#include "hgimg4.as"
; ファイル
fname = dir_tv + "se_bom.wav"
; サウンドを登録
id = 0
mmload fname, id
; 再生ボタン
button gosub "PLAY", *l_play
redraw 1
stop
; 再生ボタン
*l_play
;mmstop -1
mmplay id
return
stop
の前の redraw 1
は、hsp3dish/hgimg4を使用した際に必要になります。
redraw 1
をしないとボタンが描画されません。
dmm系命令
音声機能だけが必要な場合は、hspogg.asをinclude
して使用します。
hgimg3の音以外の機能も使用する場合は、hgimg3.asをinclude
して使用します。
hgimg3.asをinclude
すれば、hspogg.asをinclude
する必要はありません。
前述したとおり、hgimg4を使用する場合は使用できません。
dmmini
命令でサウンド機能を初期化(1回だけやればいい)dmmload
命令で音声ファイルを読み込んで サウンドID に割り当てる。dmmplay
命令で サウンドID を指定して再生する。
基本的なサンプルを書いてみました。
;
; hsptvのSE素材を再生
; dmm系命令
;
#include "hspogg.as"
; ファイル
fname = dir_tv + "se_bom.wav"
; サウンドを登録
dmmini
id = 0
dmmload fname, id
; 再生ボタン
button gosub "PLAY", *l_play
stop
; 再生ボタン
*l_play
;dmmstop -1
dmmplay id
return
mm系命令とほぼ同じでしたね。
HSPTVフォルダ素材
前述したサンプルでも使用していますが、HSP3にはゲームに使用できる素材ファイルが付属しています。 結構豊富なので、この素材だけでゲームを作って公開することもできます。開発用の仮の素材としても便利です。
HSPTVフォルダ素材一覧
https://www.onionsoft.net/hsp/v36/doclib/hsptv_res.htm
せっかくなので全部聞いてみようと思います。
どうやら hsptv_res.as をinclude
すると素材ファイルを一括で読み込めるみたいです。
これを使うと簡単そうですね。ちょっと作ってみました。
;
; 「HSPTVフォルダ素材」の使用例
;
; 「HSPTVフォルダ素材」
; https://www.onionsoft.net/hsp/v36/doclib/hsptv_res.htm
; の音楽素材を再生するサンプルです。
; hsp3dish.as / hgimg4.as を使用しなくても音を再生することはできます。
; どちらかをINCLUDEすると、再生開始のラグを低減させることができます。
; また、複数の音の同時再生ができるようになります。
;#include "hsp3dish.as"
;#include "hgimg4.as"
#include "hsptv_res.as"
;--------------------
; SE
;--------------------
hsptv_se 1 ;効果音をまとめて読み込む
repeat 15
button gosub "SE" + strf("%02d", cnt+1), *l_play_SE
objid_SE(cnt) = stat
idSE(cnt) = SE01 + cnt
loop
;--------------------
; SND
;--------------------
pos 100, 0
hsptv_se 2 ;効果音をまとめて読み込む
repeat 19
button gosub "SND" + strf("%02d", cnt+1), *l_play_SND
objid_SND(cnt) = stat
idSND(cnt) = SND01 + cnt
loop
redraw 1
stop
;--------------------
; SE 再生ボタン
;--------------------
; どのボタンが押されたかを判定して、再生する音を選択しています。
; ボタン1個にサブルーチン1個を準備するのが面倒だったので、
; このような実装にしています。
*l_play_SE
idBtn = stat ; 押されたボタンのオブジェクトID
repeat 15
if objid_SE(cnt) = idBtn {
mmplay idSE(cnt)
break
}
loop
return
;--------------------
; SND 再生ボタン
;--------------------
*l_play_SND
idBtn = stat
repeat 19
if objid_SND(cnt) = idBtn {
mmplay idSND(cnt)
break
}
loop
return
効果音だけでも結構たくさんありますね。 素材にこだわらないのであれば、ここにあるものだけでも十分かもしれません。
HSPTVフォルダ素材から音を選ぶ
hsptv_res.asを読み込んでしまうと、使わない素材も読み込んでしまいます。 配布するアプリ開発の場合は、必要なファイルだけを添付して配布したいです。
ということなので、HSPTVフォルダにある音声ファイルをファイル名とともに再生できるようにしてみました。 これで再生して音を聞きながら必要なファイル名を知ることができます。
;
; hsptvのSE素材を再生
;
;#include "hsp3dish.as"
;#include "hgimg4.as"
; ファイル一覧を取得
; HSPTVフォルダにあるWAVファイルの名前をすべて取得します。
mes "フォルダ:" + dir_tv
dirlist s, dir_tv + "*.wav", 3
numFList = stat
dim fnameList, 64, numFList
notesel s
repeat numFList
noteget b, cnt
fnameList(cnt) = b
loop
; サウンドを登録
; 見つかったWAVファイルすべてに対して、再生ボタンを作ります。
dim objid, numFList
dim idSE, numFList
px = 10
py = 30
repeat numFList
; 再生ボタン
pos px, py
button gosub "PLAY", *l_play
objid(cnt) = stat
pos px + 70, py
mes fnameList(cnt)
py += 30
if py > ginfo_winy - 40 {
px+= 200
py = 30
}
; 音声登録
fnameSE = dir_tv + fnameList(cnt)
idSE(cnt) = cnt
mmload fnameSE, idSE(cnt)
loop
redraw 1
stop
; 再生ボタン
; どのボタンが押されたかを判定して、再生する音を選択しています。
*l_play
idBtn = stat ; 押されたボタンのオブジェクトID
;mmstop -1
repeat numFList
if objid(cnt) = idBtn {
mmplay idSE(cnt)
break
}
loop
return
MIDIもあるのでこれも同じようにしてみます。
;
; hsptvのMIDI素材を再生
;
;#include "hgimg4.as"
; ファイル一覧を取得
mes "フォルダ:" + dir_tv
dirlist s, dir_tv + "*.mid", 3
numFList = stat
dim fnameList, 64, numFList
notesel s
repeat numFList
noteget b, cnt
fnameList(cnt) = b
loop
; サウンドを登録
dim objid, numFList
dim idMB, numFList
px = 10
py = 30
repeat numFList
; 再生ボタン
pos px, py
button gosub "PLAY", *l_play
objid(cnt) = stat
pos px + 70, py
mes fnameList(cnt)
py += 30
if py > ginfo_winy - 40 {
px+= 200
py = 30
}
; 音声登録
fnameMIDI = dir_tv + fnameList(cnt)
idMB(cnt) = cnt
mmload fnameMIDI, idMB(cnt)
;mmvol idMB(cnt), -1000
loop
redraw 1
stop
; 再生ボタン
*l_play
idBtn = stat
;mmstop
repeat numFList
if objid(cnt) = idBtn {
mmplay idMB(cnt)
break
}
loop
return
MIDIファイルもたくさんありますね。BGMはここから選んでもよさそうです。
音量設定
mm系とdmm系にはどちらにも音量(ボリューム)設定命令があります。 基本的には同じような機能なのですが、引数の数値に違いがあります。
mmvol | dmmvol | |
---|---|---|
音量(引数) | -1000~0 | -10000~0 |
音量(設定値) | -100.0~0 | -100.00~0 |
単位 | リニア | デシベル |
mmvol
はリニア値を指定します。
0で音量最大、-1000で無音です。使用する際は、次のように考えると理解しやすいと思います。
- 音量変更 0.0 %にするときは、 0を指定する。
- 音量変更 -50.0 %にするときは、 -500を指定する。(音量半分)
- 音量変更 -100.0 %にするときは、-1000を指定する。
dmmvol
はデシベル値を指定します。
0で音量最大、-10000で無音です。使用する際は、次のように考えると理解しやすいと思います。
- 音量変更 0.00 dBにするときは、 0を指定する。
- 音量変更 -6.00 dBにするときは、 -600を指定する。(音量半分)
- 音量変更 -100.00 dBにするときは、-1000を指定する。
実際に使う際はわかりにくいので、マニュアルにある通りにサンプルvolsamp.hsp内のvol2db
命令を使うと簡単です。
また、mmvol
は注意点があります。
- hsp3dish.as、hgimg4.asのいずれかを
include
しないと使えません。 - MIDIファイルは音量調整できません。
BGMの音量調整をしたい場合は、MIDIを避ける必要があり注意が必要ですね。
音を重ねる
前述のサンプルで音声をいくつも再生していて気がついたと思うのですが、音が一つずつしか再生されません。 前の音を再生中に次の音を再生しようとすると、前の音が停止してしまいます。特に同じ音は必ず同時再生できません。
dmm系の場合は、複数の音を重ねて再生することができます。
実はmm系も hsp3dish.as、hgimg4.asのいずれかをinclude
すれば、複数の音を重ねて再生することができるようになります。
また、include
することで再生までにかかる時間も少し短くなるようです。
しかしどちらも同じ音は重複再生することはできません。 同じ音を複数再生したい場合は、同じ音のファイルを複数回読み込んで運用する方法を使います。 複数回読み込めば、同じ音でも別のIDなので重複再生することができます。
多重再生
違う音は重ねて再生できますが、同じ音を重ねて再生することはできません。 同じ音を複数回読み込んでしまえば回避できますが、管理がちょっと面倒です。
しかしゲームでの効果音は、同じ音を重ねて再生したい場面は必ずあります。 面倒でも必要になってくる処理です。 そういう時はモジュールにしておくと便利ですね。
#module
;-----------------------------------------------------------
; サウンドデータの複数読み込み
;
;[ Infomation ]
; p_fname : ファイル名
; p_sid : サウンドID初期値
; p_num : 登録個数
;
;[ comment ]
; "ファイル名"で指定されたファイルをサウンドデータとして登録します。
; p_sid~(p_sid + p_num - 1)の範囲でサウンドIDを登録します。
; mmload 命令と同じ動作内容です。
;
; mmMPlay命令を使って再生してください。
;
; リピート再生は行いません。
; 失敗すると stat に-1を返します。
; 成功すると、 (p_sid + p_num) を返します。
;
#deffunc mmMLoad str p_fname, int p_sid, int p_num
; 引数チェック
if p_fname = "" : return 1
if p_sid <0 : return 1
if p_num <= 0 : return 1
; 読み込み
repeat p_num
mmload p_fname, p_sid + cnt
loop
return (p_sid + p_num)
;-----------------------------------------------------------
; サウンドデータの複数再生
;
;[ Infomation ]
; p_sid : サウンドID初期値
; p_num : 登録個数
;
;[ comment ]
; p_sidで指定した複数のサウンドIDを再生します。
; 同じサウンドを止めずに多重再生することができます。
; p_num で指定した登録個数まで多重再生できます。
; 再生数が p_num 個を超えた場合は、一番古いサウンドが停止されて新たに再生されます。
;
; 必ず mmMLoad 命令で読み込んだサウンドIDを使用してください。
; mmplay 命令と同じ動作内容です。
;
; 失敗すると stat に1を返します。成功時は0を返します。
;
#deffunc mmMPlay int p_sid, int p_num
; 引数チェック
if p_sid <0 : return 1
if p_num <= 0 : return 1
; 再生していないサウンドIDを探して再生
f = 0
repeat p_num
id = p_sid + cnt
mmstat s, id, 16
if s = 0 {
mmplay id
f = 1
break
}
loop
; すべて再生中だった場合
; 再生時間が一番経過しているサウンドIDを使用して再生します。
; 使用されたサウンドIDは再生が中断されて最初から再生されます。
if f = 0 {
pmax = 0.0
idold = p_sid
repeat p_num
id = p_sid + cnt
mmstat p, id, $100
if p > pmax {
pmax = p
idold = id
}
loop
mmplay idold
}
return 0
;-----------------------------------------------------------
; 複数のサウンドデータの音量設定
;
;[ Infomation ]
; p_sid : サウンドID初期値
; p_num : 登録個数
; p_vol : 音量(-10000~0)
;
;[ comment ]
; p_sidで指定した複数のサウンドIDの音量(ボリューム)を設定します。
; 必ず mmMLoad 命令で読み込んだサウンドIDを使用してください。
; mmvol 命令と同じ動作内容です。
;
; 失敗すると stat に1を返します。
;
#deffunc mmMVol int p_sid, int p_num, int p_vol
; 引数チェック
if p_sid <0 : return 1
if p_num <= 0 : return 1
vol = limit( p_vol, -10000, 0 )
repeat p_num
mmvol p_sid + cnt, vol
loop
return 0
#global
;=================================================
; ボタンを押すと音声が再生されます。
; 連打しても音が重なってい再生されます。
#include "hgimg4.as"
; ファイル一覧を取得
mes "フォルダ:" + dir_tv
fname = dir_tv + "se_bom.wav"
fname2 = dir_tv + "se_block2.wav"
; 音声登録
numSE = 10 ; 重複再生できる音の数
numSE2 = 10
idSE = 0 : mmMLoad fname , idSE , numSE
idSE2 = stat : mmMLoad fname2, idSE2, numSE2
; 音量調整
mmMVol idSE , numSE, -500
mmMVol idSE2, numSE2, -500
button gosub "se_bom", *l_play1
button gosub "se_block2", *l_play2
redraw 1
stop
*l_play1
mmMPlay idSE , numSE
return
*l_play2
mmMPlay idSE2, numSE2
return
ボタンを連打しても、再生が止まらずにちゃんと音が重なって再生出来ています。 「se_block2」が特にわかりやすくて、最後のチャリチャリという音までちゃんと聞こえています。
まとめ
HSP3で音声再生を行う場合は、 hgimg4ならmm系命令、 hgimg3ならdmm系またはmm系命令のどちらかを使うことになります。 ただしOGGを使うならdmm系です。
プラグイン、ファイル形式、重複再生、ボリューム調整、特に凝ったことをしないのであれば、このあたりに注意しておけば良さそうです。