From: yyagi Date: Tue, 21 Aug 2018 16:47:34 +0000 (+0900) Subject: #37271 サウンドのミキシングをマルチスレッド化するライブラリを使おうとしたが、うまく動かなかった。将来の再挑戦のため、とりあえず取り込んだ個所をすべて注釈化してde... X-Git-Tag: Release113~9 X-Git-Url: http://git.osdn.net/view?a=commitdiff_plain;h=9ef27d5fb98666cd88739d88c732d8f2a7255d78;p=dtxmania%2Fdtxmania.git #37271 サウンドのミキシングをマルチスレッド化するライブラリを使おうとしたが、うまく動かなかった。将来の再挑戦のため、とりあえず取り込んだ個所をすべて注釈化してdevelopに取り込んだ。(featureブランチを使えという話ですが) --- diff --git a/DTXMania/コード/全体/Program.cs b/DTXMania/コード/全体/Program.cs index 11e276cc..a97dde80 100644 --- a/DTXMania/コード/全体/Program.cs +++ b/DTXMania/コード/全体/Program.cs @@ -150,6 +150,11 @@ namespace DTXMania "bass_fx.dll is not loaded. bass_fx.dll or bass.dll must not exist." + newLine + "Please download DTXMania again." )) bDLLnotfound = true; + //if (!tDLLの存在チェック("dll\\BASSThreadedMixer.dll", + // "BASSThreadedMixer.dll を読み込めません。BASSThreadedMixer.dll が存在しません。" + newLine + "DTXManiaをダウンロードしなおしてください。", + // "BASSThreadedMixer.dll is not loaded. BASSThreadedMixer.dll must not exist." + newLine + "Please download DTXMania again." + // )) + // bDLLnotfound = true; if (!tDLLの存在チェック("dll\\DirectShowLib.dll", "DirectShowLib.dll が存在しません。" + newLine + "DTXManiaをダウンロードしなおしてください。", "DirectShowLib.dll is not found." + newLine + "Please download DTXMania again." diff --git a/FDK/FDK.csproj b/FDK/FDK.csproj index 46560b18..12d621dd 100644 --- a/FDK/FDK.csproj +++ b/FDK/FDK.csproj @@ -47,7 +47,7 @@ false 0219 - TRACE;DEBUG;TEST_CancelEnterCodeInAltEnter2 TEST_Direct3D9Ex_ + TRACE;DEBUG;TEST_CancelEnterCodeInAltEnter2 TEST_Direct3D9Ex_ TEST_MulthThreadedMixer_ false false @@ -138,6 +138,7 @@ + diff --git a/FDK/コード/03.サウンド/BASSThreadedMixerWrapper.cs b/FDK/コード/03.サウンド/BASSThreadedMixerWrapper.cs new file mode 100644 index 00000000..de5a4421 --- /dev/null +++ b/FDK/コード/03.サウンド/BASSThreadedMixerWrapper.cs @@ -0,0 +1,119 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using System.Runtime.InteropServices; +using System.Diagnostics; + +namespace FDK +{ + public unsafe class BASSThreadedMixerLibraryWrapper + { + + //* Parameters + public static readonly int BASSTM_PARAMETER_NO_THREAD_FOR_1_SOURCE = 1; //* Default = True + public static readonly int BASSTM_PARAMETER_THREADS_PRIORITY = 2; //* Affects only sources added after setting this parameter + public static readonly int BASSTM_THREADS_PRIORITY_Idle = 0; + public static readonly int BASSTM_THREADS_PRIORITY_Lowest = 1; + public static readonly int BASSTM_THREADS_PRIORITY_Lower = 2; + public static readonly int BASSTM_THREADS_PRIORITY_Normal = 3; + public static readonly int BASSTM_THREADS_PRIORITY_Higher = 4; //* Default + public static readonly int BASSTM_THREADS_PRIORITY_Highest = 5; + public static readonly int BASSTM_THREADS_PRIORITY_TimeCritical = 6; + + //* .dll file name + public static readonly string FILENAME_DLL_BASS_THREADED_MIXER_LIBRARY = @"dll\BASSThreadedMixer.dll"; + //public static readonly int BASSARLIBCALL __stdcall + //public static readonly int GETBASSTMLIBFUNCTION(f) *((void**)&f) = GetProcAddress(BASSThreadedMixerLibraryDLLHandle, #f) + + + #region [DllImport] + [DllImport("kernel32", CharSet = CharSet.Unicode, SetLastError = true)] + internal static extern void FreeLibrary(IntPtr hModule); + + [DllImport("kernel32", CharSet = CharSet.Unicode, SetLastError = true)] + internal static extern IntPtr LoadLibrary(string lpFileName); + #endregion + + #region [ BASSThreadedMixer.dll インポート ] + //----------------- + [return: MarshalAs(UnmanagedType.U4)] + [DllImport("BASSThreadedMixer.dll", EntryPoint = "BASS_ThreadedMixer_Create", CallingConvention = CallingConvention.StdCall)] + public static extern Int32 BASS_ThreadedMixer_Create(Int32 Freq, Int32 Chans, Int32 Flags, out IntPtr ThreadedMixerHandle); + + [return: MarshalAs(UnmanagedType.Bool)] + [DllImport("BASSThreadedMixer.dll", EntryPoint = "BASS_ThreadedMixer_AddSource", CallingConvention = CallingConvention.StdCall)] + public static extern bool BASS_ThreadedMixer_AddSource(IntPtr ThreadedMixerHandle, Int32 SourceChannel, IntPtr Matrix); + [return: MarshalAs(UnmanagedType.Bool)] + [DllImport("BASSThreadedMixer.dll", EntryPoint = "BASS_ThreadedMixer_RemoveSource", CallingConvention = CallingConvention.StdCall)] + public static extern bool BASS_ThreadedMixer_RemoveSource(IntPtr ThreadedMixerHandle, Int32 SourceChannel); + [return: MarshalAs(UnmanagedType.Bool)] + [DllImport("BASSThreadedMixer.dll", EntryPoint = "BASS_ThreadedMixer_SetMatrix", CallingConvention = CallingConvention.StdCall)] + public static extern bool BASS_ThreadedMixer_SetMatrix(IntPtr ThreadedMixerHandle, Int32 SourceChannel, IntPtr Matrix, Single FadeTime); + [return: MarshalAs(UnmanagedType.Bool)] + [DllImport("BASSThreadedMixer.dll", EntryPoint = "BASS_ThreadedMixer_SetParameter", CallingConvention = CallingConvention.StdCall)] + public static extern bool BASS_ThreadedMixer_SetParameter(IntPtr ThreadedMixerHandle, Int32 Parameter, Int32 Value); + + //typedef DWORD(BASSARLIBCALL* t_BASS_ThreadedMixer_Create)(DWORD Freq, DWORD Chans, DWORD Flags, HBASSTM* ThreadedMixerHandle); + //typedef BOOL(BASSARLIBCALL* t_BASS_ThreadedMixer_AddSource)(HBASSTM ThreadedMixerHandle, DWORD SourceChannel, void* Matrix); + //typedef BOOL(BASSARLIBCALL* t_BASS_ThreadedMixer_RemoveSource)(HBASSTM ThreadedMixerHandle, DWORD SourceChannel); + //typedef BOOL(BASSARLIBCALL* t_BASS_ThreadedMixer_SetMatrix)(HBASSTM ThreadedMixerHandle, DWORD SourceChannel, void* Matrix, float FadeTime); + //typedef BOOL(BASSARLIBCALL* t_BASS_ThreadedMixer_SetParameter)(HBASSTM ThreadedMixerHandle, DWORD Parameter, int Value); + + //----------------- + #endregion + + + private static IntPtr BASSThreadedMixerLibraryDLLHandle; + + public static bool InitBASSThreadedMixerLibrary() + { + //#if _WIN32 + BASSThreadedMixerLibraryDLLHandle = LoadLibrary(FILENAME_DLL_BASS_THREADED_MIXER_LIBRARY); + //#else //* OSX + //BASSThreadedMixerLibraryDLLHandle = dlopen(FILENAME_DLL_BASS_THREADED_MIXER_LIBRARY, RTLD_NOW); + //#endif + + if (null != BASSThreadedMixerLibraryDLLHandle) + { + throw new Exception("BASSThreadedMixer.dllの組み込みに失敗しました。"); + + //GETBASSTMLIBFUNCTION(BASS_ThreadedMixer_Create); + //GETBASSTMLIBFUNCTION(BASS_ThreadedMixer_AddSource); + //GETBASSTMLIBFUNCTION(BASS_ThreadedMixer_RemoveSource); + //GETBASSTMLIBFUNCTION(BASS_ThreadedMixer_SetMatrix); + //GETBASSTMLIBFUNCTION(BASS_ThreadedMixer_SetParameter); + + //if ((NULL == BASS_ThreadedMixer_Create) + // || (NULL == BASS_ThreadedMixer_AddSource) + // || (NULL == BASS_ThreadedMixer_RemoveSource) + // || (NULL == BASS_ThreadedMixer_SetMatrix) + // || (NULL == BASS_ThreadedMixer_SetParameter) + // ) + //{ + // BASSThreadedMixerLibraryDLLLoaded = FALSE; + //} + //else + //{ + // BASSThreadedMixerLibraryDLLLoaded = TRUE; + //} + } + + return true; + } + + public static bool FreeBASSThreadedMixerLibrary() + { + if (null != BASSThreadedMixerLibraryDLLHandle) + { +//# ifdef _WIN32 + FreeLibrary(BASSThreadedMixerLibraryDLLHandle); +//#else //* OSX +// BASSThreadedMixerLibraryDLLLoaded = dlclose(BASSThreadedMixerLibraryDLLHandle); +//#endif + } + return true; + } + } +} diff --git a/FDK/コード/03.サウンド/CSound.cs b/FDK/コード/03.サウンド/CSound.cs index 413b9e1e..a1620f53 100644 --- a/FDK/コード/03.サウンド/CSound.cs +++ b/FDK/コード/03.サウンド/CSound.cs @@ -1771,19 +1771,19 @@ Debug.WriteLine("更に再生に失敗: " + Path.GetFileName(this.strファイ // ... と思ったが、1サウンド辺り1つのテンポ変更ストリームが存在することになり、 // ミキシング負荷が非常に高くなるため、結局TimeStretch=ONの時のみ店舗変更ストリームを提供することにした。 { - this._hTempoStream = BassFx.BASS_FX_TempoCreate( this._hBassStream, BASSFlag.BASS_STREAM_DECODE | BASSFlag.BASS_FX_FREESOURCE ); - if ( this._hTempoStream == 0 ) + this._hTempoStream = BassFx.BASS_FX_TempoCreate(this._hBassStream, BASSFlag.BASS_STREAM_DECODE | BASSFlag.BASS_FX_FREESOURCE); + if (this._hTempoStream == 0) { hGC.Free(); - throw new Exception( string.Format( "サウンドストリームの生成に失敗しました。(BASS_FX_TempoCreate)[{0}]", Bass.BASS_ErrorGetCode().ToString() ) ); + throw new Exception(string.Format("サウンドストリームの生成に失敗しました。(BASS_FX_TempoCreate)[{0}]", Bass.BASS_ErrorGetCode().ToString())); } else { - Bass.BASS_ChannelSetAttribute( this._hTempoStream, BASSAttribute.BASS_ATTRIB_TEMPO_OPTION_USE_QUICKALGO, 1f ); // 高速化(音の品質は少し落ちる) + Bass.BASS_ChannelSetAttribute(this._hTempoStream, BASSAttribute.BASS_ATTRIB_TEMPO_OPTION_USE_QUICKALGO, 1f); // 高速化(音の品質は少し落ちる) } } - if ( _hTempoStream != 0 && !this.bIs1倍速再生 ) // 再生速度がx1.000のときは、TempoStreamを用いないようにして高速化する + if (_hTempoStream != 0 && !this.bIs1倍速再生) // 再生速度がx1.000のときは、TempoStreamを用いないようにして高速化する { this.hBassStream = _hTempoStream; } @@ -1791,7 +1791,6 @@ Debug.WriteLine("更に再生に失敗: " + Path.GetFileName(this.strファイ { this.hBassStream = _hBassStream; } - // #32248 再生終了時に発火するcallbackを登録する (演奏終了後に再生終了するチップを非同期的にミキサーから削除するため。) _cbEndofStream = new SYNCPROC( CallbackEndofStream ); Bass.BASS_ChannelSetSync( hBassStream, BASSSync.BASS_SYNC_END | BASSSync.BASS_SYNC_MIXTIME, 0, _cbEndofStream, IntPtr.Zero ); @@ -1853,7 +1852,9 @@ Debug.WriteLine("更に再生に失敗: " + Path.GetFileName(this.strファイ } public bool tBASSサウンドをミキサーから削除する( int channel ) { - bool b = BassMix.BASS_Mixer_ChannelRemove( channel ); +//bool b = BASSThreadedMixerLibraryWrapper.BASS_ThreadedMixer_RemoveSource((IntPtr)this.hMixer, channel ); +//mixingChannel.Remove((IntPtr)this.hMixer); + bool b = BassMix.BASS_Mixer_ChannelRemove(channel); if ( b ) { Interlocked.Decrement( ref CSound管理.nMixing ); @@ -1863,10 +1864,13 @@ Debug.WriteLine("更に再生に失敗: " + Path.GetFileName(this.strファイ } -// mixer への追加 - + // mixer への追加 + +//private List mixingChannel = new List(); + public bool tBASSサウンドをミキサーに追加する() { +//if (!mixingChannel.Contains((IntPtr)this.hMixer)) if ( BassMix.BASS_Mixer_ChannelGetMixer( hBassStream ) == 0 ) { BASSFlag bf = BASSFlag.BASS_SPEAKER_FRONT | BASSFlag.BASS_MIXER_NORAMPIN | BASSFlag.BASS_MIXER_PAUSE; @@ -1875,7 +1879,9 @@ Debug.WriteLine("更に再生に失敗: " + Path.GetFileName(this.strファイ // preloadされることを期待して、敢えてflagからはBASS_MIXER_PAUSEを外してAddChannelした上で、すぐにPAUSEする // -> ChannelUpdateでprebufferできることが分かったため、BASS_MIXER_PAUSEを使用することにした - bool b1 = BassMix.BASS_Mixer_StreamAddChannel( this.hMixer, this.hBassStream, bf ); +//bool b1 = BASSThreadedMixerLibraryWrapper.BASS_ThreadedMixer_AddSource( (IntPtr)this.hMixer, this.hBassStream, IntPtr.Zero ); +//mixingChannel.Add((IntPtr)this.hMixer); + bool b1 = BassMix.BASS_Mixer_StreamAddChannel(this.hMixer, this.hBassStream, bf); //bool b2 = BassMix.BASS_Mixer_ChannelPause( this.hBassStream ); t再生位置を先頭に戻す(); // StreamAddChannelの後で再生位置を戻さないとダメ。逆だと再生位置が変わらない。 //Trace.TraceInformation( "Add Mixer: " + Path.GetFileName( this.strファイル名 ) + " (" + hBassStream + ")" + " MixedStreams=" + CSound管理.nMixing ); diff --git a/FDK/コード/03.サウンド/CSoundDeviceWASAPI.cs b/FDK/コード/03.サウンド/CSoundDeviceWASAPI.cs index ab91ed1d..74028462 100644 --- a/FDK/コード/03.サウンド/CSoundDeviceWASAPI.cs +++ b/FDK/コード/03.サウンド/CSoundDeviceWASAPI.cs @@ -436,6 +436,8 @@ Trace.TraceInformation("WASAPI Device #{0}: {1}: IsDefault={2}, defPeriod={3}s, #endregion } +//LoadLibraryに失敗する・・・ +//BASSThreadedMixerLibraryWrapper.InitBASSThreadedMixerLibrary(); @@ -446,10 +448,17 @@ Trace.TraceInformation("WASAPI Device #{0}: {1}: IsDefault={2}, defPeriod={3}s, // string.Format( "BASS_SetConfig(CONFIG_MIXER_BUFFER) に失敗しました。[{0}", Bass.BASS_ErrorGetCode() ) ); var info = BassWasapi.BASS_WASAPI_GetInfo(); +//this.hMixer = BASSThreadedMixerLibraryWrapper.BASS_ThreadedMixer_Create( +// info.freq, +// info.chans, +// (int)(BASSFlag.BASS_MIXER_NONSTOP | BASSFlag.BASS_SAMPLE_FLOAT | BASSFlag.BASS_STREAM_DECODE | BASSFlag.BASS_MIXER_POSEX), +// out hMixerThreaded +// ); + this.hMixer = BassMix.BASS_Mixer_StreamCreate( info.freq, info.chans, - BASSFlag.BASS_MIXER_NONSTOP | BASSFlag.BASS_SAMPLE_FLOAT | BASSFlag.BASS_STREAM_DECODE | BASSFlag.BASS_MIXER_POSEX ); // デコードのみ=発声しない。WASAPIに出力されるだけ。 + BASSFlag.BASS_MIXER_NONSTOP | BASSFlag.BASS_SAMPLE_FLOAT | BASSFlag.BASS_STREAM_DECODE | BASSFlag.BASS_MIXER_POSEX); // デコードのみ=発声しない。WASAPIに出力されるだけ。 if ( this.hMixer == 0 ) { BASSError errcode = Bass.BASS_ErrorGetCode(); @@ -462,6 +471,12 @@ Trace.TraceInformation("WASAPI Device #{0}: {1}: IsDefault={2}, defPeriod={3}s, for (int i = 0; i <= (int)CSound.EInstType.Unknown; i++) { +//this.hMixer_Chips[i] = BASSThreadedMixerLibraryWrapper.BASS_ThreadedMixer_Create( +// info.freq, +// info.chans, +// (int)(BASSFlag.BASS_MIXER_NONSTOP | BASSFlag.BASS_SAMPLE_FLOAT | BASSFlag.BASS_STREAM_DECODE | BASSFlag.BASS_MIXER_POSEX), +// out this.hMixerThreaded_Chips[i] +//); // デコードのみ=発声しない。WASAPIに出力されるだけ。 this.hMixer_Chips[ i ] = BassMix.BASS_Mixer_StreamCreate( info.freq, info.chans, @@ -476,9 +491,10 @@ Trace.TraceInformation("WASAPI Device #{0}: {1}: IsDefault={2}, defPeriod={3}s, } // Mixerのボリューム設定 - Bass.BASS_ChannelSetAttribute(this.hMixer_Chips[ i ], BASSAttribute.BASS_ATTRIB_VOL, CSound管理.nMixerVolume[ i ] / 100.0f ); -//Trace.TraceInformation("Vol{0}: {1}", i, CSound管理.nMixerVolume[i]); + Bass.BASS_ChannelSetAttribute(this.hMixer_Chips[i], BASSAttribute.BASS_ATTRIB_VOL, CSound管理.nMixerVolume[i] / 100.0f); + //Trace.TraceInformation("Vol{0}: {1}", i, CSound管理.nMixerVolume[i]); +//bool b1 = BASSThreadedMixerLibraryWrapper.BASS_ThreadedMixer_AddSource(this.hMixerThreaded, this.hMixer_Chips[i], IntPtr.Zero); bool b1 = BassMix.BASS_Mixer_StreamAddChannel(this.hMixer, this.hMixer_Chips[i], BASSFlag.BASS_DEFAULT); if (!b1) { @@ -601,7 +617,8 @@ Trace.TraceInformation("WASAPI Device #{0}: {1}: IsDefault={2}, defPeriod={3}s, public CSound tサウンドを作成する( string strファイル名, CSound.EInstType eInstType ) { var sound = new CSound(); - int hmixer = hMixer_Chips[ (int)eInstType ]; +//int hmixer = (int)hMixerThreaded_Chips[ (int)eInstType ]; + int hmixer = hMixer_Chips[(int)eInstType]; sound.tWASAPIサウンドを作成する( strファイル名, hmixer, this.e出力デバイス, eInstType ); return sound; } @@ -612,17 +629,20 @@ Trace.TraceInformation("WASAPI Device #{0}: {1}: IsDefault={2}, defPeriod={3}s, public CSound tサウンドを作成する( byte[] byArrWAVファイルイメージ, CSound.EInstType eInstType ) { var sound = new CSound(); +//int hmixer = (int)hMixerThreaded_Chips[(int)eInstType]; int hmixer = hMixer_Chips[(int)eInstType]; sound.tWASAPIサウンドを作成する( byArrWAVファイルイメージ, hmixer, this.e出力デバイス, eInstType ); return sound; } public void tサウンドを作成する( string strファイル名, ref CSound sound, CSound.EInstType eInstType ) { +//int hmixer = (int)hMixerThreaded_Chips[(int)eInstType]; int hmixer = hMixer_Chips[(int)eInstType]; sound.tWASAPIサウンドを作成する( strファイル名, hmixer, this.e出力デバイス, eInstType ); } public void tサウンドを作成する( byte[] byArrWAVファイルイメージ, ref CSound sound, CSound.EInstType eInstType) { +//int hmixer = (int)hMixerThreaded_Chips[(int)eInstType]; int hmixer = hMixer_Chips[(int)eInstType]; sound.tWASAPIサウンドを作成する( byArrWAVファイルイメージ, hmixer, this.e出力デバイス, eInstType ); } @@ -677,6 +697,7 @@ Trace.TraceInformation("WASAPI Device #{0}: {1}: IsDefault={2}, defPeriod={3}s, } } } +//BASSThreadedMixerLibraryWrapper.FreeBASSThreadedMixerLibrary(); if ( !this.bIsBASSFree ) { @@ -701,6 +722,9 @@ Trace.TraceInformation("WASAPI Device #{0}: {1}: IsDefault={2}, defPeriod={3}s, protected int hMixer_Record = 0; protected int[] hMixer_Chips = new int[(int)CSound.EInstType.Unknown + 1]; //DTX2WAV対応 BGM, SE, Drums...を別々のmixerに入れて、個別に音量変更できるようにする +//protected IntPtr hMixerThreaded = IntPtr.Zero; +//protected IntPtr[] hMixerThreaded_Chips = new IntPtr[(int)CSound.EInstType.Unknown + 1]; + protected BaseEncoder encoder; protected int stream; protected WASAPIPROC tWasapiProc = null; @@ -709,7 +733,8 @@ Trace.TraceInformation("WASAPI Device #{0}: {1}: IsDefault={2}, defPeriod={3}s, { // BASSミキサからの出力データをそのまま WASAPI buffer へ丸投げ。 - int num = Bass.BASS_ChannelGetData( this.hMixer_DeviceOut, buffer, length ); // num = 実際に転送した長さ + int num = Bass.BASS_ChannelGetData( this.hMixer_DeviceOut, buffer, length ); // num = 実際に転送した長さ + //int num = BassMix.BASS_Mixer_ChannelGetData(this.hMixer_DeviceOut, buffer, length); // これだと動作がめちゃくちゃ重くなる if ( num == -1 ) num = 0;