HSPポータル
サイトマップ お問い合わせ


HSPTV!掲示板


未解決 解決 停止 削除要請

2025
0829
usagiXAudio2を使った再生16解決


usagi

リンク

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の周波数変更については要望だしてありますが、これが追加されるだけで
できることがかなり広がると思われます。



Nick Bender

リンク

2025/9/3(Wed) 16:25:07|NO.103927

DLL不要で、途中のループ再生や音量、パンなどを扱えるのは大きな利点です。通常、こういった機能は実装が最も難しい部分ですからね。シンプルさを保つという設計思想も素晴らしいですし、他の人も採用して発展させやすいでしょう。素晴らしい仕事です!
https://ragdollhitstickman.io



usagi

リンク

2025/9/5(Fri) 11:55:25|NO.103939

みなさんコメントありがとうございます。
>名無しさん
とんでもないです。私も研究目的なので至らない所があり、指摘いただけると嬉しいです。
>窓月ららさん
OGGのデコードも面白そうですね。自作音源開発されてましたね楽しみです。
>Nick Bender
難しい処理は全部XAudioがしてくれるので楽でしたが、インターフェースから関数引っ張ってくるのが厄介でした。。。



へびぃ

リンク

2025/9/8(Mon) 08:42:10|NO.103958

ちょうどXAudio2について調べてるところだったので、すごく有難いです。
理解は全く追いついておりませんが、色々と実験したいので使わせていただきます。

ありがとうございます!



レピッシュ

リンク

2025/9/20(Sat) 22:40:26|NO.104022

こちらコンテスト作品で使用させていただきました(NO.103884のスクリプト)
ogg再生ではできなかったことができるようになって助かりました

これからも使わせていただきます
ありがとうございました



usagi

リンク

2025/9/25(Thu) 08:26:51|NO.104026

>へびぃさん
ちょっとこれ私の魔改造が過ぎてしまったせいか分かりにくかったですよね。。。
個人的に反省してまして、手入れの面からももっとシンプルで制限してたものに書き直しを考えてます。(基本は標準命令のみで実現)

>レピッシュさん
作品プレイさせていただきました。
ゲーム自体も素晴らしいですが、UIやチュートリアルの作りこみがスゴイですね!
こんなしっかりとしたゲームで使っていただき感激です。わたし自身も使用に耐えうるか実験中だったので参考になりました。



usagi

リンク

2025/9/25(Thu) 08:52:16|NO.104027

こんにちわ。今までの反省を生かして書き直してみました。(ちょっと誤字も修正)
関数ポインタ書き換えたり、機械語使ったり、ぱっと見分からない所が多かったので、
Xaudio2のdllとcom以外はシンプルに標準命令で出来るだけ記載しました。

ついでに、同じwavの同時再生数を増やす目的として参照再生(メモリ増えない)と、音ゲー用途などでシーク再生できるようにしました。
あと、よくゲームのメニューでBGMやSEの音量調整あると思うので、グループ音量機能付けました。
これくらいがミニマムな機能として丁度いいかなぁ。。。と思いつつ。

良くない所や改善点あったらご指摘いただければと思います。


