HSP | waveファイルの再生を地道な方法でやってみる

HSP | waveファイルの再生を地道な方法でやってみる

HSPの標準命令のmmplayやmciだとWAVEファイルの同時再生ってできないんですよね…。
そのせいで、STG造ろうとしても、BGMは流れていても、いくつかの効果音出したらそれのどれか一つしか流れないということになります…。
なので、複数の出せるモジュール作ろうじゃないかということで作り始めました。(しかし、前回のMIDI解析の件みたいに、途中であきらめるかもしれません…。そうなったらごめんなさい…。)

// 準備
#include "winmm.as"
#define CALLBACK_FUNCTION 0x30000
#define CALLBACK_NULL 0
#define CALLBACK_WINDOW 0x10000
#define WHDR_BEGINLOOP 4
#define WHDR_ENDLOOP 8

// 読み込み
filename="aiueo.wav" // WAVEファイルのあるパス指定
exist filename
wavedatasize=strsize
if wavedatasize=-1 : end
sdim data,wavedatasize
bload filename,data

// ヘッダー解析
sdim PCMWAVEFORMAT,16
sdim wavedata
chunk=""
chunk_length=0
chunk_type=""
index=0
repeat
lpoke chunk,0,lpeek(data,index)
switch chunk
case "RIFF"
index+4
;chunk_length=lpeek(data,index) ; 本当はこのサイズだけ解析、とするべきだが、どうせ最後までRIFFのデータなんだからいいんじゃね?的なノリ
index+4
lpoke chunk_type,0,lpeek(data,index)
index+4
repeat
lpoke chunk,0,lpeek(data,index)
switch chunk
case "LIST"
index+4
chunk_length=lpeek(data,index)
index+4
;lpoke chunk_type,0,lpeek(data,index)
index+4
;LISTチャンクのデータ抜き出し
index+chunk_length
swbreak
case "fmt "
index+4
chunk_length=lpeek(data,index)
index+4
memexpand PCMWAVEFORMAT,chunk_length
memcpy PCMWAVEFORMAT,data,chunk_length,0,index
index+chunk_length
swbreak
case "data"
index+4
chunk_length=lpeek(data,index)
index+4
memexpand wavedata,chunk_length
memcpy wavedata,data,chunk_length,0,index
index+chunk_length
swbreak
swend
if index>wavedatasize-8 : break
loop
swbreak
swend
if index>wavedatasize-8 : break
loop

// 再生には必要ないが、PCMWAVEFORMAT構造体解析
wpoke formatType,0,wpeek(PCMWAVEFORMAT,0)
wpoke channels,0,wpeek(PCMWAVEFORMAT,2)
lpoke samplingRate,0,lpeek(PCMWAVEFORMAT,4)
lpoke meanDataTransferRate,0,lpeek(PCMWAVEFORMAT,8)
wpoke blocAlign,0,wpeek(PCMWAVEFORMAT,12)
wpoke bit,0,wpeek(PCMWAVEFORMAT,14)

// blocAlign=channels*1(2) // 16bitなら2、8bitなら1
// meanDataTransferRate=samplingRate*blocAlign

// 変数
sdim WAVEFORMATEX,18
memcpy WAVEFORMATEX,PCMWAVEFORMAT,16,0,0
;wpoke WAVEFORMATEX,0,formatType
;wpoke WAVEFORMATEX,2,channels
;lpoke WAVEFORMATEX,4,samplingRate
;lpoke WAVEFORMATEX,8,samplingRate*2
;wpoke WAVEFORMATEX,12,blocAlign
;wpoke WAVEFORMATEX,14,bit

sdim WAVEHDR,32
lpoke WAVEHDR,0,varptr(wavedata)
lpoke WAVEHDR,4,wavedatasize
lpoke WAVEHDR,16,WHDR_BEGINLOOP | WHDR_ENDLOOP
lpoke WAVEHDR,20,1

sdim MMTIME,16
lpoke MMTIME,0,1

dim phwo,1024

// メイン
waveOutOpen varptr(phwo),-1,varptr(WAVEFORMATEX),0,0,CALLBACK_NULL
waveOutPrepareHeader phwo(0),varptr(WAVEHDR),32
waveOutWrite phwo(0),varptr(WAVEHDR),32
*lp
redraw 0
waveOutGetPosition phwo(0),varptr(MMTIME),16
color 255,255,255 : boxf
color
pos 0,0 : mes ""+(lpeek(MMTIME,4)/meanDataTransferRate)+"."+((lpeek(MMTIME,4)\meanDataTransferRate)*1000/meanDataTransferRate)+"秒"
redraw
await 50
goto *lp
*exit
waveOutReset phwo(0)
waveOutUnprepareHeader phwo(0),varptr(WAVEHDR),32
waveOutClose phwo(0)
end

ところどころ命令とかがあるのにコメントアウトしてあるところは、実行してもいいけど役に立っていない部分です。このソースを別な目的で使うなら必要になるかもしれません。
別な目的で使いたいとかいう人は、コメントアウトしてあるところはずしたり処理を日本語で書いてる部分を書き換えたりして使ってください。

phwoだけだったら普通に配列にして、代入させる (?) 時には4バイトずれたところに書き込みさせる、とすればいいですが、WAVEFORMATEXやWAVEHDRは一工夫しないと…。

最終的にはこれをモジュール化して、HSPでいうmmloadごとに違うデバイスになるようにしたいです。でも、ここまでくればもうすぐ完成すると思います。(たぶん)
DirectSoundとかいうのを使えば同時再生できるそうですが…。Direct~使うんだったら描画とかもDirect~に任せたほうが速いけど、いまさら造りかけのSTG造り変えるのめんどいし…。
音声再生だけのためにDLL付けるのも…ちょっと…。自分のモジュールだったら外部DLLしか使ってないし…。
音声再生だけできればいいので、自分で頑張って作ってみます。
↓あなたのクリックでこれが完成するまでの時間が短くなります。


「HSP | waveファイルの再生を地道な方法でやってみる」への3件のフィードバック

  1. ケルパニさん、こんばんは
    なんだか分からない文字の羅列
    凄すぎます…
    理解不能で涙
    だけどリスペクトのナイス押しちゃっていいですか?

  2. > †Chacottさん
    ありがとうございます!! 大歓迎です!! (^^
    本当は一般向きの記事も書きたいんですけど、今ちょっと訳あって更新できないんです (><
    ごめんなさい!!

  3. ありがとうございます!
    では今後はすべて
    「なんだか凄いからリスペクトのNICE!」
    押しに来ますねヾ(。◕‿◕。)

コメントは受け付けていません。