|
 |
|
2025/8/29(Fri) 17:44:50|NO.103884
こんにちわ。
XAudio2でwavを再生するモジュールを作ってみました。
mmplayなどに比べ「DLL不要、多重再生、途中ループ、音量、パン、ピッチ、フィルター」が魅力かと思います。
Win10以降で動くと思います。("XAudio2_9.dll"標準で搭載されている環境)
なるべくシンプルにしたので、ちょっと無駄があるかもしれませんが、
もっとこうする方が良い、これは良くないなどご意見頂けると嬉しいです。
改変、組み込みもご自由にどうぞ。
※wavの途中ループはWavosaurなどのsmplチャンクを編集できるツールで保存。
;===============================================================================
; 簡易XAudioモジュール v1.0 author: usagi file: ezXAudio.hsp
;===============================================================================
#ifndef __EZXAUDIO__
#define global __EZXAUDIO__
#module "ezXAudio"
; DLL
#uselib "msvcrt.dll"
#cfunc malloc "malloc" int
#func free "free" int
#uselib "kernel32.dll"
#func VirtualProtect "VirtualProtect" var,int,int,var
#uselib "XAudio2_9.dll"
#func XAudio2Create "XAudio2Create" var,int,int
; COM
#define IID_IXAudio2 "{2B02E3CF-2E0B-4ec3-BE45-1B2A3FE7210D}"
#usecom IXAudio2 IID_IXAudio2
#comfunc CreateSourceVoice 5 var,var,int,float,int,int,int
#comfunc CreateSubmixVoice 6 var,int,int,int,int,int,int
#comfunc CreateMasteringVoice 7 var,int,int,int,int,int,int
#comfunc StartEngine 8
#comfunc StopEngine 9
; Dummy Function
#uselib ""
#cfunc float "" float
#func __GetVoiceDetails "" int, var
#func __SetFilterParameters "" int, var, int
#func __SetVolume "" int, float, int
#func __SetOutputMatrix "" int,int,int,int,var,int
#func __DestroyVoice "" int
#func __Start "" int, int, int
#func __Stop "" int, int, int
#func __SubmitSourceBuffer "" int, int, int
#func __FlushSourceBuffers "" int
#func __ExitLoop "" int, int
#func __GetState "" int, var, int
#func __SetFrequencyRatio "" int, float, int
; Overwrite Function
#deffunc local overwriteFunction int _libptr, int _pp, int _index
dupptr p, _pp, 4 : dupptr pfuncs, p, (_index+1)*4 : dupptr _sdat, _libptr, 28 : _sdat.6 = pfuncs._index : return
#define ctype def(%1,%2,%3=_p) overwriteFunction libptr(%2),%3,%1:%2 %3
; ------------------
#deffunc local _GetVoiceDetails int _p, var _details
def( 0, __GetVoiceDetails), _details : return stat
#deffunc local _SetFilterParameters int _p, var _filterParams
def( 8, __SetFilterParameters ), _filterParams, 0 : return stat
#deffunc local _SetVolume int _p, double _vol
def(12, __SetVolume), _vol,0 : return stat
#deffunc local _SetOutputMatrix int _p, int _srcCh, int _dstCh, var _lvMtx
def(16, __SetOutputMatrix), 0,_srcCh,_dstCh,_lvMtx,0 : return stat
#deffunc local _DestroyVoice int _p
def(18, __DestroyVoice) : return stat
#deffunc local _Start int _p
def(19, __Start), 0, 0 : return stat
#deffunc local _Stop int _p
def(20, __Stop), 0, 0 : return stat
#deffunc local _SubmitSourceBuffer int _p, int _pBuffer
def(21, __SubmitSourceBuffer), _pBuffer, 0 : return stat
#deffunc local _FlushSourceBuffers int _p
def(22, __FlushSourceBuffers) : return stat
#deffunc local _ExitLoop int _p
def(24, __ExitLoop), 0 : return stat
#deffunc local _GetState int _p, var _state
def(25, __GetState), _state, 0 : return stat
#deffunc local _SetFrequencyRatio int _p, double _ratio
def(26, __SetFrequencyRatio), _ratio, 0 : return stat
; ------------------
#deffunc local machinecode int _p, array _code
VirtualProtect _code, varsize(_code),$40, _ : dupptr _sdat, _p, 28 : _sdat.6 = varptr(_code) : return
#defcfunc local getInputChannels int _p
res = 0,0,0,0 : _GetVoiceDetails _p, res : return res.2
#defcfunc local getInputSampleRate int _p
res = 0,0,0,0 : _GetVoiceDetails _p, res : return res.3
#defcfunc local getStateBuffersQueued int _p
res = 0,0,0,0 : _GetState _p, res : return res.1
#defcfunc local getStateSamplesPlayed int _p
res = 0,0,0,0 : _GetState _p, res : d = 0.0 : lpoke d,0,res.2 : lpoke d,4,res.3 : return double(strf("%I64u",d))
#defcfunc local checkID var _data, str _identifier, int _offset
mref identifier, 65 : identifier = " " : lpoke identifier, 0, lpeek(_data, _offset) : return identifier == _identifier
#defcfunc local dupChunkData var _dup, var _data, int _offset
size = lpeek(_data, _offset + 4) : dupptr _dup, varptr(data) + offset + 8, size : return offset + 8 + size
; Once
#deffunc local call_once
__float = $0424448b, $c3909090 : machinecode libptr(float), __float ; mov 0x4(%esp),%eax ; ret
xaInit 1024, 2, 0, 0
return
;===============================================================================
; コマンド
;===============================================================================
; 初期化
;-----------------------------
#deffunc xaInit int _max, double _freqRatio, int _channels, int _sampleRate
if m_pXAudio != 0 { xaDeinit }
; Reset
m_voiceMax = _max
m_freqRatio = limitf(_freqRatio, 1.0/1024.0, 1024.0)
dim m_pSourceVoice, m_voiceMax
dim m_pAudioData, m_voiceMax
dim m_pAudioDataSize, m_voiceMax
dim m_loopBegin, m_voiceMax
dim m_loopLength, m_voiceMax
dim m_loopCount, m_voiceMax
; XAudio2 Start
XAudio2Create m_pXAudio, 0, 1
newcom m_XAudio, IID_IXAudio2, -1, m_pXAudio
if stat != 0 : return -1
CreateMasteringVoice m_XAudio, m_pMasteringVoice, _channels, _sampleRate, 0, 0,0,0
if stat != 0 : return -1
return 0
; 読み込み
;-----------------------------
#deffunc xaLoad str _file, int _id, int _count, int _flags
flags = 0
if _flags & 1 : flags |= 0x0002 ; *XAUDIO2_VOICE_NOPITCH
if _flags & 2 : flags |= 0x0008 ; *XAUDIO2_VOICE_USEFILTER
if _id >= m_voiceMax : return -1
xaDel _id
xaLoop _id, 0, 0, _count
exist _file : sdim data, strsize : bload _file, data
if (checkID(data,"RIFF", 0) && checkID(data,"WAVE", 8)) = 0 : return -1
offset = 12
repeat -1
if offset >= varsize(data) : break
if checkID(data,"fmt ", offset) {
offset = dupChunkData(fmtChunk, data, offset)
continue
}
if checkID(data,"data", offset) {
offset = dupChunkData(dataChunk, data, offset)
continue
}
if checkID(data,"smpl", offset) {
offset = dupChunkData(smplChunk, data, offset)
m_loopBegin._id = smplChunk.11
m_loopLength._id = smplChunk.12 - smplChunk.11
continue
}
offset = dupChunkData(_, data, offset)
loop
m_pAudioDataSize._id = varsize(dataChunk)
m_pAudioData._id = malloc(m_pAudioDataSize._id)
dupptr audioData, m_pAudioData._id, m_pAudioDataSize._id
memcpy audioData, dataChunk, m_pAudioDataSize._id
CreateSourceVoice m_XAudio, m_pSourceVoice._id, fmtChunk, flags, m_freqRatio,0,0,0
if stat != 0 : return -1
xaPan _id, 0
return 0
; 削除
;-----------------------------
#deffunc xaDel int _id
if m_pAudioData._id != 0 {
free m_pAudioData._id
m_pAudioDataSize._id = 0
m_pAudioData._id = 0
}
if m_pSourceVoice._id != 0 {
_DestroyVoice m_pSourceVoice._id
m_pSourceVoice._id = 0
}
return
#deffunc xaDelAll
repeat m_voiceMax : xaDel cnt : loop
return
; 再生
;-----------------------------
#deffunc xaPlay int _id, int _mode
xaStop _id
if m_pAudioDataSize._id == 0 : return
xaudio2_buffer.0 = 0x40, m_pAudioDataSize._id, m_pAudioData._id, 0, 0
xaudio2_buffer.5 = m_loopBegin._id, m_loopLength._id, m_loopCount._id, 0
_SubmitSourceBuffer m_pSourceVoice._id, varptr(xaudio2_buffer)
_Start m_pSourceVoice._id
return stat
; 停止
;-----------------------------
#deffunc xaStop int _id
if m_pSourceVoice._id == 0 : return
_Stop m_pSourceVoice._id : _FlushSourceBuffers m_pSourceVoice._id
return stat
#deffunc xaStopAll
repeat m_voiceMax : xaStop cnt : loop
return
; ポーズ
;-----------------------------
#deffunc xaPause int _id
if m_pSourceVoice._id == 0 : return
_Stop m_pSourceVoice._id
return stat
; リジューム
;-----------------------------
#deffunc xaResume int _id
if m_pSourceVoice._id == 0 : return
_Start m_pSourceVoice._id
return stat
; ループ
;-----------------------------
#deffunc xaLoop int _id, int _st, int _ed, int _count
m_loopBegin._id = _st : m_loopLength._id = _ed - _st
if _count < 0 { m_loopCount._id = 255 } else { m_loopCount._id = limit(_count, 0, 255) }
return stat
#deffunc xaExitLoop int _id
if m_pSourceVoice._id == 0 : return
_ExitLoop m_pSourceVoice._id
return stat
; 音量
;-----------------------------
#deffunc xaVol int _id, double _vol
if m_pSourceVoice._id == 0 : return
_SetVolume m_pSourceVoice._id, _vol
return stat
; 周波数
;-----------------------------
#deffunc xaFreq int _id, double _ratio
if m_pSourceVoice._id == 0 : return
_SetFrequencyRatio m_pSourceVoice._id, _ratio
return stat
; 定位
;-----------------------------
#deffunc xaPan int _id, double _pan
if m_pSourceVoice._id == 0 : return
srcCh = getInputChannels(m_pSourceVoice._id)
dstCh = getInputChannels(m_pMasteringVoice)
; TODO: 現状ステレオのリニアパンニングにだけ対応
if dstCh = 2 {
l = limitf(0.5 - _pan * 0.5, 0, 1)
r = 1.0 - l
if srcCh = 1 {
; L_IN
;-------------------
lvMtx.0 = float(l) ; L_OUT
lvMtx.1 = float(r) ; R_OUT
_SetOutputMatrix m_pSourceVoice._id, srcCh, dstCh, lvMtx
}
if srcCh = 2 {
; L_IN : R_IN
;-----------------------------
lvMtx.0 = float(l), float(0) ; L_OUT
lvMtx.2 = float(0), float(r) ; R_OUT
_SetOutputMatrix m_pSourceVoice._id, srcCh, dstCh, lvMtx
}
}
return
; フィルター tyep: enum { LowPass, BandPass, HighPass, Notch }
;-----------------------------
#deffunc xaFilter int _id, int _type, double _freq, double _oneOverQ
if m_pSourceVoice._id == 0 : return
filterParams = _type, float(_freq), float(limitf(_oneOverQ, 0, 1.5))
_SetFilterParameters m_pSourceVoice._id, filterParams
return
; 情報
;-----------------------------
#defcfunc xaStat int _id, int _mode
if m_pSourceVoice._id == 0 : return
; TODO: 種類を増やす、番号整理(もしくは小分けにする)
if _mode = 4 : return getInputChannels(m_pSourceVoice._id)
if _mode = 5 : return getInputSampleRate(m_pSourceVoice._id)
if _mode = 16 : return getStateBuffersQueued(m_pSourceVoice._id)
if _mode = 17 : return getStateSamplesPlayed(m_pSourceVoice._id)
return
; 破棄
;-----------------------------
#deffunc xaDeinit onexit
if m_pXAudio = 0 : return
StopEngine m_XAudio
repeat m_voiceMax : xaDel cnt : loop
_DestroyVoice m_pMasteringVoice : m_pMasteringVoice = 0
delcom m_XAudio : m_pXAudio = 0
return
#global
call_once@ezXAudio
#endif
;===============================================================================
; テスト
xaLoad dir_tv+"se_block2.wav", 0, -1, 2 : xaPlay 0
xaLoad dir_tv+"se_shot.wav" , 1
xaLoad dir_tv+"se_bom.wav" , 2
*MAIN
vol = 1.0 - (double(mousey)/ginfo_sy)
freq= vol
pan = (double(mousex)/ginfo_sx)*2.0 - 1.0
title strf("pan=%f, freq=%f, stat=%f", pan, freq, xaStat(0, 16))
xaFilter 0, 0, freq, 1
xaPan 0, pan
getkey key, 51 : if key { xaVol 0, freq }
getkey key, 52 : if key { xaFreq 0, freq }
stick pad
if pad & 256 : xaPlay 0
if pad & 512 : xaStop 0
getkey key, 49 : if key { xaPlay 1 }
getkey key, 50 : if key { xaPlay 2 }
cmp = ginfo_wx1<ginfo_mx & ginfo_mx<ginfo_wx2 & ginfo_wy1<ginfo_my & ginfo_my<ginfo_wy2
if cmp : xaResume 0 : else :xaPause
await 16
goto *MAIN