;=============================================================================== ; XAudio2再生モジュール author: usagi file: ezXAudio.hsp ; シンプル命令,WAV複製再生可能,機械語&特殊マクロを使わない バージョン ;=============================================================================== #ifndef __EZXAUDIO__ #define global __EZXAUDIO__ ; WAVEモジュール変数 #module mod_wave m_wav, m_buffer #defcfunc local getChunkID var _data, int _offset id = " " : lpoke id, 0, lpeek(_data, _offset) : return id #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) #modinit str _file mref i, 2 m_buffer = /*xaudio2_buffer*/0x0040, 0,0, 0,0, 0,0,0/*8:fmt_size, 9:fmt_ptr*/,0,0 exist _file : sdim m_wav, strsize : bload _file, m_wav if getChunkID(m_wav, 0)!="RIFF" || getChunkID(m_wav, 8)!="WAVE" : return -1 offset = 12 do chunkID = getChunkID(m_wav, offset) offset = dupChunkData(chunk, m_wav, offset) switch chunkID case "fmt " : m_buffer.8 = varsize(chunk), varptr(chunk) : swbreak case "data" : m_buffer.1 = varsize(chunk), varptr(chunk) : swbreak case "smpl" : if length(chunk)>12 { m_buffer.5 = chunk.11, chunk.12 - chunk.11, 255 } : swbreak swend until offset >= varsize(m_wav) return i #modcfunc local pBuff return varptr(m_buffer) #modcfunc local pFmt return m_buffer.9 #global ; 本体 ;=============================================================================== #module "ezXAudio" ; DLL と COM #uselib "XAudio2_9.dll" #func XAudio2Create "XAudio2Create" var,int,int #define IID_IXAudio2 "{2B02E3CF-2E0B-4ec3-BE45-1B2A3FE7210D}" #usecom IXAudio2 IID_IXAudio2 #comfunc CreateSourceVoice 5 var,int,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 StopEngine 9 ; Floatのキャスト #defcfunc d2f double _d f = _d * BIAS : return (lpeek(f, 4)&0x80000000) | (lpeek(f, 4)<<3&$7fffffff) | (lpeek(f)>>29&7) #defcfunc f2d int _f t = 0.0 : lpoke t, 4, (_f&$80000000) | ((_f&$7fffffff)>>3) : lpoke t, 0, _f<<29 : return t*BIAS ; インターフェースメソッド呼び出し #defcfunc local callInterfaceFunc array args, int _funcidx, int _argnum dupptr p, args.0, 4 : dupptr pfuncs, p, _funcidx*4+4 return callfunc(args, pfuncs._funcidx, _argnum) #deffunc local SetOutputVoices var _p, int _pSendList args = _p, _pSendList return callInterfaceFunc(args, 1, 2) #deffunc local SetVolume var _p, double _vol args = _p, d2f(_vol), 0 return callInterfaceFunc(args, 12, 3) #deffunc local SetOutputMatrix var _p, int _srcCh, int _dstCh, var _lvMtx args = _p, 0, _srcCh, _dstCh, varptr(_lvMtx), 0 return callInterfaceFunc(args, 16, 6) #deffunc local DestroyVoice var _p args = _p res = callInterfaceFunc(args, 18, 1) if res == 0 { _p = 0 } return res #deffunc local StartVoice var _p args = _p, 0, 0 return callInterfaceFunc(args, 19, 3) #deffunc local StopVoice var _p args = _p, 0, 0 return callInterfaceFunc(args, 20, 3) #deffunc local SubmitSourceBuffer var _p, int _pBuf args = _p, _pBuf, 0 return callInterfaceFunc(args, 21, 3) #deffunc local FlushSourceBuffers var _p args = _p return callInterfaceFunc(args, 22, 1) #deffunc local SetFrequencyRatio var _p, double _ratio args = _p, d2f(_ratio), 0 return callInterfaceFunc(args, 26, 3) #defcfunc local GetInputChannels int _p args = _p, varptr(res) : res = 0,0,0,0 res = callInterfaceFunc(args, 0, 2) return res.2 #defcfunc local GetBuffersQueued int _p args = _p, varptr(res), 0x100 : res = 0,0,0,0 res = callInterfaceFunc(args, 25, 3) return res.1 #defcfunc local GetSamplesPlayed int _p args = _p, varptr(res), 0 : res = 0,0,0,0 res = callInterfaceFunc(args, 25, 3) return res.2 ; 定数 #define DEF_SMPLRATE 48000 ; マスター再生周波数 #define DEF_CHANNEL 2 ; マスターチャンネル数 #define DEF_MAXFREQ 8 ; 最大再生速度 ;=============================================================================== ; コマンド ;=============================================================================== ; 初期化 ;----------------------------- #deffunc xaInit int _wavMax, int _groupMax if m_pXAudio != 0 { xaDeinit } dim m_pVoice, _wavMax dim m_i , _wavMax : foreach m_i : m_i.cnt = -1 : loop dimtype m_wave, 5 XAudio2Create m_pXAudio, 0, 1 : newcom m_XAudio, IID_IXAudio2, -1, m_pXAudio CreateMasteringVoice m_XAudio, m_pMasterVoice, DEF_CHANNEL, DEF_SMPLRATE, 0,0,0,0 if stat != 0 : return -1 repeat _groupMax CreateSubmixVoice m_XAudio, m_pGroupVoice.cnt, DEF_CHANNEL, DEF_SMPLRATE, 0,0,0,0 if stat != 0 : return -1 loop return 0 ; 破棄 ;----------------------------- #deffunc xaDeinit onexit if m_pXAudio = 0 : return StopEngine m_XAudio xaDelAll DestroyVoice m_pMasterVoice foreach m_pGroupVoice : DestroyVoice m_pGroupVoice.cnt : loop delcom m_XAudio : m_pXAudio = 0 return ; ★読込: ファイル名, ID ;----------------------------- #deffunc xaLoad str _file, int _id xaDel _id newmod m_wave, mod_wave, _file : m_i._id = stat CreateSourceVoice m_XAudio, m_pVoice._id, pfmt@mod_wave(m_wave(m_i._id)), 0, DEF_MAXFREQ, 0,0,0 xaPan _id, 0.0 return stat ; ★複製: ID, 複製元のID ;----------------------------- #deffunc xaPoly int _id, int _dupId m_i._id = m_i._dupId CreateSourceVoice m_XAudio, m_pVoice._id, pfmt@mod_wave(m_wave(m_i._dupId)), 0, DEF_MAXFREQ, 0,0,0 xaPan _id, 0.0 return stat ; ★破棄: ID ※複製の場合も削除されます ;----------------------------- #deffunc xaDel int _id if m_pVoice._id != 0 { DestroyVoice m_pVoice._id } if m_i._id != -1 { delmod m_wave(m_i._id) : m_i._id = -1 } return #deffunc xaDelAll foreach m_pVoice : xaDel cnt : loop return ; ★再生: ID ;----------------------------- #deffunc xaPlay int _id if varuse(m_wave(m_i._id)) == 0 : return -1 xaStop _id SubmitSourceBuffer m_pVoice._id, pBuff@mod_wave(m_wave(m_i._id)) StartVoice m_pVoice._id return stat ; ★シーク再生: ID, 開始位置(サンプル数) ;----------------------------- #deffunc xaSeek int _id, int _begin if varuse(m_wave(m_i._id)) == 0 : return -1 xaStop _id dupptr buff, pBuff@mod_wave(m_wave(m_i._id)), 32 buff.3 = _begin SubmitSourceBuffer m_pVoice._id, varptr(buff) buff.3 = 0 StartVoice m_pVoice._id return stat ; ★停止: ID ;----------------------------- #deffunc xaStop int _id if m_pVoice._id == 0 : return -1 StopVoice m_pVoice._id FlushSourceBuffers m_pVoice._id return stat ; ★一時停止: ID ;----------------------------- #deffunc xaPause int _id if m_pVoice._id == 0 : return -1 StopVoice@ezXAudio m_pVoice._id return stat ; ★再開: ID ;----------------------------- #deffunc xaResume int _id if m_pVoice._id == 0 : return -1 StartVoice m_pVoice._id return stat ; ★音量: ID, 音量 ;----------------------------- #deffunc xaVol int _id, double _vol if m_pVoice._id == 0 : return -1 SetVolume m_pVoice._id, _vol return stat ; ★音程: ID, 比率 ;----------------------------- #deffunc xaFreq int _id, double _ratio if m_pVoice._id == 0 : return -1 SetFrequencyRatio m_pVoice._id, _ratio return stat ; ★定位: ID, パン ;----------------------------- #deffunc xaPan int _id, double _pan if m_pVoice._id == 0 : return -1 srcCh = GetInputChannels(m_pVoice._id) dstCh = DEF_CHANNEL 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 { lvMtx.0 = d2f(l) lvMtx.1 = d2f(r) } if srcCh = 2 { lvMtx.0 = d2f(l), d2f(0) lvMtx.2 = d2f(0), d2f(r) } SetOutputMatrix m_pVoice._id, srcCh, dstCh, lvMtx } return ; ★再生中: ID ;----------------------------- #defcfunc xaIsPlay int _id if m_pVoice._id == 0 : return -1 return GetBuffersQueued(m_pVoice._id) ; ★再生時間: ID ;----------------------------- #defcfunc xaTime int _id if m_pVoice._id == 0 : return -1 return GetSamplesPlayed(m_pVoice._id) ; ★グループ: ID, グループID (-1マスター) ;----------------------------- #deffunc xaGroup int _id, int _gId if m_pVoice._id = 0 : return if _gId < 0 { SetOutputVoices m_pVoice._id, 0 } else { sends = 0, m_pGroupVoice._gId sendList = 1, varptr(sends) SetOutputVoices m_pVoice._id, varptr(sendList) } return ; ★グループ音量: グループID, 音量 ;----------------------------- #deffunc xaGroupVol int _id, double _vol if m_pGroupVoice._id == 0 : return -1 SetVolume m_pGroupVoice._id, _vol return stat ; 起動時に一度だけ実行 #deffunc local call_once BIAS = powf(2,$380) ; float, double 変換用のバイアス xaInit 256, 16 ; 初期化 return #global call_once@ezXAudio #endif ;=============================================================================== ; ■□■ ここからテストプログラム ■□■ xaLoad dir_tv+"se_shot.wav", 0 xaGroup 0, 1 repeat 7, 1 xaPoly cnt, 0 ; 複製 xaGroup cnt, 1 loop xaGroupVol 1, 0.4 ; グループ音量設定 xaLoad dir_tv+"se_bom.wav", 8 *MAIN stick pad, 256 if pad=256 && interval<=0 { spx.index = mousex : spy.index = mousey pan = double(mousex)/ginfo_sx*2-1 vol = 0.9 + 0.1*(double(rnd(32768))/32767.0) frq = 0.8 + 0.2*(double(rnd(32768))/32767.0) xaPlay index xaVol index, vol xaPan index, pan xaFreq index, frq index++ : index \= 8 interval = 6 } interval-- if pad=512 { xaPlay 8 } redraw 0 : color : boxf color 255 repeat 8 if xaIsPlay(cnt) == 0 : continue hsvcolor 20*cnt, 255, 255 r = xaTime(cnt)/200\20 circle spx.cnt-r, spy.cnt-r, spx.cnt+r, spy.cnt+r, 0 loop redraw 1 : await 16 goto *MAIN



