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


HSPTV!掲示板


未解決 解決 停止 削除要請

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


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



記事削除

記事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.