| |
|
2025/8/29(Fri) 19:31:24|NO.103885
HSPしか分からない自分にはXAudio2とか理解できないので扱えちゃうのが凄いです。
usagiさんの技術力とフリーで公開しちゃう心の広さに脱帽です。
|
|
2025/8/31(Sun) 23:47:53|NO.103901
すごいのだ!! 研究素材として使用させて頂きます。
この手あまり反応ない気がしますが、HSPはこの部分(サウンド周り)あまり強くないんで
もう少し拡充してほしいと思ってたりします。
そう思ってうちも独自開発して追加しようと思ってるんですが、なかなかリリースできないのだ。
HSPOGGの周波数変更については要望だしてありますが、これが追加されるだけで
できることがかなり広がると思われます。
|
|
2025/9/3(Wed) 16:25:07|NO.103927
DLL不要で、途中のループ再生や音量、パンなどを扱えるのは大きな利点です。通常、こういった機能は実装が最も難しい部分ですからね。シンプルさを保つという設計思想も素晴らしいですし、他の人も採用して発展させやすいでしょう。素晴らしい仕事です!
https://ragdollhitstickman.io
|
|
2025/9/5(Fri) 11:55:25|NO.103939
みなさんコメントありがとうございます。
>名無しさん
とんでもないです。私も研究目的なので至らない所があり、指摘いただけると嬉しいです。
>窓月ららさん
OGGのデコードも面白そうですね。自作音源開発されてましたね楽しみです。
>Nick Bender
難しい処理は全部XAudioがしてくれるので楽でしたが、インターフェースから関数引っ張ってくるのが厄介でした。。。
|
|
2025/9/5(Fri) 12:09:29|NO.103940
折角なので、仕様を少しかえエフェクトとサブミックスも試してみました。
ゲーム的な使用に耐えられるかテストしてみたのですが、wav参照の複製かフォーマット固定してボイスプールする仕組みにした方が良かったかもです。
※それを掲示板に書くにはスペースが足りない。。。長くてすみません。
XAudioのラッパーだけ分けて、それを使うモジュールを用意する方が正解だったかもですね(でも複雑かなぁ)
良いアイデアいただけると嬉しいです。
#ifndef __EZXAUDIO__
#define global __EZXAUDIO__
#module "ezXAudio"
; DLL
#uselib "msvcrt.dll"
#cfunc malloc "malloc" int
#func free "free" int
#uselib "kernel32.dll"
#func VirtualProtect "VirtualProtect" var,int,int,var
#uselib "XAudio2_9.dll"
#func XAudio2Create "XAudio2Create" var,int,int
#func XAudio2CreateReverb "CreateAudioReverb" var,int
#func XAudio2CreateVolumeMeter "CreateAudioVolumeMeter" var,int
#func XAudio2CreateFX "CreateFX" var,var,nullptr,nullptr
; COM
#define IID_IUnknown "{00000000-0000-0000-C000-000000000046}"
#define IID_IXAudio2 "{2B02E3CF-2E0B-4ec3-BE45-1B2A3FE7210D}"
#usecom IXAudio2 IID_IXAudio2
#comfunc CreateSourceVoice 5 var,var,int,float,int,int,int
#comfunc CreateSubmixVoice 6 var,int,int,int,int,int,int
#comfunc CreateMasteringVoice 7 var,int,int,int,int,int,int
#comfunc StartEngine 8
#comfunc StopEngine 9
; Dummy Function
#uselib ""
#cfunc float "" float
#func f2ds "" var,var,int; float[],double[],int
#func __GetVoiceDetails "" int,var
#func __SetOutputVoices "" int,var
#func __SetEffectChain "" int,var
#func __EnableEffect "" int,int,int
#func __DisableEffect "" int,int,int
#func __SetEffectParameters "" int,int,var,int,int
#func __GetEffectParameters "" int,int,var,var
#func __SetFilterParameters "" int,var,int
#func __SetVolume "" int,float,int
#func __SetOutputMatrix "" int,int,int,int,var,int
#func __DestroyVoice "" int
#func __Start "" int,int,int
#func __Stop "" int,int,int
#func __SubmitSourceBuffer "" int,int,int
#func __FlushSourceBuffers "" int
#func __ExitLoop "" int,int
#func __GetState "" int,var,int
#func __SetFrequencyRatio "" int,float,int
#func __GetChannelMask "" int,var
; Overwrite Function
#deffunc local overwriteFunction int _libptr, int _pp, int _index
dupptr p, _pp, 4 : dupptr pfuncs, p, (_index+1)*4 : dupptr _sdat, _libptr, 28 : _sdat.6 = pfuncs._index : return
#define ctype def(%1,%2,%3=_p) overwriteFunction libptr(%2),%3,%1:%2 %3
; IXAudio2Voice
#deffunc local _GetVoiceDetails int _p, var _details
def( 0, __GetVoiceDetails), _details : return stat
#deffunc local _SetOutputVoices int _p, var _sendList
def( 1, __SetOutputVoices), _sendList : return stat
#deffunc local _SetEffectChain int _p, var _effectChain
def( 2, __SetEffectChain), _effectChain : return stat
#deffunc local _EnableEffect int _p, int _index
def( 3, __EnableEffect), _index, 0 : return stat
#deffunc local _DisableEffect int _p, int _index
def( 4, __DisableEffect), _index, 0 : return stat
#deffunc local _SetEffectParameters int _p, int _index, var _param, int _size
def( 6, __SetEffectParameters), _index, _param, _size, 0 : return stat
#deffunc local _GetEffectParameters int _p, int _index, var _param, var _size
def( 7, __GetEffectParameters), _index, _param, _size : return stat
#deffunc local _SetFilterParameters int _p, var _filterParams
def( 8, __SetFilterParameters ), _filterParams, 0 : return stat
#deffunc local _SetVolume int _p, double _vol
def(12, __SetVolume), _vol,0 : return stat
#deffunc local _SetOutputMatrix int _p, int _srcCh, int _dstCh, var _lvMtx
def(16, __SetOutputMatrix), 0,_srcCh,_dstCh,_lvMtx,0 : return stat
#deffunc local _DestroyVoice int _p
def(18, __DestroyVoice) : return stat
; IXAudio2SourceVoice
#deffunc local _Start int _p
def(19, __Start), 0, 0 : return stat
#deffunc local _Stop int _p
def(20, __Stop), 0, 0 : return stat
#deffunc local _SubmitSourceBuffer int _p, int _pBuffer
def(21, __SubmitSourceBuffer), _pBuffer, 0 : return stat
#deffunc local _FlushSourceBuffers int _p
def(22, __FlushSourceBuffers) : return stat
#deffunc local _ExitLoop int _p
def(24, __ExitLoop), 0 : return stat
#deffunc local _GetState int _p, var _state, var _flags
def(25, __GetState), _state, _flags : return stat
#deffunc local _SetFrequencyRatio int _p, double _ratio
def(26, __SetFrequencyRatio), _ratio, 0 : return stat
; IXAudio2MasteringVoice
#deffunc local _GetChannelMask int _p, var _channelmask
def(19, __GetChannelMask), _channelmask : return stat
; ------------------
#deffunc local machinecode int _p, array _code
VirtualProtect _code, varsize(_code),$40, _ : dupptr _sdat, _p, 28 : _sdat.6 = varptr(_code) : return
#defcfunc local getInputChannels int _p
res = 0,0,0,0 : _GetVoiceDetails _p, res : return res.2
#defcfunc local getInputSampleRate int _p
res = 0,0,0,0 : _GetVoiceDetails _p, res : return res.3
#defcfunc local getStateBuffersQueued int _p
res = 0,0,0,0 : _GetState _p, res, $100 : return res.1
#defcfunc local getStateSamplesPlayed int _p
res = 0,0,0,0 : _GetState _p, res, 0 : d = 0.0 : lpoke d,0,res.2 : lpoke d,4,res.3 : return double(strf("%I64u",d))
#defcfunc local checkID var _data, str _identifier, int _offset
mref identifier, 65 : identifier = " " : lpoke identifier, 0, lpeek(_data, _offset) : return identifier == _identifier
#defcfunc local dupChunkData var _dup, var _data, int _offset
size = lpeek(_data, _offset + 4) : dupptr _dup, varptr(data) + offset + 8, size : return offset + 8 + size+(size\2);BUGFIX:奇数バイト対策
; Once
#deffunc local call_once
__float = $0424448b,$c3909090 : machinecode libptr(float), __float
__f2ds = $0c244c8b,$1f7ec985,$0424448b,$0824548b,$8d880c8d,$90002674,$c08300d9,$08c28304,$39f85add,$31f175c8,$9090c3c0 : machinecode libptr(f2ds), __f2ds
_CLSID_FXMASTERINGLIMITER = $c4137916,$46fd2be1,$15449985,$5698f436; "{C4137916-2BE1-46FD-8599-441536F49856}"
_CLSID_FXEQ = $f5e01117,$485ad6c4,$5169f5a3,$fadbf396; "{F5E01117-D6C4-485A-A3F5-695196F3DBFA}"
_CLSID_FXECHO = $5039d740,$449af736,$62a5d384,$877b5502; "{5039D740-F736-449A-84D3-A56202557B87}"
_CLSID_FXREVERB = $7d9aca56,$4807cb68,$37b132b6,$96852e35; "{7D9ACA56-CB68-4807-B632-B137352E8596}"
;Name |WDM |Room |RoomHF |* |DecayT |DecayHFR|Reflect |ReflectD|Reverb |ReverbD |Diffus |Density |HFRef |
;------------------------------------------------------------------------------------------------------------------------------
_REVERB_PRESETS = {"
DEFAULT , 100, -10000, 0, 0, 1.00, 0.50, -10000., 0.020, -10000, 0.040, 100, 100, 5000
GENERIC , 100, -1000, -100, 0, 1.49, 0.83, -2602., 0.007, 200, 0.011, 100, 100, 5000
PADDEDCELL , 100, -1000, -6000, 0, 0.17, 0.10, -1204., 0.001, 207, 0.002, 100, 100, 5000
ROOM , 100, -1000, -454, 0, 0.40, 0.83, -1646., 0.002, 53, 0.003, 100, 100, 5000
BATHROOM , 100, -1000, -1200, 0, 1.49, 0.54, -370., 0.007, 1030, 0.011, 100, 60, 5000
LIVINGROOM , 100, -1000, -6000, 0, 0.50, 0.10, -1376., 0.003, -1104, 0.004, 100, 100, 5000
STONEROOM , 100, -1000, -300, 0, 2.31, 0.64, -711., 0.012, 83, 0.017, 100, 100, 5000
AUDITORIUM , 100, -1000, -476, 0, 4.32, 0.59, -789., 0.020, -289, 0.030, 100, 100, 5000
CONCERTHALL , 100, -1000, -500, 0, 3.92, 0.70, -1230., 0.020, -2, 0.029, 100, 100, 5000
CAVE , 100, -1000, 0, 0, 2.91, 1.30, -602., 0.015, -302, 0.022, 100, 100, 5000
ARENA , 100, -1000, -698, 0, 7.24, 0.33, -1166., 0.020, 16, 0.030, 100, 100, 5000
HANGAR , 100, -1000, -1000, 0, 10.05, 0.23, -602., 0.020, 198, 0.030, 100, 100, 5000
CARPETEDHALLWAY, 100, -1000, -4000, 0, 0.30, 0.10, -1831., 0.002, -1630, 0.030, 100, 100, 5000
HALLWAY , 100, -1000, -300, 0, 1.49, 0.59, -1219., 0.007, 441, 0.011, 100, 100, 5000
STONECORRIDOR , 100, -1000, -237, 0, 2.70, 0.79, -1214., 0.013, 395, 0.020, 100, 100, 5000
ALLEY , 100, -1000, -270, 0, 1.49, 0.86, -1204., 0.007, -4, 0.011, 100, 100, 5000
FOREST , 100, -1000, -3300, 0, 1.49, 0.54, -2560., 0.162, -613, 0.088, 79, 100, 5000
CITY , 100, -1000, -800, 0, 1.49, 0.67, -2273., 0.007, -2217, 0.011, 50, 100, 5000
MOUNTAINS , 100, -1000, -2500, 0, 1.49, 0.21, -2780., 0.300, -2014, 0.100, 27, 100, 5000
QUARRY , 100, -1000, -1000, 0, 1.49, 0.83, -10000., 0.061, 500, 0.025, 100, 100, 5000
PLAIN , 100, -1000, -2000, 0, 1.49, 0.50, -2466., 0.179, -2514, 0.100, 21, 100, 5000
PARKINGLOT , 100, -1000, 0, 0, 1.65, 1.50, -1363., 0.008, -1153, 0.012, 100, 100, 5000
SEWERPIPE , 100, -1000, -1000, 0, 2.81, 0.14, 429., 0.014, 648, 0.021, 80, 60, 5000
UNDERWATER , 100, -1000, -4000, 0, 1.49, 0.10, -449., 0.007, 1700, 0.011, 100, 100, 5000
SMALLROOM , 100, -1000, -600, 0, 1.10, 0.83, -400., 0.005, 500, 0.010, 100, 100, 5000
MEDIUMROOM , 100, -1000, -600, 0, 1.30, 0.83, -1000., 0.010, -200, 0.020, 100, 100, 5000
LARGEROOM , 100, -1000, -600, 0, 1.50, 0.83, -1600., 0.020, -1000, 0.040, 100, 100, 5000
MEDIUMHALL , 100, -1000, -600, 0, 1.80, 0.70, -1300., 0.015, -800, 0.030, 100, 100, 5000
LARGEHALL , 100, -1000, -600, 0, 1.80, 0.70, -2000., 0.030, -1400, 0.060, 100, 100, 5000
PLATE , 100, -1000, -200, 0, 1.30, 0.90, 0., 0.002, 0, 0.010, 100, 75, 5000
"}
xaInit 1024, 2, 2, 48000
return
; 定数
#enum global XA_FXLIMITER = 0
#enum global XA_FXEQ
#enum global XA_FXECHO
#enum global XA_FXREVERB
;===============================================================================
; コマンド
;===============================================================================
; 初期化
;-----------------------------
#deffunc xaInit int _max, double _freqRatio, int _channels, int _sampleRate
if m_pXAudio != 0 { xaDeinit }
; Reset
m_sampleRate = _sampleRate : m_channels = _channels : m_channelMask = 3
m_deviceId = 0; TODO: 変更可能にする
; Audio
m_voiceMax = _max
m_freqRatio = limitf(_freqRatio, 1.0/1024.0, 1024.0)
dim m_pSourceVoice, m_voiceMax
dim m_pAudioData, m_voiceMax
dim m_pAudioDataSize, m_voiceMax
dim m_loopBegin, m_voiceMax
dim m_loopLength, m_voiceMax
dim m_loopCount, m_voiceMax
; Group
m_submixMax = 16
dim m_pSubmixVoice, m_submixMax; 0=MasteringVoice
dim m_pGroupFx, m_submixMax
dim m_pVolumeMeter, m_submixMax
dimtype m_groupFx,6, m_submixMax
dimtype m_volumeMeter,6, m_submixMax
dim m_groupFxType, m_submixMax
dim m_peakLevels, m_channels
dim m_rmsLevels, m_channels
m_volumeMeterLevels = varptr(m_peakLevels), varptr(m_rmsLevels), m_channels
; XAudio2 Start
XAudio2Create m_pXAudio, 0, 1 : newcom m_XAudio, IID_IXAudio2, -1, m_pXAudio
if stat != 0 : return -1
CreateMasteringVoice m_XAudio, m_pSubmixVoice.0, m_channels, m_sampleRate, 0, m_deviceId, 0, 0
if stat != 0 : return -2
_GetChannelMask m_pSubmixVoice.0, m_channelMask
; FX
CreateGroupFx 0, 0
if stat != 0 : return -3
return
; 破棄
;-----------------------------
#deffunc xaDeinit onexit
if m_pXAudio = 0 : return
StopEngine m_XAudio
xaDelAll
xaDelGroupAll
delcom m_XAudio : m_pXAudio = 0
return
; エフェクト作成
;-----------------------------
#deffunc local CreateGroupFx int _id, int _type
if m_pGroupFx._id != 0 {
_DisableEffect m_pSubmixVoice._id, 0
_DisableEffect m_pSubmixVoice._id, 1
delcom m_groupFx._id : m_pGroupFx._id = 0
delcom m_volumeMeter._id : m_pVolumeMeter._id = 0
}
m_groupFxType._id = _type
switch m_groupFxType._id
case XA_FXLIMITER : XAudio2CreateFX _CLSID_FXMASTERINGLIMITER, m_pGroupFx._id : swbreak
case XA_FXEQ : XAudio2CreateFX _CLSID_FXEQ, m_pGroupFx._id : swbreak
case XA_FXECHO : XAudio2CreateFX _CLSID_FXECHO, m_pGroupFx._id : swbreak
case XA_FXREVERB : XAudio2CreateReverb m_pGroupFx._id, 0 : swbreak
swend
newcom m_groupFx._id, IID_IUnknown, -1, m_pGroupFx._id
XAudio2CreateVolumeMeter m_pVolumeMeter._id, 0
newcom m_volumeMeter._id, IID_IUnknown, -1, m_pVolumeMeter._id
effects = /*0*/ m_pGroupFx._id, 0, m_channels, /*1*/ m_pVolumeMeter._id, 0, m_channels
effectChain = 2, varptr(effects)
_SetEffectChain m_pSubmixVoice._id, effectChain
return
; リミッター release(1-6-20), loudness(1-1000-18000)
;-----------------------------
#deffunc xaFxLimiter int _id, int _release, int _loudness
if m_groupFxType._id != XA_FXLIMITER : CreateGroupFx _id, XA_FXLIMITER
_EnableEffect m_pSubmixVoice._id, 0
prarams = limit(_release, 1, 20), limit(_loudness, 1, 1800)
_SetEffectParameters m_pSubmixVoice._id, 0, prarams, 8
return
; イコライザ― def f0:100, f1:800, f2:2000, f3:10000
;-----------------------------
#deffunc xaFxEq int _id, double _f0, double _g0, double _b0, double _f1, double _g1, double _b1, double _f2, double _g2, double _b2, double _f3, double _g3, double _b3
if m_groupFxType._id != XA_FXEQ : CreateGroupFx _id, XA_FXEQ
_EnableEffect m_pSubmixVoice._id, 0
prarams.0 = float(limitf(_f0, 20, 20000)), float(limitf(_g0, 0.126, 7.94)), float(limitf(_b0, 0.1, 2.0))
prarams.3 = float(limitf(_f1, 20, 20000)), float(limitf(_g1, 0.126, 7.94)), float(limitf(_b1, 0.1, 2.0))
prarams.6 = float(limitf(_f2, 20, 20000)), float(limitf(_g2, 0.126, 7.94)), float(limitf(_b2, 0.1, 2.0))
prarams.9 = float(limitf(_f3, 20, 20000)), float(limitf(_g3, 0.126, 7.94)), float(limitf(_b3, 0.1, 2.0))
_SetEffectParameters m_pSubmixVoice._id, 0, prarams, 48
return
; エコー mix(0-0.5-1) feedback(0-0.5-1) delay(1-500-2000)
;-----------------------------
#deffunc xaFxEcho int _id, double _mix, double _feedback, double _delay
if m_groupFxType._id != XA_FXECHO : CreateGroupFx _id, XA_FXECHO
_EnableEffect m_pSubmixVoice._id, 0
prarams = float(limitf(_mix, 0, 1)), float(limitf(_feedback, 0, 1)), float(limitf(_delay, 1, 2000))
_SetEffectParameters m_pSubmixVoice._id, 0, prarams, 12
return
; リバーブ name(DEFAULT)
;-----------------------------
#deffunc xaFxReverb int _id, str _name
notesel _REVERB_PRESETS
noteget noteline, limit(notefind(_name,1), 1)
split noteline, ",", sPreset
repeat 13 : paramI3DL2.cnt = double(sPreset(cnt+1)) : loop
noteunsel
ReverbConvertI3DL2ToNative paramI3DL2, paramNative
if m_groupFxType._id != XA_FXREVERB : CreateGroupFx _id, XA_FXREVERB
_EnableEffect m_pSubmixVoice._id, 0
_SetEffectParameters m_pSubmixVoice._id, 0, paramNative, 54
return
#deffunc local ReverbConvertI3DL2ToNative array _s, array _d
sdim _d, 54
if _s.5 >= 1.0 {
t = limit(-4.0 * (logf(_s.5)/logf(10)) + 8,0,12), 8, float(_s.4 * _s.5)
} else {
t = 8, limit(4.0 * (logf(_s.5)/logf(10)) + 8,0,8), float(_s.4)
}
lpoke _d, 0, float(_s.0) ;WetDryMix
lpoke _d, 4, limit(_s.7 * 1000.0,1,299) ;ReflectionsDelay
poke _d, 8, limit(_s.9 * 1000.0,0,84) ;ReverbDelay
poke _d, 9, 5 ;RearDelay
poke _d, 10, 5 ;SideDelay
poke _d, 11, 6 ;PositionLeft
poke _d, 12, 6 ;PositionRight
poke _d, 13, 27 ;PositionMatrixLeft
poke _d, 14, 27 ;PositionMatrixRight
poke _d, 15, int(15.0 * _s.10 / 100.0) ;EarlyDiffusion
poke _d, 16, int(15.0 * _s.10 / 100.0) ;LateDiffusion
poke _d, 17, t.0 ;LowEQGain
poke _d, 19, t.1 ;LowEQCutoff
poke _d, 18, 4 ;HighEQGain
poke _d, 20, 6 ;HighEQCutoff
lpoke _d, 21, float(_s.12) ;RoomFilterFreq
lpoke _d, 25, float(_s.1 / 100.0) ;RoomFilterMain
lpoke _d, 29, float(_s.2 / 100.0) ;RoomFilterHF
lpoke _d, 33, float(_s.6 / 100.0) ;ReflectionsGain
lpoke _d, 37, float(_s.8 / 100.0) ;ReverbGain
lpoke _d, 41, t.2 ;DecayTime
lpoke _d, 45, float(_s.11) ;Density
lpoke _d, 49, float(100) ;RoomSize
poke _d, 53, 0 ;DisableLateField
return
; ピークメーター
;-----------------------------
#deffunc xaPeakMeter int _id, array _out
if m_pSubmixVoice._id = 0 : return
_EnableEffect m_pSubmixVoice._id, 1
_GetEffectParameters m_pSubmixVoice._id, 1, m_volumeMeterLevels, size
if vartype(_out)!=3 || length(_out) < m_channels { ddim _out, m_channels }
f2ds m_peakLevels, _out, m_channels
return
; グループ作成
;-----------------------------
#deffunc xaGroup int _id, int _stage, int _fxType
if _id >= m_submixMax : return -1
xaDelGroup _id
flags = 0x0008 ; *XAUDIO2_VOICE_USEFILTER
CreateSubmixVoice m_XAudio, m_pSubmixVoice._id, m_channels, m_sampleRate, flags, _stage, 0,0
if stat != 0 : return -1
CreateGroupFx _id, _fxType
if stat != 0 : return -2
return 0
; グループ出力先設定
;-----------------------------
#define global xaGroupSend(%1,%2=-1,%3=-1,%4=-1,%5=-1) _xaGroupSend %1,%2,%3,%4,%5
#deffunc _xaGroupSend int _id, int _s1, int _s2, int _s3, int _s4
if m_pSubmixVoice._id = 0 : return
sends = 0, 0 : count = 0 : i = 0
if _s1>-1 { send.i = 0 : i++ : send.i = m_pSubmixVoice._s1 : i++ : count++ }
if _s2>-1 { send.i = 0 : i++ : send.i = m_pSubmixVoice._s2 : i++ : count++ }
if _s3>-1 { send.i = 0 : i++ : send.i = m_pSubmixVoice._s3 : i++ : count++ }
if _s4>-1 { send.i = 0 : i++ : send.i = m_pSubmixVoice._s4 : i++ : count++ }
if count > 0 { sends = count, varptr(send)}
_SetOutputVoices m_pSubmixVoice._id, sends
if stat != 0 : return -1
return 0
; グループ削除
;-----------------------------
#deffunc xaDelGroup int _id
if m_pSubmixVoice._id != 0 {
_DestroyVoice m_pSubmixVoice._id
m_pSubmixVoice._id = 0
}
if m_pVolumeMeter._id != 0 {
delcom m_volumeMeter._id
m_pVolumeMeter._id = 0
}
if m_pGroupFx._id != 0 {
delcom m_groupFx._id
m_pGroupFx._id = 0
m_groupFxType._id = 0
}
return
#deffunc xaDelGroupAll
repeat m_submixMax : xaDelGroup cnt : loop
return
; グループ音量
;-----------------------------
#deffunc xaGroupVol int _id, double _vol
if m_pSubmixVoice._id == 0 : return
_SetVolume m_pSubmixVoice._id, _vol
return stat
; グループフィルター
;-----------------------------
#deffunc xaGroupFilter int _id, int _type, double _freq, double _q/*1/q*/
if m_pSubmixVoice._id == 0 : return
filterParams = _type, float(_freq), float(limitf(_q, 0, 1.5))
_SetFilterParameters m_pSubmixVoice._id, filterParams
return stat
; 読み込み
;-----------------------------
#deffunc xaLoad str _file, int _id, int _gid, int _flags
if (_id < 0) || (_id >= m_voiceMax) : return -1
if (_gid < 0) || (_gid >= m_submixMax) : return -2
if m_pSubmixVoice._gid = 0 : return -3
xaDel _id
xaLoop _id, 0, 0, 0
flags = 0
if _flags & 1 : flags |= 0x0008 ; *XAUDIO2_VOICE_USEFILTER
if _flags & 2 : flags |= 0x0002 ; *XAUDIO2_VOICE_NOPITCH
exist _file : sdim data, strsize : bload _file, data
if (checkID(data,"RIFF", 0) && checkID(data,"WAVE", 8)) = 0 : return -1
offset = 12
repeat -1
if offset >= varsize(data) : break
if checkID(data,"fmt ", offset) {
offset = dupChunkData(fmtChunk, data, offset)
continue
}
if checkID(data,"data", offset) {
offset = dupChunkData(dataChunk, data, offset)
continue
}
if checkID(data,"smpl", offset) {
offset = dupChunkData(smplChunk, data, offset)
xaLoop _id, smplChunk.11, smplChunk.12, -1
continue
}
offset = dupChunkData(_, data, offset)
loop
m_pAudioDataSize._id = varsize(dataChunk)
m_pAudioData._id = malloc(m_pAudioDataSize._id)
dupptr audioData, m_pAudioData._id, m_pAudioDataSize._id
memcpy audioData, dataChunk, m_pAudioDataSize._id
send = 0, m_pSubmixVoice._gid : sends = 1, varptr(send) : pSends= varptr(sends)
CreateSourceVoice m_XAudio, m_pSourceVoice._id, fmtChunk, flags, m_freqRatio,0,pSends,0
if stat != 0 : return -1
xaPan _id, 0
return 0
; 削除
;-----------------------------
#deffunc xaDel int _id
if m_pAudioData._id != 0 {
free m_pAudioData._id
m_pAudioDataSize._id = 0
m_pAudioData._id = 0
}
if m_pSourceVoice._id != 0 {
_DestroyVoice m_pSourceVoice._id
m_pSourceVoice._id = 0
}
return
#deffunc xaDelAll
repeat m_voiceMax : xaDel cnt : loop
return
; 再生
;-----------------------------
#deffunc xaPlay int _id, int _mode
xaStop _id
if m_pAudioDataSize._id == 0 : return
xaudio2_buffer.0 = 0x40, m_pAudioDataSize._id, m_pAudioData._id, 0, 0
xaudio2_buffer.5 = m_loopBegin._id, m_loopLength._id, m_loopCount._id, 0
_SubmitSourceBuffer m_pSourceVoice._id, varptr(xaudio2_buffer)
_Start m_pSourceVoice._id
return stat
; 停止
;-----------------------------
#deffunc xaStop int _id
if m_pSourceVoice._id == 0 : return
_Stop m_pSourceVoice._id : _FlushSourceBuffers m_pSourceVoice._id
return stat
#deffunc xaStopAll
repeat m_voiceMax : xaStop cnt : loop
return
; ポーズ
;-----------------------------
#deffunc xaPause int _id
if m_pSourceVoice._id == 0 : return
_Stop m_pSourceVoice._id
return stat
; リジューム
;-----------------------------
#deffunc xaResume int _id
if m_pSourceVoice._id == 0 : return
_Start m_pSourceVoice._id
return stat
; ループ
;-----------------------------
#deffunc xaLoop int _id, int _count, int _st, int _ed
m_loopBegin._id = _st : m_loopLength._id = _ed - _st
if _count < 0 { m_loopCount._id = 255 } else { m_loopCount._id = limit(_count, 0, 255) }
return stat
#deffunc xaExitLoop int _id
if m_pSourceVoice._id == 0 : return
_ExitLoop m_pSourceVoice._id
return stat
; 音量
;-----------------------------
#deffunc xaVol int _id, double _vol
if m_pSourceVoice._id == 0 : return
_SetVolume m_pSourceVoice._id, _vol
return stat
; 周波数
;-----------------------------
#deffunc xaFreq int _id, double _ratio
if m_pSourceVoice._id == 0 : return
_SetFrequencyRatio m_pSourceVoice._id, _ratio
return stat
; フィルター tyep: enum { LowPass, BandPass, HighPass, Notch }
;-----------------------------
#deffunc xaFilter int _id, int _type, double _freq, double _q/*1/q*/
if m_pSourceVoice._id == 0 : return
filterParams = _type, float(_freq), float(limitf(_q, 0, 1.5))
_SetFilterParameters m_pSourceVoice._id, filterParams
return stat
; 定位
;-----------------------------
#deffunc xaPan int _id, double _pan
if m_pSourceVoice._id == 0 : return
srcCh = getInputChannels(m_pSourceVoice._id)
dstCh = m_channels
if dstCh = 2 { ; ステレオのみ対応
l = limitf(0.5 - _pan * 0.5, 0, 1) : r = 1.0 - l ; リニア
l = sin(0.5*M_PI*l) : r = sin(0.5*M_PI*r) ; 等パワー
if srcCh = 1 {
; L_IN
;-------------------
lvMtx.0 = float(l) ; L_OUT
lvMtx.1 = float(r) ; R_OUT
_SetOutputMatrix m_pSourceVoice._id, srcCh, dstCh, lvMtx
}
if srcCh = 2 {
; L_IN : R_IN
;-----------------------------
lvMtx.0 = float(l), float(0) ; L_OUT
lvMtx.2 = float(0), float(r) ; R_OUT
_SetOutputMatrix m_pSourceVoice._id, srcCh, dstCh, lvMtx
}
}
return
; 情報 TODO: 種類を増やす、番号整理(もしくは小分けにする)
;-----------------------------
#defcfunc xaStat int _id, int _mode
if m_pSourceVoice._id == 0 : return
if _mode = 4 : return getInputChannels(m_pSourceVoice._id)
if _mode = 5 : return getInputSampleRate(m_pSourceVoice._id)
if _mode = 16 : return getStateBuffersQueued(m_pSourceVoice._id)
if _mode = 17 : return getStateSamplesPlayed(m_pSourceVoice._id)
return
#global
call_once@ezXAudio
#endif
;===============================================================================
; サンプル ※エフェクトグループとゲーム的な使用に耐えられるかのテスト
#include "hsp3dish.as"
#enum SND_GROUP_MASTER = 0 ; マスター※固定自動生成
#enum SND_GROUP_BGM ; 音楽
#enum SND_GROUP_SFX ; 効果音
#enum SND_GROUP_REV ; 残響エフェクト
#enum SND_GROUP_ECH ; エコー
TBL_GROUP_TEXT = "MASTER","BGM","SFX","REVERB","ECHO"
TBL_GROUP_ID = SND_GROUP_MASTER,SND_GROUP_BGM,SND_GROUP_SFX,SND_GROUP_REV,SND_GROUP_ECH
; グループを追加
xaGroup SND_GROUP_BGM, 0 ; 第二引数で処理の階層を設定
xaGroup SND_GROUP_SFX, 0 ; ※同値以下にはSend出来ません。
xaGroup SND_GROUP_REV, 1
xaGroup SND_GROUP_ECH, 1
; グループの出力先を設定
xaGroupSend SND_GROUP_BGM, SND_GROUP_MASTER
xaGroupSend SND_GROUP_SFX, SND_GROUP_MASTER, SND_GROUP_REV, SND_GROUP_ECH
xaGroupSend SND_GROUP_REV, SND_GROUP_MASTER
; エフェクト ※グループに対して1つ設定できます。
xaFxLimiter SND_GROUP_MASTER, 6, 1800
xaFxLimiter SND_GROUP_SFX, 6, 1800
xaFxReverb SND_GROUP_REV, "CITY"
xaFxEcho SND_GROUP_ECH, 1, 0.1, 200 : xaGroupVol SND_GROUP_ECH, 0.1
; 読み込み
xaLoad dir_tv+"se_block2.wav", 0, SND_GROUP_BGM : xaLoop 0, -1
xaLoad dir_tv+"se_shot.wav" , 1, SND_GROUP_SFX
xaLoad dir_tv+"se_bom.wav" , 2, SND_GROUP_SFX
xaLoad dir_tv+"se_foot.wav" , 3, SND_GROUP_SFX
xaLoad dir_tv+"se_jump.wav" , 4, SND_GROUP_SFX
xaLoad dir_tv+"se15.wav" , 5; 指定なしはマスター
xaLoad dir_tv+"se14.wav" , 6; 指定なしはマスター
screen 0,640,480 : title "早打ちゲーム" : randomize
sx_max = ginfo_sx : sx_mid = sx_max/2 : sy_max = ginfo_sy : sy_mid = sy_max/2
ranking = 20000,15000,12500,10000,7500,5000,2500,1000,500 : ranking_cur = 8
game_state = 0 : gosub *RESET : xaPlay 0
*MAIN
on game_state gosub *UPDATE_TITLE, *UPDATE_INGAME, *UPDATE_RESULT
redraw 0 : gmode 0 : font "", 32
on game_state gosub *DRAW_TITLE, *DRAW_INGAME, *DRAW_RESULT
if mousex>120 { gosub *DRAW_METER }
redraw 1 : await 16
goto *MAIN
*RESET
bullets = 6 : score = 0 : score_pt = 100 : time_limit = 60*10 : pt=0,0,0,0
gosub *RESET_TERGET
return
*RESET_TERGET
target_px = limit(rnd(sx_max),64,sx_max-64) : target_py = limit(rnd(ginfo_sy),64,sy_max-64) : target_r = rnd(4)*8+16
return
*SHOT_GUN
pan = (double(mousex)/sx_max)*2.0 - 1.0
xaPlay 1 : xaPan 1, pan : xaFreq 1, 1.+0.01*rnd(50) : shot_time = 5 : bullets = limit(bullets-1,0)
return
*UPDATE_TITLE
stick pad
if pad == 256 { gosub *SHOT_GUN } : shot_time=limit(shot_time-1,0,255)
if pad == 512 { xaPlay 5 : xaStop 0 : game_state = 1 : gosub *RESET}
return
*UPDATE_INGAME
stick pad
if pad == 256 {
if bullets>0 {
gosub *SHOT_GUN
dist = sqrt(powf(mousex-target_px,2)+powf(mousey-target_py,2))
if dist<=target_r {
xaPlay 2 : xaPan 2, pan : xaFreq 2, 1.+0.01*rnd(50)
pt = score_pt*limit(40-dist,1),target_px,target_py,30
score += pt : score_pt = 100
gosub *RESET_TERGET
}
} else { xaPlay 3 : xaFreq 3, 1.+0.01*rnd(50) }
}
if pad & 512 { xaPlay 4 : bullets = 6 }
shot_time=limit(shot_time-1,0,255) : pt.3--
score_pt=limit(score_pt-1,0) : hightscore=limit(score,hightscore)
time_limit--
if time_limit == 180 || time_limit == 120 || time_limit == 60 { xaPlay 6 }
if time_limit <= 0 { gosub *UPDATE_RANKING : xaPlay 5 : game_state = 2}
return
*UPDATE_RANKING
ranking.8 = score : sortval ranking, 1 : repeat 9 : sortget i, cnt : if i=8 { ranking_cur=cnt : break } : loop
return
*UPDATE_RESULT
stick pad
if pad == 256 { gosub *SHOT_GUN } : shot_time=limit(shot_time-1,0,255)
if pad == 512 { xaPlay 4 : xaPlay 0 : game_state = 0 }
return
*DRAW_TITLE
gosub *DRAW_BG : gosub *DRAW_TITLELOGO : gosub *DRAW_RANKING : gosub *DRAW_GUN
return
*DRAW_INGAME
gosub *DRAW_BG : gosub *DRAW_TARGET : gosub *DRAW_GUN : gosub *DRAW_UI
return
*DRAW_TITLELOGO
font "", 64 : pos sx_mid-320, 16 : rgbcolor $ffff00 : mes " - Quick Shooting -", 4
font "", 32 : pos sx_mid-160, sy_max-64 : rgbcolor $ff00ff : mes "Right click to start", 4
return
*DRAW_RESULT
gosub *DRAW_BG : gosub *DRAW_RANKING : gosub *DRAW_GUN : gosub *DRAW_UI
return
*DRAW_RANKING
pos sx_mid-96,88 : rgbcolor $ff0000 : mes " RNAKING", 4
repeat 8 :rgbcolor (cnt!=ranking_cur)*$ff<<16|$00ffff : mes strf("%2d: %8d", cnt+1, ranking.cnt), 4 : loop
return
*DRAW_BG
gradf 0,0,sx_max,0.75*sy_max,1,$83aeff,$c6f4fb : gradf 0,0.75*sy_max,sx_max,0.25*sy_max,1,$ffeecd,$82e487
return
*DRAW_GUN
rgbcolor : line mousex-32,mousey,mousex+32,mousey : line mousex,mousey-32,mousex,mousey+32
circle mousex-8,mousey-8,mousex+8,mousey+8,0
gmode 5,,,shot_time*64: rgbcolor $ffffff : grect sx_mid, sy_mid, 0,sx_max, sy_max
return
*DRAW_TARGET
repeat target_r/4:r=target_r-cnt*4:rgbcolor (cnt\2)*$ffffff : circle target_px-r,target_py-r,target_px+r,target_py+r:loop
if pt.3>0 {rgbcolor $ffffff:pos sx_max,sx_may:mes pt:pos pt.1-ginfo_mesx/2,pt.2+pt.3-ginfo_mesy*2:mes pt,4}
return
*DRAW_UI
pos 0,0 : rgbcolor $ffff00 : mes strf("HIGHT%8d",hightscore),5
pos sx_max-208,0: rgbcolor $00ffff : mes strf("SCORE%8d",score),5
pos sx_mid-32 : rgbcolor $ffffff : mes strf("Time\n %02d",time_limit/60),5
pos sx_mid-bullets*16,ginfo_sy-40 : rgbcolor $ac813f : repeat bullets : mes "■",5 : loop
rgbcolor $ff5d22 : boxf sx_mid-score_pt, sy_max-60, sx_mid+score_pt, sy_max-50
return
*DRAW_METER
pos 0,64 : font "", 16
foreach TBL_GROUP_ID
xaPeakMeter TBL_GROUP_ID.cnt, peak
rgbcolor $ffffff: mes "◆"+TBL_GROUP_TEXT.cnt, 4
foreach peak
dB = limitf(20.0*(logf(peak.cnt)/logf(10)), -96) : amp = peak.cnt*96
rgbcolor $333333: boxf ginfo_cx, ginfo_cy, ginfo_cx+ 96, ginfo_cy+15
rgbcolor $663333: boxf ginfo_cx+96, ginfo_cy, ginfo_cx+120, ginfo_cy+15
rgbcolor $00ee00: boxf ginfo_cx, ginfo_cy, ginfo_cx+amp, ginfo_cy+14
rgbcolor $ffffff: if dB<=-96 : mes "-∞",4 : else : mes strf("%+4.2f",dB), 4
loop
loop
return

| |
|