レピッシュ

リンク

2025/9/27(Sat) 17:56:25|NO.104039

>作品プレイさせていただきました。
>ゲーム自体も素晴らしいですが、UIやチュートリアルの作りこみがスゴイですね!
>こんなしっかりとしたゲームで使っていただき感激です

プレイありがとうございます
oggだと一時停止/再開がどうやってもずれてしまったり
xaFreqを使用してテンポを変える演出が可能になったりと
かなり助かりました

>わたし自身も使用に耐えうるか実験中だったので参考になりました。
有用なモジュールだと感じておりますので
検証などのできる協力はしていきたいと思っております

ということでNO.104027の最新のモジュールを組み込んで
検証してみました

BGM、SEの再生、xaFreqを使用した演出など
前回のモジュールでできていたことは一通り動作していました
グループ音量機能を使ってオプションでのBGM、SE音量調整を反映させたところ
こちらも問題なく動作いたしました

また、ogg→wavでexeファイルのサイズが5倍になったことから
XAudio2.9はxWMA再生に対応しているとのことだったので
xWMA再生できるように改造してexeファイルのサイズダウンもしました

xWMAに関してですがusagiさんの方で
wav以外の形式の実装の予定はありますでしょうか?

xWMAはXAudio2.8で非対応、XAudio2.9で復活という流れなので
またいつ非対応になるか読めないことと
C++でMediaFoundationを使用してmp3の再生をしているソースを参考に
こちらに組み込もうと頑張ってみましたが
C++の開発にしても、HSP側のDLL使用にしても
圧倒的に経験値が足りていないため、遅々として進まずといったところで
少し気になっております



usagi

リンク

2025/9/27(Sat) 22:56:24|NO.104042

とても発想の勉強になります!!
ランダム再生くらいの用途に考えてたのですが、マリオ的なテンポアップの表現に使えるとわ。
しかもxWMAまで対応なんて、すっすごい。。

実際に作品を作ると容量の問題が出てくるのですね。参考になります。
とく更新の予定は無いですが、ローカルではdllを使ってogg vorbisの再生と、wavのストリーム(コールバックは機械語使うことになるのでtimerなどで。。)はお遊びレベルでしか無いですが実験してみてます。
もし今後試してみるとしたらopusでしょうか。音質も圧縮も良いと感じますしライセンスも使いやすく、採用例から長く使えそうな気がしてます。

ただHSPだけで行うとすると時間はかかるかもですね。。。
Oggのコンテナは簡単に剥がせそうですが、デコード部分の難易度が高そうでした。
(私もC++はよく分かりません、むつかしい。。。)



レピッシュ

リンク

2025/9/28(Sun) 15:26:20|NO.104045

容量については
サイズが5倍になったことに驚いて
勝手に焦ってしまったことなので
問題があるというつもりはございません
すいませんでした

別形式への対応の件も了解いたしました
今回、新しい知識に触れるいい機会を得ましたので
経験を積む意味でも
自分なりに頑張ってみたいと思います

ありがとうございました



usagi

リンク

2025/9/28(Sun) 17:16:10|NO.104047

1/4程度の圧縮でよければADPCM使うのもありかもしれませんね。
MediaFoundationちょっと面白そうだったので、まにゅある見ながらHSPに書き下ろしてみました。
メモリからの読み込みは資料が探せなかったのでまだ分かってないのですがファイルからなら簡単にできそうです。
wav,adpcm,mp3,wmaの読み込みは確認できましたが、ogg,opusはダメでした(メディアプレイヤーで再生できるので行けそうな気がするのでけど。。)
よろしかったらどうぞ。

#module #uselib "Ole32.dll" #func CoTaskMemFree "CoTaskMemFree" int #uselib "Mfplat.dll" #func MFStartup "MFStartup" int, int #func MFShutdown "MFShutdown" #func MFCreateMediaType "MFCreateMediaType" int #func MFCreateWaveFormatExFromMFMediaType "MFCreateWaveFormatExFromMFMediaType" int, int, int, int #uselib "Mfreadwrite.dll" #func MFCreateSourceReaderFromURL "MFCreateSourceReaderFromURL" wptr, int, int #func MFCreateSourceReaderFromByteStream "MFCreateSourceReaderFromByteStream" var, int, int #define IID_IMFSourceReader "{70ae66f2-c809-4e4f-8915-bdcb406b7993}" #usecom IMFSourceReader IID_IMFSourceReader #comfunc GetCurrentMediaType 6 int, int #comfunc SetCurrentMediaType 7 int, int, int #comfunc ReadSample 9 int, int, int, int, int, int #define IID_IMFMediaType "{44ae0fa8-ea31-4109-8d2e-4cae4997c555}" #usecom IMFMediaType IID_IMFMediaType #comfunc SetGUID 24 int, int #define IID_IMFSample "{c40a00f2-b93a-4d80-ae8c-5a1c634f58e4}" #usecom IMFSample IID_IMFSample #comfunc ConvertToContiguousBuffer 41 int #define IID_IMFMediaBuffer "{045fa593-8799-42b8-bc8d-8968c6453507}" #usecom IMFMediaBuffer IID_IMFMediaBuffer #comfunc Lock 3 int, int, int #comfunc Unlock 4 #define IID_IMFByteStream "{ad4c1b00-4bf7-422f-9175-756693d9130d}" #usecom IMFByteStream IID_IMFByteStream #comfunc Write 12 var, int, var ; ★オーディオを読み込む: URL, formatコピー先, dataコピー先 ;---------------------------------------------------------- #deffunc mfLoadAudio str _url, var _fmt, var _data MFStartup /*MF_VERSION*/(0x2 << 16 | 0x0070), /*MFSTARTUP_NOSOCKET*/0x1 MFCreateSourceReaderFromURL _url, 0, varptr(pMFSourceReader) if pMFSourceReader == 0 : MFShutdown : return -1 newcom MFSourceReader, IID_IMFSourceReader, -1, pMFSourceReader ; メディアタイプを設定 MF_MT_MAJOR_TYPE = $48eba18e,$4687f8c9,$740a11bf,$8f6af9c9 ; "{48eba18e-f8c9-4687-bf11-0a74c9f96a8f}" MF_MT_SUBTYPE = $f7e34c9a,$471442e8,$29cb4bb7,$e5352cd7 ; "{f7e34c9a-42e8-4714-b74b-cb29d72c35e5}" MFMediaType_Audio = $73647561,$00100000,$aa000080,$719b3800 ; "{73647561-0000-0010-8000-00aa00389b71}" MFAudioFormat_PCM = $00000001,$00100000,$aa000080,$719b3800 ; "{00000001-0000-0010-8000-00aa00389b71}" MFCreateMediaType varptr(pMFMediaType) newcom MFMediaType, IID_IMFMediaType, -1, pMFMediaType SetGUID MFMediaType, varptr(MF_MT_MAJOR_TYPE), varptr(MFMediaType_Audio) SetGUID MFMediaType, varptr(MF_MT_SUBTYPE), varptr(MFAudioFormat_PCM) SetCurrentMediaType MFSourceReader, /*MF_SOURCE_READER_FIRST_AUDIO_STREAM*/0xfffffffd, 0, pMFMediaType delcom MFMediaType : pMFMediaType = 0 GetCurrentMediaType MFSourceReader, /*MF_SOURCE_READER_FIRST_AUDIO_STREAM*/0xfffffffd, varptr(pMFMediaType) newcom MFMediaType, IID_IMFMediaType, -1, pMFMediaType ; フォーマット取得 MFCreateWaveFormatExFromMFMediaType pMFMediaType, varptr(pWF), varptr(cbSize), /*MFWaveFormatExConvertFlag_Normal*/0 dupptr _wf, pWF, cbSize , 2 dim _fmt, cbSize/4+1 : memcpy _fmt, _wf, cbSize CoTaskMemFree pWF ; データ取得 sdim _data : data_size = 0 repeat -1 ReadSample MFSourceReader, /*MF_SOURCE_READER_FIRST_AUDIO_STREAM*/0xfffffffd, 0, 0, varptr(dwStreamFlags), 0, varptr(pMFSample) if (dwStreamFlags) || (pMFSample == 0) { break } newcom MFSample, IID_IMFSample, -1, pMFSample ConvertToContiguousBuffer MFSample, varptr(pMFMediaBuffer) newcom MFMediaBuffer, IID_IMFMediaBuffer, -1, pMFMediaBuffer Lock MFMediaBuffer, varptr(pBuffer), 0, varptr(cbCurrentLength) dupptr buf, pBuffer, cbCurrentLength memexpand _data, data_size+cbCurrentLength memcpy _data, buf, cbCurrentLength, data_size, 0 data_size += cbCurrentLength Unlock MFMediaBuffer : dup buf, _dummy_ delcom MFMediaBuffer : pMFMediaBuffer = 0 delcom MFSample : pMFSample = 0 loop delcom MFMediaType : pMFMediaType = 0 delcom MFSourceReader : pMFSourceReader = 0 MFShutdown return 0 #global ; テスト button "開く", *L_OPEN_AUDIO stop *L_OPEN_AUDIO dialog ,16 if stat != 1: mes "キャンセル" : stop rgbcolor $FFFFFF : boxf : color : pos 0, 32 mfLoadAudio refstr, fmt, data if stat : mes "読み込み失敗" : stop mes "----- format -----" mes strf("wFormatTag : %d", fmt.0&$FF) mes strf("nChannels : %d", fmt.0>>16) mes strf("nSamplesPerSec : %d", fmt.1) mes strf("nAvgBytesPerSec: %d", fmt.2) mes strf("nBlockAlign : %d", fmt.3&$FF) mes strf("wBitsPerSample : %d", fmt.3>>16) ch = fmt.0>>16 rate = fmt.1 mes "----- data -----" if ch = 1 { scale = double(ginfo_sx) / (varsize(data)/2) redraw 0 : pos 0, 256 : color 0,128,255 i = 0 repeat varsize(data)/2 l = wpeek(data, cnt*2)<<16>>16 line scale*i, 256.0 - 128.0*(double(l)/65535.0) i++ if cnt\rate=0 : redraw 1 : wait 0 : redraw 0 loop redraw 1 } if ch = 2 { scale = double(ginfo_sx) / (varsize(data)/4) redraw 0 : pos 0, 256 : color 0,128,255 i = 0 repeat varsize(data)/4 l = wpeek(data, cnt*4)<<16>>16 line scale*i, 256.0 - 128.0*(double(l)/65535.0) i++ if cnt\rate=0 : redraw 1 : wait 0 : redraw 0 loop i = 0 pos 0, 384 : color 0,128,255 repeat varsize(data)/4 r = wpeek(data, cnt*4+2)<<16>>16 line scale*i, 384.0 - 128.0*(double(r)/65535.0) i++ if cnt\rate=0 : redraw 1 : wait 0 : redraw 0 loop redraw 1 }



レピッシュ

リンク

2025/9/30(Tue) 23:17:30|NO.104052

MediaFoundationのソースありがとうございます
私の方でも恐らく同じC++のソースをHSPに落とし込もうと
自分なりに頑張っていたのですが
「アクセス違反 C0000005」で落ちまくって困っていたところ
非常に参考になるソースで助かりました
本当にありがとうございました



usagi

リンク

2025/10/1(Wed) 08:17:16|NO.104053

とんでもないです。私も知らなかった事が知れて実験が楽しかったです。コメントありがとうございました。
今回もろもろはMSDNのマニュアルと、comなどはmingwのヘッダ参考にさせていただきました。

HSPは気軽に使えるのに、dllやcomまで使えてしまうので、結構色々できますよね。
私はゲームが好きなのですが、"気軽に少しだけ"サウンドにこだわった作品も増えるといいなぁという気持ちで投稿しました。
もっとこだわりたい場合はステキなライブラリが色々あると思いますので、それを使うのが良いと思ってます。
このスレッドは終了したいと思います。

最後におきまりですが、モジュールの使用は自己責任でお願いします。
エラーチェックなど最低限に省いているので、使い方によっては改造は必要かと考えてます。
※FXに関しては、使いにくいのとパラメタの参考が未確認なところがあったので削除しました。

以上ありがとうございました。



窓月らら

リンク

2025/10/2(Thu) 18:53:46|NO.104057

まだちょっとしか見てないのですが、
こういう情報は今後 XAudio2 を利用したいと考えた方々が参考になると思うので
大変貴重だと思われます。そこからまた新たなソフトが誕生すると思われます。
ありがとうございます。



usagi

リンク

2025/10/16(Thu) 16:20:54|NO.104101

MediaFoundationのメモリから読み込みですが時間ができたのでやってみました。
長くなってしまうので、一部抜粋です。前回のスクリプトに追加してみてくださいまし。
これでパックファイルとかから読み込めますね。

□必要なコマンド

#uselib "Shlwapi.dll" #cfunc SHCreateMemStream "SHCreateMemStream" int, int #define IID_IStream "{0000000c-0000-0000-c000-000000000046}" #uselib "Mfplat.dll" #func MFCreateMFByteStreamOnStream "MFCreateMFByteStreamOnStream" int, int #uselib "Mfreadwrite.dll" #func MFCreateSourceReaderFromByteStream "MFCreateSourceReaderFromByteStream" int, int, int

□スタートアップ部分の差し替えイメージ

MFStartup /*MF_VERSION*/(0x2 << 16 | 0x0070), /*MFSTARTUP_NOSOCKET*/0x1 ; ファイル読み込み exist _file : if strsize = -1 : return -1 sdim buf, strsize : bload _file, buf ; ストリームの作成とソースリーダーの作成 pIStream = SHCreateMemStream(varptr(buf), varsize(buf)) if pIStream = 0 : /*ここで開放もしてリターン*/ : return -2 newcom IStream, IID_IStream, -1, pIStream MFCreateMFByteStreamOnStream pIStream, varptr(pMFByteStream) newcom MFByteStream, IID_IMFByteStream, -1, pMFByteStream MFCreateSourceReaderFromByteStream pMFByteStream, 0, varptr(pMFSourceReader)

※余談※
いまさらながらMSDNって言わないんですね。。。MSLearn?



記事削除

記事NO.パスワード
(質問が解決したスレッドは他の利用者に活用してもらうため、削除しないようお願いします)

NO.103884への返信

マスコット

好きなマスコットを選んでください。

名前

e-mail
HOME
  1. 初めて利用する方は、HSP3掲示板の使い方をお読みください。
  2. 不要部分の多い長いスクリプトの投稿は ご遠慮ください。
  3. 書き込みは自動改行されません。適度に改行を入れてください。
  4. スクリプトは小文字の<pre>〜</pre>で囲むと見やすく表示できます。

削除用パスワード

エラー発生時、再送信すると二重送信になることがあります。
回答が得られたら、お礼書き込み時に[解決]チェックしてください。
SPAM防止のためURLから始まる文章は投稿できません。
SPAM防止のため英文字のみの本文を投稿することはできません。

ONION software Copyright 1997-2025(c) All rights reserved.