OSDN Git Service

CSCore の高レベルAPIを使って WASAPI 名前空間を再実装。ただし音量が大きいと音割れする。
authorくまかみ工房 <kumakamikoubou@gmail.com>
Wed, 16 Nov 2016 15:25:34 +0000 (00:25 +0900)
committerくまかみ工房 <kumakamikoubou@gmail.com>
Wed, 16 Nov 2016 15:25:34 +0000 (00:25 +0900)
15 files changed:
FDK24/FDK24.csproj
FDK24/メディア/サウンド/WASAPI/Decoder.cs
FDK24/メディア/サウンド/WASAPI/Device.cs
FDK24/メディア/サウンド/WASAPI/Mixer.cs
FDK24/メディア/サウンド/WASAPI/Sound.cs
FDK24/メディア/サウンド/WASAPI/SoundTimer.cs
FDK24/メディア/サウンド/WASAPIold/Device.cs [deleted file]
FDK24/メディア/サウンド/WASAPIold/MFAsyncCallback.cs [deleted file]
FDK24/メディア/サウンド/WASAPIold/Mixer.cs [deleted file]
FDK24/メディア/サウンド/WASAPIold/Sound.cs [deleted file]
FDK24/メディア/サウンド/WASAPIold/SoundTimer.cs [deleted file]
StrokeStyleT/StrokeStyleT.cs
StrokeStyleT/ステージ/曲読込/曲読込ステージ.cs
StrokeStyleT/ステージ/演奏/ドラムサウンド.cs
StrokeStyleT/ステージ/演奏/演奏ステージ.cs

index ada5180..203ef3d 100644 (file)
     <Compile Include="メディア\画像.cs" />
     <Compile Include="メディア\画像フォント.cs" />
     <Compile Include="メディア\矩形リスト.cs" />
-    <Compile Include="メディア\サウンド\WASAPIold\Device.cs" />
-    <Compile Include="メディア\サウンド\WASAPIold\MFAsyncCallback.cs" />
-    <Compile Include="メディア\サウンド\WASAPIold\Mixer.cs" />
-    <Compile Include="メディア\サウンド\WASAPIold\Sound.cs" />
-    <Compile Include="メディア\サウンド\WASAPIold\SoundTimer.cs" />
     <Compile Include="メディア\テクスチャ.cs" />
     <Compile Include="メディア\デバイスリソース.cs" />
     <Compile Include="入力\IInputDevice.cs" />
index 8a4bdb2..2041d06 100644 (file)
@@ -33,7 +33,7 @@ namespace FDK.メディア.サウンド.WASAPI
                        get { return this._Position; }
                        set
                        {
-                               if( ( 0 > value ) || ( this.Length <= value ) )
+                               if( ( 0 > value ) || ( ( this.Length > 0 ) && ( this.Length <= value ) ) )      // Length == 0 なら例外は出さない
                                        throw new ArgumentOutOfRangeException();
 
                                this._Position = value;
@@ -136,30 +136,26 @@ namespace FDK.メディア.サウンド.WASAPI
                                        //----------------
                                        using( var partialMediaType = new SharpDX.MediaFoundation.MediaType() )
                                        {
-                                               // 部分メディアタイプを作成し、オーディオフォーマットを設定する。 (オーディオフォーマットは IEEE FLOAT で固定。)
+                                               // 部分メディアタイプを作成し、オーディオフォーマットを設定する。
                                                partialMediaType.Set<Guid>( SharpDX.MediaFoundation.MediaTypeAttributeKeys.MajorType, SharpDX.MediaFoundation.MediaTypeGuids.Audio );
                                                partialMediaType.Set<Guid>( SharpDX.MediaFoundation.MediaTypeAttributeKeys.Subtype, SharpDX.MediaFoundation.AudioFormatGuids.Float );
                                                partialMediaType.Set<int>( SharpDX.MediaFoundation.MediaTypeAttributeKeys.AudioNumChannels, this.WaveFormat.Channels );
                                                partialMediaType.Set<int>( SharpDX.MediaFoundation.MediaTypeAttributeKeys.AudioSamplesPerSecond, this.WaveFormat.SampleRate );
-                                               partialMediaType.Set<int>( SharpDX.MediaFoundation.MediaTypeAttributeKeys.AudioBlockAlignment, this.WaveFormat.BlockAlign );
-                                               partialMediaType.Set<int>( SharpDX.MediaFoundation.MediaTypeAttributeKeys.AudioAvgBytesPerSecond, this.WaveFormat.BytesPerSecond );
-                                               partialMediaType.Set<int>( SharpDX.MediaFoundation.MediaTypeAttributeKeys.AudioBitsPerSample, this.WaveFormat.BitsPerSample );
+                                               partialMediaType.Set<int>( SharpDX.MediaFoundation.MediaTypeAttributeKeys.AudioBitsPerSample, 32 );
+                                               //partialMediaType.Set<int>( SharpDX.MediaFoundation.MediaTypeAttributeKeys.AudioAvgBytesPerSecond, this.WaveFormat.BytesPerSecond );
+                                               //partialMediaType.Set<int>( SharpDX.MediaFoundation.MediaTypeAttributeKeys.AudioBlockAlignment, this.WaveFormat.BlockAlign );
                                                partialMediaType.Set<int>( SharpDX.MediaFoundation.MediaTypeAttributeKeys.AllSamplesIndependent, 1 ); // TRUE
 
-                                               if( this.WaveFormat.WaveFormatTag == AudioEncoding.Extensible )
-                                               {
-                                                       var wfmEx = this.WaveFormat as CSCore.WaveFormatExtensible;
-                                                       partialMediaType.Set<int>( SharpDX.MediaFoundation.MediaTypeAttributeKeys.AudioChannelMask, (int) wfmEx.ChannelMask );
-                                                       partialMediaType.Set<int>( SharpDX.MediaFoundation.MediaTypeAttributeKeys.AudioSamplesPerBlock, wfmEx.SamplesPerBlock );
-                                                       partialMediaType.Set<int>( SharpDX.MediaFoundation.MediaTypeAttributeKeys.AudioValidBitsPerSample, wfmEx.ValidBitsPerSample );
-                                               }
-
                                                // 作成したメディアタイプを sourceReader にセットする。必要なデコーダが見つからなかったら、ここで例外が発生する。
                                                sourceReader.SetCurrentMediaType( SharpDX.MediaFoundation.SourceReaderIndex.FirstAudioStream, partialMediaType );
 
                                                // 完成されたメディアタイプを取得する。
                                                this._MediaType = sourceReader.GetCurrentMediaType( SharpDX.MediaFoundation.SourceReaderIndex.FirstAudioStream );
 
+                                               int wfsize;
+                                               var wfx = this._MediaType.ExtracttWaveFormat( out wfsize );
+                                               this.WaveFormat = new CSCore.WaveFormat( wfx.SampleRate, wfx.BitsPerSample, wfx.Channels, AudioEncoding.IeeeFloat );
+
                                                // 最初のオーディオストリームが選択されていることを保証する。
                                                sourceReader.SetStreamSelection( SharpDX.MediaFoundation.SourceReaderIndex.FirstAudioStream, true );
                                        }
@@ -213,8 +209,9 @@ namespace FDK.メディア.サウンド.WASAPI
                                        #endregion
                                }
                        }
-                       catch
+                       catch( Exception e )
                        {
+                               FDK.Log.ERROR( $"WASAPI.Decoder の初期化に失敗しました。[{e.Message}]" );
                                this._EncodedWaveData = new byte[] { };
                        }
 
index d52c120..2801c46 100644 (file)
@@ -72,11 +72,39 @@ namespace FDK.メディア.サウンド.WASAPI
                /// <summary>
                ///             現在のデバイス位置を取得する。
                /// </summary>
-               public void GetClock( out long Pu64Position, out long QPCPosition )
+               public void GetClock( out long Pu64Position, out long QPCPosition, out long Pu64Frequency )
                {
-                       lock( this._スレッド間同期 )
+                       //lock( this._スレッド間同期 )   なくてもいいっぽい。
                        {
-                               this._AudioClock.GetPositionNative( out Pu64Position, out QPCPosition );
+                               this._AudioClock.GetFrequencyNative( out Pu64Frequency );
+
+                               // IAudioClock::GetPosition() は、S_FALSE を返すことがある。
+                               // これは、WASAPI排他モードにおいて、GetPosition 時に優先度の高いイベントが発生しており
+                               // 既定時間内にデバイス位置を取得できなかった場合に返される。(MSDNより)
+
+                               int hr = 0;
+                               long pos = 0;
+                               long qpcPos = 0;
+                               for( int リトライ回数 = 0; リトライ回数 < 10; リトライ回数++ )    // 最大10回までリトライ。
+                               {
+                                       hr = this._AudioClock.GetPositionNative( out pos, out qpcPos );
+
+                                       if( ( (int) CSCore.Win32.HResult.S_OK ) == hr )
+                                       {
+                                               break;      // OK
+                                       }
+                                       else if( ( (int) CSCore.Win32.HResult.S_FALSE ) == hr )
+                                       {
+                                               continue;   // リトライ
+                                       }
+                                       else
+                                       {
+                                               throw new CSCore.Win32.Win32ComException( hr, "IAudioClock", "GetPosition" );
+                                       }
+                               }
+
+                               Pu64Position = pos;
+                               QPCPosition = qpcPos;
                        }
                }
 
@@ -268,11 +296,7 @@ namespace FDK.メディア.サウンド.WASAPI
                                this._AudioClient = CSCore.CoreAudioAPI.AudioClient.FromMMDevice( this._MMDevice );
 
                                // フォーマットを決定する。
-                               var defaultFormat = ( this._共有モード == CSCore.CoreAudioAPI.AudioClientShareMode.Shared ) ?
-                                       this._AudioClient.GetMixFormat() :
-                                       new CSCore.WaveFormat( 48000, 32, 2, AudioEncoding.IeeeFloat );
-
-                               if( null == ( this._WaveFormat = this._適切なフォーマットを調べて返す( 希望フォーマット ?? defaultFormat ) ) )
+                               if( null == ( this._WaveFormat = this._適切なフォーマットを調べて返す( 希望フォーマット ?? this._AudioClient.GetMixFormat() ) ) )
                                {
                                        throw new NotSupportedException( "サポート可能な WaveFormat が見つかりませんでした。" );
                                }
@@ -318,7 +342,7 @@ namespace FDK.メディア.サウンド.WASAPI
 
                                // ミキサーを生成し、デバイスのソース(DirectSound でいうところのプライマリバッファ)として登録する。
                                this._Mixer = new Mixer( this._WaveFormat ) {
-                                       DivideResult = false,
+                                       DivideResult = false,   // BGMのような長い音にドラムのような短い音が入るとBGMの音量がコロコロ変わってしまうので、このオプションは false で固定。
                                };
                                this._SetSource( this._Mixer );
                        }
@@ -354,8 +378,8 @@ namespace FDK.メディア.サウンド.WASAPI
                        if( null != this._レンダリング先 )
                                throw new InvalidOperationException( "レンダリングターゲットはすでに設定済みです。" );
 
-                       this._レンダリング先 = new CSCore.Streams.VolumeSource( targetSource );  // サンプル(float)単位のレンダリング先と、
-                       this._生レンダリング先 = targetSource.ToWaveSource();                                           // データ(byte)単位のレンダリング先とを持っておく。
+                       this._レンダリング先 = new CSCore.Streams.VolumeSource( targetSource );  // サンプル単位のレンダリング先と、
+                       this._生レンダリング先 = targetSource.ToWaveSource( targetSource.WaveFormat.BitsPerSample );    // データ(byte)単位のレンダリング先とを持っておく。
                }
 
                /// <summary>
@@ -395,13 +419,12 @@ namespace FDK.メディア.サウンド.WASAPI
                                {
                                        // (D) AudioClient が共有モードのフォーマットすらNGと言ってきた場合は、以下から探す。
 
-                                       最終的に決定されたフォーマット = new[]
-                                       {
-                                                       new CSCore.WaveFormatExtensible( waveFormat.SampleRate, 32, waveFormat.Channels, CSCore.AudioSubTypes.IeeeFloat ),
-                                                       new CSCore.WaveFormatExtensible( waveFormat.SampleRate, 24, waveFormat.Channels, CSCore.AudioSubTypes.Pcm ),
-                                                       new CSCore.WaveFormatExtensible( waveFormat.SampleRate, 16, waveFormat.Channels, CSCore.AudioSubTypes.Pcm ),
-                                                       new CSCore.WaveFormatExtensible( waveFormat.SampleRate,  8, waveFormat.Channels, CSCore.AudioSubTypes.Pcm ),
-                                               }
+                                       最終的に決定されたフォーマット = new[] {
+                                               new CSCore.WaveFormat( waveFormat.SampleRate, 16, waveFormat.Channels, AudioEncoding.Pcm ),
+                                               new CSCore.WaveFormat( waveFormat.SampleRate, 24, waveFormat.Channels, AudioEncoding.Pcm ),
+                                               new CSCore.WaveFormat( waveFormat.SampleRate,  8, waveFormat.Channels, AudioEncoding.Pcm ),
+                                               new CSCore.WaveFormat( waveFormat.SampleRate, 32, waveFormat.Channels, AudioEncoding.IeeeFloat ),
+                                       }
                                        .FirstOrDefault( ( format ) => ( this._AudioClient.IsFormatSupported( this._共有モード, format ) ) );
 
                                        // (E) それでも見つからなかったら null 。
@@ -484,6 +507,7 @@ namespace FDK.メディア.サウンド.WASAPI
                        }
                        catch( Exception e )
                        {
+                               FDK.Log.ERROR( $"例外が発生しました。レンダリングスレッドを中断します。[{e.Message}]" );
                                例外 = e;
                        }
                        finally
index d0e6331..d79ec38 100644 (file)
@@ -154,7 +154,7 @@ namespace FDK.メディア.サウンド.WASAPI
                                                // DiviveResult 用。
                                                var サウンド別読み出し数 = new List<int>( this._Sounds.Count );
 
-                                               // ミキサに登録されているすべての Sound について……(逆順
+                                               // ミキサに登録されているすべての Sound について……(リストから Remove する場合があるので、逆順に。
                                                for( int m = this._Sounds.Count - 1; m >= 0; m-- )
                                                {
                                                        var sound = this._Sounds[ m ];
@@ -169,7 +169,8 @@ namespace FDK.メディア.サウンド.WASAPI
                                                                        * sound.Volume                  // 個別音量
                                                                        * this._Volume;                 // ミキサ音量
 
-                                                               バッファ[ i ] += data;  // ベースに無音を出力済みなので、上書きじゃなく常に加算。
+                                                               // ベースに無音を出力済みなので、上書きじゃなく常に加算。
+                                                               バッファ[ i ] += data;
                                                        }
 
                                                        if( 0 < 受け取ったサンプル数 )
index d74cb37..e4464bd 100644 (file)
@@ -15,7 +15,7 @@ namespace FDK.メディア.サウンド.WASAPI
 
                public double 長さsec
                {
-                       get { return this.長さsample / ( this.WaveFormat.Channels * this.WaveFormat.SampleRate ); }
+                       get { return this._SampleToSec( this.長さsample ); }
                }
 
                public long 位置sample
@@ -28,14 +28,13 @@ namespace FDK.メディア.サウンド.WASAPI
                {
                        get
                        {
-                               return this.位置sample / ( this.WaveFormat.Channels * this.WaveFormat.SampleRate );
+                               return this._SampleToSec( this.位置sample );
                        }
                        set
                        {
-                               long position = (long) ( value * this.WaveFormat.SampleRate * this.WaveFormat.Channels + 0.5 ); // +0.5 は四捨五入
-                               position -= ( position % this.WaveFormat.Channels );    // チャンネル数の倍数にする。
+                               long position = this._SecToSample( value );
 
-                               if( ( 0 > position ) || ( this.長さsample <= position ) )
+                               if( ( 0 > position ) || ( ( this.長さsample > 0 ) && ( this.長さsample <= position ) ) )            // 長さsample == 0 では例外は出さない
                                        throw new ArgumentOutOfRangeException();
 
                                this.位置sample = position;
@@ -89,13 +88,20 @@ namespace FDK.メディア.サウンド.WASAPI
                        this._MixerRef = null;
                }
 
-               public void Play()
+               public void Play( long 再生開始位置sample = 0 )
                {
+                       this.位置sample = 再生開始位置sample;
+
                        Mixer mixer;
                        if( this._MixerRef.TryGetTarget( out mixer ) )
                                mixer.AddSound( this );
                }
 
+               public void Play( double 再生開始位置sec )
+               {
+                       this.Play( this._SecToSample( 再生開始位置sec ) );
+               }
+
                public void Stop()
                {
                        Mixer mixer;
@@ -107,5 +113,18 @@ namespace FDK.メディア.サウンド.WASAPI
                private CSCore.ISampleSource _SampleSource = null;
                private System.WeakReference<Mixer> _MixerRef = null;
                private float _Volume = 1.0f;
+
+               private long _SecToSample( double 時間sec )
+               {
+                       long 時間sample = (long) ( 時間sec * this.WaveFormat.SampleRate * this.WaveFormat.Channels + 0.5 ); // +0.5 は四捨五入
+                       時間sample -= ( 時間sample % this.WaveFormat.Channels );    // チャンネル数の倍数にする。
+
+                       return 時間sample;
+               }
+
+               private double _SampleToSec( long 時間sample )
+               {
+                       return 時間sample / ( this.WaveFormat.Channels * this.WaveFormat.SampleRate );
+               }
        }
 }
index d6a1202..da29c5c 100644 (file)
@@ -15,56 +15,19 @@ namespace FDK.メディア.サウンド.WASAPI
        public class SoundTimer
        {
                /// <returns>エラー時は double.NaN を返す。</returns>
-               public double 現在のデバイス位置secを取得する( CSCore.CoreAudioAPI.AudioClock audioClock )
+               public double 現在のデバイス位置secを取得する( long position, long qpcPosition, long frequency )
                {
                        lock( this._スレッド間同期 )
                        {
-                               int hr = 0;
-
-                               long デバイス周波数 = 0;
-                               //デバイス周波数 = audioClock.Pu64Frequency; --> Native 系で統一するため、こちらは使わない。
-                               audioClock.GetFrequencyNative( out デバイス周波数 );
-
-                               long QPC周波数 = FDK.カウンタ.QPCTimer.周波数;
-                               long デバイス位置 = 0;
-                               long デバイス位置取得時のパフォーマンスカウンタを100ns単位に変換した時間 = 0;
+                               long デバイス周波数 = frequency;
+                               long デバイス位置 = position;
+                               //long デバイス位置取得時のパフォーマンスカウンタを100ns単位に変換した時間 = qpcPosition;
+                               //long QPC周波数 = FDK.カウンタ.QPCTimer.周波数;
 
                                if( 0.0 >= デバイス周波数 )
                                        return double.NaN;
 
-                               // IAudioClock::GetPosition() は、S_FALSE を返すことがある。
-                               // これは、WASAPI排他モードにおいて、GetPosition 時に優先度の高いイベントが発生しており
-                               // 既定時間内にデバイス位置を取得できなかった場合に返される。(MSDNより)
-                               for( int リトライ回数 = 0; リトライ回数 < 10; リトライ回数++ )    // 最大10回までリトライ。
-                               {
-                                       hr = audioClock.GetPositionNative( out デバイス位置, out デバイス位置取得時のパフォーマンスカウンタを100ns単位に変換した時間 );
-
-                                       if( ( (int) CSCore.Win32.HResult.S_OK ) == hr )
-                                       {
-                                               break;      // OK
-                                       }
-                                       else if( ( (int) CSCore.Win32.HResult.S_FALSE ) == hr )
-                                       {
-                                               continue;   // リトライ
-                                       }
-                                       else
-                                       {
-                                               throw new CSCore.Win32.Win32ComException( hr, "IAudioClock", "GetPosition" );
-                                       }
-                               }
-                               if( ( (int) CSCore.Win32.HResult.S_FALSE ) == hr )
-                               {
-                                       // 全部リトライしてもまだダメならエラー。
-                                       return double.NaN;
-                               }
-
-                               // デバイス位置は、GetPosition() で取得した瞬間からここに至るまでに、既にいくらか進んでいる。
-                               // そこで、この時点で最新のパフォーマンスカウンタを取得し、時間の増加分をデバイス位置に加えて精度を上げる。(MSDNより)
-                               double QPCから調べた差分sec =
-                                       ( (double) FDK.カウンタ.QPCTimer.生カウント / QPC周波数 ) -
-                                       FDK.Utilities.変換_100ns単位からsec単位へ( デバイス位置取得時のパフォーマンスカウンタを100ns単位に変換した時間 );
-
-                               return ( ( (double) デバイス位置 ) / デバイス周波数 ) + QPCから調べた差分sec;
+                               return (double) デバイス位置 / デバイス周波数;
                        }
                }
 
diff --git a/FDK24/メディア/サウンド/WASAPIold/Device.cs b/FDK24/メディア/サウンド/WASAPIold/Device.cs
deleted file mode 100644 (file)
index 88f8823..0000000
+++ /dev/null
@@ -1,360 +0,0 @@
-using System;
-using System.Diagnostics;
-
-namespace FDK.メディア.サウンド.WASAPIold
-{
-       public unsafe class Device : IDisposable
-       {
-               public double 遅延sec
-               {
-                       get { return ( this.更新間隔sec * 1000.0 ); }
-               }
-               public CSCore.CoreAudioAPI.AudioClock AudioClock
-               {
-                       get { return this.bs_AudioClock; }
-               }
-               public bool Dispose済み
-               {
-                       get;
-                       protected set;
-               } = true;
-
-               public void 初期化する( CSCore.CoreAudioAPI.AudioClientShareMode 共有モード, double 希望更新間隔sec = 0.015 )
-               {
-                       FDK.Log.BeginInfo( $"{FDK.Utilities.現在のメソッド名}" );
-
-                       int hr = 0;
-
-                       lock( this.スレッド間同期 )
-                       {
-                               Trace.Assert( this.Dispose済み );
-                               this.Dispose済み = false;
-
-                               this.共有モード = 共有モード;
-
-                               #region " AudioClientをアクティベートする。"
-                               //-----------------
-                               using( var devices = new CSCore.CoreAudioAPI.MMDeviceEnumerator() )
-                               using( var 既定のデバイス = devices.GetDefaultAudioEndpoint( CSCore.CoreAudioAPI.DataFlow.Render, CSCore.CoreAudioAPI.Role.Console ) )
-                               {
-                                       this.AudioClient = CSCore.CoreAudioAPI.AudioClient.FromMMDevice( 既定のデバイス );
-                               }
-                               //-----------------
-                               #endregion
-                               #region " 指定された希望更新間隔とデバイス能力をもとに、更新間隔を決定する。"
-                               //-----------------
-                               long 共有モードでの間隔100ns = 0;
-                               long 排他モードでの最小間隔100ns = 0;
-
-                               // デバイスから間隔値を取得する。
-                               hr = this.AudioClient.GetDevicePeriodNative( out 共有モードでの間隔100ns, out 排他モードでの最小間隔100ns );
-                               if( 0 > hr )
-                                       System.Runtime.InteropServices.Marshal.ThrowExceptionForHR( hr );
-
-                               if( 共有モード == CSCore.CoreAudioAPI.AudioClientShareMode.Shared )
-                               {
-                                       this.更新間隔100ns = 共有モードでの間隔100ns;
-                               }
-                               else
-                               {
-                                       this.更新間隔100ns = Math.Max( FDK.Utilities.変換_sec単位から100ns単位へ( 希望更新間隔sec ), 排他モードでの最小間隔100ns );
-                               }
-                               //-----------------
-                               #endregion
-                               #region " デバイスフォーマットを決定する。"
-                               //----------------
-                               if( this.共有モード == CSCore.CoreAudioAPI.AudioClientShareMode.Shared )
-                               {
-                                       this.WaveFormat = this.AudioClient.GetMixFormat();
-                               }
-                               else
-                               {
-                                       this.WaveFormat = new CSCore.WaveFormat( 44100, 16, 2, CSCore.AudioEncoding.Pcm );
-                               }
-                               //----------------
-                               #endregion
-                               #region " AudioClient を初期化する。"
-                               //-----------------
-                               try
-                               {
-                                       this.AudioClient.Initialize(
-                                               this.共有モード,
-                                               CSCore.CoreAudioAPI.AudioClientStreamFlags.StreamFlagsEventCallback,
-                                               // | CSCore.CoreAudioAPI.AudioClientStreamFlags.StreamFlagsNoPersist,   // 音量とミュートを記憶しない → 無効。してください
-                                               this.更新間隔100ns,
-                                               this.更新間隔100ns,
-                                               this.WaveFormat,
-                                               Guid.Empty );   // この AudioClient (= AudioStrem) が所属する AudioSession。null ならデフォルトのAudioSessionに登録される。
-                               }
-                               catch( CSCore.CoreAudioAPI.CoreAudioAPIException e )
-                               {
-                                       if( AUDCLNT_E_BUFFER_SIZE_NOT_ALIGNED == e.ErrorCode )
-                                       {
-                                               #region " 排他&イベント駆動モードの場合、バッファサイズアライメントエラーが返される場合がある。この場合、サイズを調整してオーディオストリームを作成し直す。"
-                                               //----------------
-                                               this.更新間隔100ns = FDK.Utilities.変換_sec単位から100ns単位へ(
-                                                       (double) this.AudioClient.GetBufferSize() / (double) this.WaveFormat.SampleRate );   // GetBufferSize は、更新間隔に一番近い、アライメントされたバッファサイズ(sample単位)を返す。
-
-                                               // AudioClient を一度解放し、もう一度アクティベートし直す。
-                                               this.AudioClient.Dispose();
-                                               using( var devices = new CSCore.CoreAudioAPI.MMDeviceEnumerator() )
-                                               using( var 既定のデバイス = devices.GetDefaultAudioEndpoint( CSCore.CoreAudioAPI.DataFlow.Render, CSCore.CoreAudioAPI.Role.Console ) )
-                                               {
-                                                       this.AudioClient = CSCore.CoreAudioAPI.AudioClient.FromMMDevice( 既定のデバイス );
-                                               }
-
-                                               // アライメントされたサイズを使って、AudioClient を再初期化する。それでもエラーなら例外発出。
-                                               this.AudioClient.Initialize(
-                                                       this.共有モード,
-                                                       CSCore.CoreAudioAPI.AudioClientStreamFlags.StreamFlagsEventCallback,
-                                                       // | CSCore.CoreAudioAPI.AudioClientStreamFlags.StreamFlagsNoPersist,   // 音量とミュートを記憶しない → 無効。してください
-                                                       this.更新間隔100ns,
-                                                       this.更新間隔100ns,
-                                                       this.WaveFormat,
-                                                       Guid.Empty );
-                                               //----------------
-                                               #endregion
-                                       }
-                               }
-
-                               this.更新間隔sample = this.AudioClient.GetBufferSize();
-                               //-----------------
-                               #endregion
-                               #region " AudioRenderClient を取得する。"
-                               //-----------------
-                               this.AudioRenderClient = CSCore.CoreAudioAPI.AudioRenderClient.FromAudioClient( this.AudioClient );
-                               //-----------------
-                               #endregion
-                               #region " AudioClock を取得する。"
-                               //-----------------
-                               this.bs_AudioClock = CSCore.CoreAudioAPI.AudioClock.FromAudioClient( this.AudioClient );
-                               //-----------------
-                               #endregion
-                               #region " エンドポイントバッファを無音で埋めておく。"
-                               //-----------------
-                               this.AudioRenderClient.GetBuffer( this.更新間隔sample );
-                               
-                               // 無音を書き込んだことにして、バッファをコミット。(GetBuffer の戻り値は使わない。)
-                               this.AudioRenderClient.ReleaseBuffer( this.更新間隔sample, CSCore.CoreAudioAPI.AudioClientBufferFlags.Silent );
-                               //-----------------
-                               #endregion
-
-                               #region " ミキサーを生成し初期化する。"
-                               //-----------------
-                               this.Mixer = new Mixer( this.更新間隔sample );
-                               //-----------------
-                               #endregion
-
-                               #region " 情報表示。"
-                               //-----------------
-                               FDK.Log.Info( $"WASAPIクライアントを初期化しました。" );
-                               FDK.Log.Info( ( 共有モード == CSCore.CoreAudioAPI.AudioClientShareMode.Shared ) ?
-                                       " モード: 共有 & イベント駆動" :
-                                       " モード: 排他 & イベント駆動" );
-                               FDK.Log.Info( $" フォーマット: {this.WaveFormat.BitsPerSample} bits, {this.WaveFormat.SampleRate} Hz" );
-                               FDK.Log.Info( $" エンドポイントバッファ: {( (float) this.更新間隔sample / (double) this.WaveFormat.SampleRate ) * 1000.0f} ミリ秒 ({this.更新間隔sample} samples) × 2枚" );
-                               FDK.Log.Info( $" 希望更新間隔: {希望更新間隔sec * 1000.0} ミリ秒" );
-                               FDK.Log.Info( $" 更新間隔: {this.更新間隔sec * 1000.0} ミリ秒 ({this.更新間隔sample} samples)" );
-                               if( 共有モード == CSCore.CoreAudioAPI.AudioClientShareMode.Exclusive )
-                                       FDK.Log.Info( $" 最小間隔: {FDK.Utilities.変換_100ns単位からsec単位へ( 排他モードでの最小間隔100ns )} ミリ秒" );
-                               //-----------------
-                               #endregion
-
-                               #region " ワークキューとイベントを作成し、作業項目を登録する。"
-                               //-----------------
-                               // MediaFoundation が管理する、プロセス&MMCSSタスクごとに1つずつ作ることができる特別な共有ワークキューを取得(または生成して取得)する。
-                               int dwTaskId = 0;
-                               SharpDX.MediaFoundation.MediaFactory.LockSharedWorkQueue( ( 0.011 > this.更新間隔sec ) ? "Pro Audio" : "Games", 0, ref dwTaskId, out this.QueueID );
-
-                               // エンドポイントバッファからの出力要請イベントを作成し、AudioClient に登録する。
-                               this.出力要請イベント = CreateEvent( IntPtr.Zero, false, false, "WASAPI出力要請イベント" );
-                               this.AudioClient.SetEventHandle( this.出力要請イベント );
-
-                               // コールバックを作成し、ワークキューに最初の作業項目を登録する。
-                               this.出力要請イベントのコールバック = new MFAsyncCallback( this.QueueID, this.出力要請イベントへ対応する );
-                               this.作業項目をキューに格納する();
-                               //-----------------
-                               #endregion
-                               #region " WASAPI レンダリングを開始。"
-                               //-----------------
-                               this.AudioClient.Start();
-                               //-----------------
-                               #endregion
-                       }
-
-                       FDK.Log.EndInfo( $"{FDK.Utilities.現在のメソッド名}" );
-               }
-               public void Dispose()
-               {
-                       FDK.Log.BeginInfo( $"{FDK.Utilities.現在のメソッド名}" );
-
-                       Trace.Assert( false == this.Dispose済み );
-
-                       #region " WASAPI作業項目を終了させる。オーディオのレンダリングを止める前に行うこと。"
-                       //-----------------
-                       {
-                               //SharpDX.MediaFoundation.MediaFactory.CancelWorkItem( this.出力要請イベントキャンセル用キー ); --> コールバックの実行中にキャンセルしてしまうと NullReference例外
-                               this.出力終了通知.状態 = 同期.TriStateEvent.状態種別.ON;
-                               this.出力終了通知.OFFになるまでブロックする();
-                               FDK.Log.Info( "WASAPI出力処理を終了しました。" );
-                       }
-                       //-----------------
-                       #endregion
-
-                       lock( this.スレッド間同期 )
-                       {
-                               #region " オーディオのレンダリングを停止する。"
-                               //-----------------
-                               this.AudioClient?.Stop();
-                               //-----------------
-                               #endregion
-                               #region " ミキサー(とサウンドリスト)は現状を維持する。"
-                               //-----------------
-
-                               // 何もしない。
-
-                               //-----------------
-                               #endregion
-                               #region " WASAPIオブジェクトを解放する。"
-                               //-----------------
-                               FDK.Utilities.解放する( ref this.bs_AudioClock );
-                               FDK.Utilities.解放する( ref this.AudioRenderClient );
-                               FDK.Utilities.解放する( ref this.AudioClient );
-                               //-----------------
-                               #endregion
-                               #region " 共有ワークキューをこのプロセスから解放する。"
-                               //-----------------
-                               if( int.MaxValue != this.QueueID )
-                               {
-                                       SharpDX.MediaFoundation.MediaFactory.UnlockWorkQueue( this.QueueID );
-                                       this.QueueID = int.MaxValue;
-                               }
-                               //-----------------
-                               #endregion
-                               #region " WASAPIイベント駆動用のコールバックとイベントを解放する。"
-                               //-----------------
-                               FDK.Utilities.解放する( ref this.出力要請イベントのコールバック );
-
-                               if( IntPtr.Zero != this.出力要請イベント )
-                                       Device.CloseHandle( this.出力要請イベント );
-                               //-----------------
-                               #endregion
-
-                               this.Dispose済み = true;
-                       }
-
-                       FDK.Log.EndInfo( $"{FDK.Utilities.現在のメソッド名}" );
-               }
-               public void サウンドをミキサーに追加する( Sound sound )
-               {
-                       this.Mixer.サウンドを追加する( sound );
-               }
-               public void サウンドをミキサーから削除する( Sound sound )
-               {
-                       this.Mixer.サウンドを削除する( sound );
-               }
-
-               protected CSCore.CoreAudioAPI.AudioClientShareMode 共有モード;
-               protected CSCore.CoreAudioAPI.AudioClient AudioClient = null;
-               protected CSCore.CoreAudioAPI.AudioRenderClient AudioRenderClient = null;
-               protected CSCore.WaveFormat WaveFormat = null;
-               protected long 更新間隔100ns = 0;
-               protected int 更新間隔sample = 0;
-               protected int 更新間隔byte => ( this.更新間隔sample * this.WaveFormat.Channels * this.WaveFormat.BytesPerSample );
-               protected double 更新間隔sec => ( FDK.Utilities.変換_100ns単位からsec単位へ( this.更新間隔100ns ) );
-
-               // ミキサー。サウンドリストもここ。
-               protected Mixer Mixer = null;
-
-               // WASAPIバッファ出力用
-               private int QueueID = int.MaxValue;
-               private IntPtr 出力要請イベント = IntPtr.Zero;
-               private MFAsyncCallback 出力要請イベントのコールバック = null;
-               private long 出力要請イベントキャンセル用キー = 0;
-               private FDK.同期.TriStateEvent 出力終了通知 = new 同期.TriStateEvent();
-
-               private readonly object スレッド間同期 = new object();
-
-               private void 作業項目をキューに格納する()
-               {
-                       var asyncResult = (SharpDX.MediaFoundation.AsyncResult) null;
-                       try
-                       {
-                               // IAsyncCallback を内包した AsyncResult を作成する。
-                               SharpDX.MediaFoundation.MediaFactory.CreateAsyncResult(
-                                       null,
-                                       SharpDX.ComObject.ToCallbackPtr<SharpDX.MediaFoundation.IAsyncCallback>( this.出力要請イベントのコールバック ),
-                                       null,
-                                       out asyncResult );
-
-                               // 作成した AsyncResult を、ワークキュー投入イベントの待機状態にする。
-                               SharpDX.MediaFoundation.MediaFactory.PutWaitingWorkItem(
-                                       hEvent: this.出力要請イベント,
-                                       priority: 0,
-                                       resultRef: asyncResult,
-                                       keyRef: out this.出力要請イベントキャンセル用キー );
-                       }
-                       finally
-                       {
-                               // out 引数に使う変数は using 変数にはできないので、代わりに try-finally を使う。
-                               asyncResult?.Dispose();
-                       }
-               }
-
-               /// <summary>
-               /// このメソッドは、WASAPIイベント発生時にワークキューに投入され作業項目から呼び出される。
-               /// </summary>
-               private void 出力要請イベントへ対応する( SharpDX.MediaFoundation.AsyncResult asyncResult )
-               {
-                       try
-                       {
-                               // 出力終了通知が来ていれば、応答してすぐに終了する。
-                               if( this.出力終了通知.状態 == 同期.TriStateEvent.状態種別.ON )
-                               {
-                                       this.出力終了通知.状態 = 同期.TriStateEvent.状態種別.無効;
-                                       return;
-                               }
-
-                               lock( this.スレッド間同期 )
-                               {
-                                       // エンドポインタの空きバッファへのポインタを取得する。
-                                       // このポインタが差すのはネイティブで確保されたメモリなので、GCの対象外である。はず。
-                                       var bufferPtr = this.AudioRenderClient.GetBuffer( this.更新間隔sample );    // イベント駆動なのでサイズ固定。
-
-                                       // ミキサーを使って、エンドポインタへサウンドデータを出力する。
-                                       var flags = this.Mixer.エンドポイントへ出力する( (void*) bufferPtr, this.更新間隔sample );
-
-                                       // エンドポインタのバッファを解放する。
-                                       this.AudioRenderClient.ReleaseBuffer( this.更新間隔sample, flags );
-
-                                       // 後続のイベント待ち作業項目をキューに格納する。
-                                       this.作業項目をキューに格納する();
-
-                                       // 以降、WASAPIからイベントが発火されるたび、作業項目を通じて本メソッドが呼び出される。
-                               }
-                       }
-                       catch
-                       {
-                               // 例外は無視。
-                       }
-               }
-
-               #region " バックストア。"
-               //----------------
-               private CSCore.CoreAudioAPI.AudioClock bs_AudioClock = null;
-               //----------------
-               #endregion
-
-               #region " Win32 API "
-               //-----------------
-               private static int AUDCLNT_E_BUFFER_SIZE_NOT_ALIGNED = unchecked((int) 0x88890019);
-
-               [System.Runtime.InteropServices.DllImport( "kernel32.dll" )]
-               private static extern IntPtr CreateEvent( IntPtr lpEventAttributes, bool bManualReset, bool bInitialState, string lpName );
-
-               [System.Runtime.InteropServices.DllImport( "kernel32.dll" )]
-               private static extern bool CloseHandle( IntPtr hObject );
-               //-----------------
-               #endregion
-       }
-}
diff --git a/FDK24/メディア/サウンド/WASAPIold/MFAsyncCallback.cs b/FDK24/メディア/サウンド/WASAPIold/MFAsyncCallback.cs
deleted file mode 100644 (file)
index dd76175..0000000
+++ /dev/null
@@ -1,36 +0,0 @@
-using System;
-
-namespace FDK.メディア.サウンド.WASAPIold
-{
-       /// <summary>
-       /// IMFAsyncCallback の汎用的な実装。
-       /// </summary>
-       /// <remarks>
-       /// コンストラクタで、ワークキューIDとコールバックデリゲート(InvokeFunc型)を指定する。
-       /// </remarks>
-       public class MFAsyncCallback : SharpDX.MediaFoundation.AsyncCallbackBase, SharpDX.MediaFoundation.IAsyncCallback
-       {
-               public delegate void InvokeFunc( SharpDX.MediaFoundation.AsyncResult asyncResult );
-
-               public MFAsyncCallback( int QueueID, InvokeFunc invokeFunc )
-               {
-                       this.QueueID = new SharpDX.MediaFoundation.WorkQueueId( QueueID );
-                       this.invokeFunc = invokeFunc;
-               }
-
-               public override SharpDX.MediaFoundation.WorkQueueId WorkQueueId
-               {
-                       get
-                       {
-                               return this.QueueID;
-                       }
-               }
-               public override void Invoke( SharpDX.MediaFoundation.AsyncResult asyncResult )
-               {
-                       this.invokeFunc( asyncResult );
-               }
-
-               private SharpDX.MediaFoundation.WorkQueueId QueueID = SharpDX.MediaFoundation.WorkQueueId.Standard;
-               private InvokeFunc invokeFunc = null;
-       }
-}
diff --git a/FDK24/メディア/サウンド/WASAPIold/Mixer.cs b/FDK24/メディア/サウンド/WASAPIold/Mixer.cs
deleted file mode 100644 (file)
index 4e2dba7..0000000
+++ /dev/null
@@ -1,128 +0,0 @@
-using System;
-using System.Collections.Generic;
-
-namespace FDK.メディア.サウンド.WASAPIold
-{
-       /// <summary>
-       /// Sound のリストを持ち、そのサウンドデータを合成してWASAPIデバイスへ出力するミキサー。
-       /// </summary>
-       public unsafe class Mixer : IDisposable
-       {
-               public Mixer()
-               {
-               }
-               public Mixer( int エンドポイントバッファサイズsample ) : this()
-               {
-                       this.初期化する( エンドポイントバッファサイズsample );
-               }
-               public void 初期化する( int エンドポイントバッファサイズsample )
-               {
-                       lock( this.スレッド間同期 )
-                       {
-                               if( エンドポイントバッファサイズsample == this.エンドポイントバッファサイズsample )
-                                       return;     // サイズに変更があったときのみ初期化する。
-
-                               this.エンドポイントバッファサイズsample = エンドポイントバッファサイズsample;
-                               this.サウンドリスト.Clear();
-
-                               if( null != this.合成用バッファ )
-                                       FDK.Memory.Free( this.合成用バッファ );
-                               this.合成用バッファ = FDK.Memory.Alloc( this.エンドポイントバッファサイズsample * ( 4 * 2 ) );       // 1sample = 32bit×2ch
-                       }
-               }
-               public void Dispose()
-               {
-                       lock( this.スレッド間同期 )
-                       {
-                               this.サウンドリスト.Clear();
-                               if( null != this.合成用バッファ )
-                               {
-                                       FDK.Memory.Free( this.合成用バッファ );
-                                       this.合成用バッファ = null;
-                               }
-                               this.エンドポイントバッファサイズsample = -1;
-                       }
-               }
-               public void サウンドリストをクリアする()
-               {
-                       lock( this.スレッド間同期 )
-                       {
-                               this.サウンドリスト.Clear();
-                       }
-               }
-               public void サウンドを追加する( Sound sound )
-               {
-                       lock( this.スレッド間同期 )
-                       {
-                               this.サウンドリスト.Add( sound );
-                       }
-               }
-               public void サウンドを削除する( Sound sound )
-               {
-                       lock( this.スレッド間同期 )
-                       {
-                               this.サウンドリスト.Remove( sound );
-                       }
-               }
-               public CSCore.CoreAudioAPI.AudioClientBufferFlags エンドポイントへ出力する( void* エンドポイントの出力先, int 出力数sample )
-               {
-                       lock( this.スレッド間同期 )
-                       {
-                               if( null == this.合成用バッファ )
-                                       return CSCore.CoreAudioAPI.AudioClientBufferFlags.Silent;
-
-                               #region " すべてのサウンドについて、合成バッファへ出力する。"
-                               //-----------------
-                               bool 最初の出力である = true;
-
-                               foreach( var sound in this.サウンドリスト )
-                               {
-                                       var flag = sound.次のサウンドデータを出力する( this.合成用バッファ, 出力数sample, 最初の出力である );
-
-                                       if( false == flag.HasFlag( CSCore.CoreAudioAPI.AudioClientBufferFlags.Silent ) )
-                                               最初の出力である = false;   // sound が何らかのデータを出力した(戻り値がSILENTじゃなかった)
-                               }
-
-                               // 全サウンドが SILENT だったなら、エンドポイントには何も書き込まずに SILENT フラグを返す。
-                               if( 最初の出力である )
-                                       return CSCore.CoreAudioAPI.AudioClientBufferFlags.Silent;
-                               //-----------------
-                               #endregion
-                               #region " 合成バッファのデータ値(32bit;オーバーサンプル)を16bitに丸めてエンドポイントに出力する。"
-                               //-----------------
-                               Int32* 出力元 = (Int32*) ( this.合成用バッファ );
-                               Int16* 出力先 = (Int16*) エンドポイントの出力先;
-                               for( int i = 0; i < 出力数sample; i++ )
-                               {
-                                       Int32 src;
-
-                                       // 音量やミュートの処理は不要。(WASAPI が自動でマスタ音量・ミュート状態に合わせてくれる)
-
-                                       // 左ch
-                                       src = *出力元++;
-                                       if( -32768 > src )
-                                               src = -32768;
-                                       else if( 32767 < src )
-                                               src = 32767;
-                                       *出力先++ = (Int16) src;
-
-                                       // 右ch
-                                       src = *出力元++;
-                                       if( -32768 > src )
-                                               src = -32768;
-                                       else if( 32767 < src )
-                                               src = 32767;
-                                       *出力先++ = (Int16) src;
-                               }
-                               //-----------------
-                               #endregion
-                       }
-                       return CSCore.CoreAudioAPI.AudioClientBufferFlags.None;
-               }
-
-               private int エンドポイントバッファサイズsample = -1;
-               private readonly List<Sound> サウンドリスト = new List<Sound>();
-               private void* 合成用バッファ = null;
-               private readonly object スレッド間同期 = new object();
-       }
-}
diff --git a/FDK24/メディア/サウンド/WASAPIold/Sound.cs b/FDK24/メディア/サウンド/WASAPIold/Sound.cs
deleted file mode 100644 (file)
index d7afcbe..0000000
+++ /dev/null
@@ -1,376 +0,0 @@
-using System;
-
-namespace FDK.メディア.サウンド.WASAPIold
-{
-       public unsafe class Sound : IDisposable
-       {
-               public enum E再生状態
-               {
-                       停止中,    // 初期状態
-                       再生中,
-                       一時停止中,
-                       再生終了,
-               };
-               public E再生状態 再生状態 = E再生状態.停止中;
-
-               /// <summary>
-               /// 0.0(最小)~1.0(原音) の範囲で指定する。再生中でも反映される。
-               /// </summary>
-               public float 音量
-               {
-                       set
-                       {
-                               float 設定値 = Math.Min( Math.Max( value, 0.0f ), 1.0f );  // 0.0未満は0.0へ、1.0超は1.0へ。
-                               lock( this.排他利用 )
-                               {
-                                       this.bs_音量 = 設定値;
-                               }
-                       }
-                       get
-                       {
-                               lock( this.排他利用 )
-                               {
-                                       return this.bs_音量;
-                               }
-                       }
-               }
-               public double 長さsec
-               {
-                       get
-                       {
-                               lock( this.排他利用 )
-                               {
-                                       return ( this.サウンドデータサイズsample / this.WAVEフォーマット.SampleRate );
-                               }
-                       }
-               }
-
-               public Sound()
-               {
-               }
-               public Sound( string サウンドファイルuri ) : this()
-               {
-                       this.ファイルから作成する( サウンドファイルuri );
-               }
-               public void ファイルから作成する( string サウンドファイルuri )
-               {
-                       lock( this.排他利用 )
-                       {
-                               #region " 作成済みなら先にDisposeする。"
-                               //-----------------
-                               if( this.作成済み )
-                                       this.Dispose();
-
-                               this.作成済み = false;
-                               //-----------------
-                               #endregion
-
-                               byte[] encodedPcm = null;
-
-                               using( var sourceReader = new SharpDX.MediaFoundation.SourceReader( サウンドファイルuri ) )
-                               using( var pcmStream = new System.IO.MemoryStream() )
-                               {
-                                       #region " サウンドファイル名から SourceReader を作成する。"
-                                       //-----------------
-
-                                       // 先述の using で作成済み。
-
-                                       // 最初のオーディオストリームを選択し、その他のすべてのストリームを非選択にする。
-                                       sourceReader.SetStreamSelection( SharpDX.MediaFoundation.SourceReaderIndex.AllStreams, false );
-                                       sourceReader.SetStreamSelection( SharpDX.MediaFoundation.SourceReaderIndex.FirstAudioStream, true );
-
-                                       // メディアタイプを作成し、オーディオフォーマットを設定する。(固定フォーマットとする。)
-                                       using( var mediaType = new SharpDX.MediaFoundation.MediaType() )
-                                       {
-                                               mediaType.Set<Guid>( SharpDX.MediaFoundation.MediaTypeAttributeKeys.MajorType, SharpDX.MediaFoundation.MediaTypeGuids.Audio );
-                                               mediaType.Set<Guid>( SharpDX.MediaFoundation.MediaTypeAttributeKeys.Subtype, SharpDX.MediaFoundation.AudioFormatGuids.Pcm );
-                                               mediaType.Set<int>( SharpDX.MediaFoundation.MediaTypeAttributeKeys.AudioNumChannels, this.WAVEフォーマット.Channels );
-                                               mediaType.Set<int>( SharpDX.MediaFoundation.MediaTypeAttributeKeys.AudioSamplesPerSecond, this.WAVEフォーマット.SampleRate );
-                                               mediaType.Set<int>( SharpDX.MediaFoundation.MediaTypeAttributeKeys.AudioBlockAlignment, this.WAVEフォーマット.BlockAlign );
-                                               mediaType.Set<int>( SharpDX.MediaFoundation.MediaTypeAttributeKeys.AudioAvgBytesPerSecond, this.WAVEフォーマット.AverageBytesPerSecond );
-                                               mediaType.Set<int>( SharpDX.MediaFoundation.MediaTypeAttributeKeys.AudioBitsPerSample, this.WAVEフォーマット.BitsPerSample );
-                                               mediaType.Set<int>( SharpDX.MediaFoundation.MediaTypeAttributeKeys.AllSamplesIndependent, 1 ); // TRUE
-
-                                               // 作成したメディアタイプを sourceReader にセットする。sourceReader は、必要なデコーダをロードするだろう。
-                                               sourceReader.SetCurrentMediaType( SharpDX.MediaFoundation.SourceReaderIndex.FirstAudioStream, mediaType );
-                                       }
-
-                                       // 最初のオーディオストリームが選択されていることを保証する。
-                                       sourceReader.SetStreamSelection( SharpDX.MediaFoundation.SourceReaderIndex.FirstAudioStream, true );
-                                       //-----------------
-                                       #endregion
-                                       #region " sourceReader からサンプルを取得してデコードし、メモリストリーム pcmStream へ書き込んだのち、encodedPcm へ変換する。"
-                                       //-----------------
-                                       using( var pcmWriter = new System.IO.BinaryWriter( pcmStream ) )
-                                       {
-                                               while( true )
-                                               {
-                                                       // 次のサンプルを読み込む。
-                                                       int dwActualStreamIndexRef = 0;
-                                                       var dwStreamFlagsRef = SharpDX.MediaFoundation.SourceReaderFlags.None;
-                                                       Int64 llTimestampRef = 0;
-
-                                                       using( var sample = sourceReader.ReadSample(
-                                                               SharpDX.MediaFoundation.SourceReaderIndex.FirstAudioStream,
-                                                               SharpDX.MediaFoundation.SourceReaderControlFlags.None,
-                                                               out dwActualStreamIndexRef,
-                                                               out dwStreamFlagsRef,
-                                                               out llTimestampRef ) )
-                                                       {
-                                                               if( null == sample )
-                                                                       break;      // EndOfStream やエラーも含まれる。
-
-                                                               // サンプルをロックし、オーディオデータへのポインタを取得する。
-                                                               int cbMaxLengthRef = 0;
-                                                               int cbCurrentLengthRef = 0;
-                                                               using( var mediaBuffer = sample.ConvertToContiguousBuffer() )
-                                                               {
-                                                                       // オーディオデータをメモリストリームに書き込む。
-                                                                       var audioData = mediaBuffer.Lock( out cbMaxLengthRef, out cbCurrentLengthRef );
-
-                                                                       byte[] dstData = new byte[ cbCurrentLengthRef ];
-                                                                       byte* psrcData = (byte*) audioData.ToPointer(); // fixed
-                                                                       fixed ( byte* pdstData = dstData )
-                                                                       {
-                                                                               CopyMemory( pdstData, psrcData, cbCurrentLengthRef );
-                                                                       }
-                                                                       pcmWriter.Write( dstData, 0, cbCurrentLengthRef );
-
-                                                                       // サンプルのロックを解除する。
-                                                                       mediaBuffer.Unlock();
-                                                               }
-                                                       }
-                                               }
-
-                                               // ストリームの内容を byte 配列に出力。(Position に関係なく全部出力される。)
-                                               encodedPcm = pcmStream.ToArray();
-                                       }
-                                       //-----------------
-                                       #endregion
-                               }
-                               #region " オーバーサンプリングサウンドデータバッファを確保し、encodedPcm からサンプルを転送する。"
-                               //-----------------
-                               using( var pcmReader = new System.IO.BinaryReader( new System.IO.MemoryStream( encodedPcm ) ) )
-                               {
-                                       // PCMサイズを計算する。(16bit → 32bit でオーバーサンプリングする。)
-                                       this.サウンドデータサイズbyte = encodedPcm.Length * 2;       // 32bit は 16bit の2倍。
-                                       this.サウンドデータサイズsample = this.サウンドデータサイズbyte / 8;    // 1sample = 32bit×2h = 64bit = 8bytes
-
-                                       // オーバーサンプリングサウンドデータ用メモリを確保する。
-                                       this.サウンドデータ = (byte*) FDK.Memory.Alloc( this.サウンドデータサイズbyte );
-
-                                       // ストリームからオーバーサンプリングサウンドデータへ転送する。
-                                       var p = (Int32*) this.サウンドデータ;
-                                       for( int i = 0; i < this.サウンドデータサイズsample; i++ )
-                                       {
-                                               // 1サンプル = 2ch×INT16 を 2ch×INT32 に変換しながら格納。
-                                               *p++ = (Int32) pcmReader.ReadInt16();   // 左ch
-                                               *p++ = (Int32) pcmReader.ReadInt16();   // 右ch
-                                       }
-                               }
-                               //-----------------
-                               #endregion
-
-                               this.再生位置sample = 0;
-                               this.作成済み = true;
-                       }
-               }
-               public void 再生を開始する( double 再生開始位置sec = 0.0 )
-               {
-                       lock( this.排他利用 )
-                       {
-                               if( false == this.作成済み )
-                                       return;     // エラーにはしない。サウンド作成失敗時には、何も再生しないようにするだけ。
-
-                               int 開始位置sample = (int) ( 再生開始位置sec * this.WAVEフォーマット.SampleRate );
-                               if( 開始位置sample < this.サウンドデータサイズsample )
-                               {
-                                       this.再生状態 = E再生状態.再生中;
-                                       this.再生位置sample = 開始位置sample;
-                               }
-                       }
-               }
-               public void 再生を一時停止する()
-               {
-                       lock( this.排他利用 )
-                       {
-                               if( false == this.作成済み )
-                                       return;     // エラーにはしない。サウンド作成失敗時には、何も再生しないようにするだけ。
-
-                               this.再生状態 = E再生状態.一時停止中;
-                       }
-               }
-               public void 再生を再開する()
-               {
-                       lock( this.排他利用 )
-                       {
-                               if( false == this.作成済み )
-                                       return;     // エラーにはしない。サウンド作成失敗時には、何も再生しないようにするだけ。
-
-                               if( E再生状態.一時停止中 != this.再生状態 )
-                                       this.再生位置sample = 0;
-
-                               this.再生状態 = E再生状態.再生中;
-                       }
-               }
-               public void 再生を停止する()
-               {
-                       lock( this.排他利用 )
-                       {
-                               if( false == this.作成済み )
-                                       return;     // エラーにはしない。サウンド作成失敗時には、何も再生しないようにするだけ。
-
-                               this.再生状態 = E再生状態.停止中;
-                               this.再生位置sample = 0;
-                       }
-               }
-               public CSCore.CoreAudioAPI.AudioClientBufferFlags 次のサウンドデータを出力する( void* 出力先, int 出力サンプル数, bool 最初の出力である )
-               {
-                       lock( this.排他利用 )
-                       {
-                               #region " 未作成、または再生中でないなら無音フラグをもって帰還。"
-                               //-----------------
-                               if( ( false == this.作成済み ) || ( E再生状態.再生中 != this.再生状態 ) )
-                                       return CSCore.CoreAudioAPI.AudioClientBufferFlags.Silent;
-                               //-----------------
-                               #endregion
-
-                               int オーバーサンプルサイズbyte = 4 * 2;    // 32bit×2ch
-                               Int32* 出力元 = (Int32*) ( this.サウンドデータ + ( this.再生位置sample * オーバーサンプルサイズbyte ) );
-                               Int32* _出力先 = (Int32*) 出力先;     // この実装ではサンプルは Int32 単位
-                               int 出力できるサンプル数 = System.Math.Min( 出力サンプル数, ( this.サウンドデータサイズsample - this.再生位置sample ) );
-                               int 出力できないサンプル数 = 出力サンプル数 - 出力できるサンプル数;
-
-                               if( 出力できるサンプル数 <= 0 )
-                                       this.再生状態 = E再生状態.再生終了; // 念のため
-
-                               if( 最初の出力である )
-                               {
-                                       #region " (A) 上書き。余った部分にもデータ(無音またはループ)を出力する。"
-                                       //-----------------
-                                       if( 1.0f == this.bs_音量 )
-                                       {
-                                               // 原音(最大音量)。
-                                               CopyMemory( _出力先, 出力元, ( 出力できるサンプル数 * オーバーサンプルサイズbyte ) );
-                                       }
-                                       else
-                                       {
-                                               // 音量を反映。
-                                               for( int i = 0; i < 出力できるサンプル数; i++ )
-                                               {
-                                                       // 1サンプル = 2ch×INT32
-                                                       *_出力先++ = (Int32) ( ( *出力元++ ) * this.bs_音量 );
-                                                       *_出力先++ = (Int32) ( ( *出力元++ ) * this.bs_音量 );
-                                               }
-                                       }
-
-                                       if( 0 < 出力できないサンプル数 ) // サウンドデータの末尾に達した
-                                       {
-                                               // 残りの部分は、とりあえず今は無音。(ループ再生未対応)
-                                               ZeroMemory(
-                                                       (void*) ( ( (byte*) _出力先 ) + ( 出力できるサンプル数 * オーバーサンプルサイズbyte ) ),
-                                                       出力できないサンプル数 * オーバーサンプルサイズbyte );
-                                       }
-                                       //-----------------
-                                       #endregion
-                               }
-                               else
-                               {
-                                       #region " (B) 加算合成。余った部分は放置してもいいし、ループしてデータ加算を続けてもいい。"
-                                       //-----------------
-                                       for( int i = 0; i < 出力できるサンプル数; i++ )
-                                       {
-                                               // 1サンプル = 2ch×INT32
-                                               *_出力先++ += (Int32) ( ( *出力元++ ) * this.bs_音量 );
-                                               *_出力先++ += (Int32) ( ( *出力元++ ) * this.bs_音量 );
-                                       }
-
-                                       if( 0 < 出力できないサンプル数 )
-                                       {
-                                               // 残りの部分は、今回の実装では無視。(ループ再生未対応。)
-                                       }
-                                       //-----------------
-                                       #endregion
-                               }
-
-                               #region " 再生位置を移動。"
-                               //---------------------------------------------------
-                               this.再生位置sample += 出力できるサンプル数;
-
-                               if( this.サウンドデータサイズsample <= this.再生位置sample )  // サウンドデータの末尾に達した
-                               {
-                                       this.再生位置sample = this.サウンドデータサイズsample;
-                                       this.再生状態 = E再生状態.再生終了;   // 再生終了に伴う自動終了なので、"停止中" ではない。
-                               }
-                               //---------------------------------------------------
-                               #endregion
-                       }
-
-                       return CSCore.CoreAudioAPI.AudioClientBufferFlags.None;
-               }
-
-               #region " Dispose-Finalizeパターン "
-               //----------------
-               ~Sound()
-               {
-                       this.Dispose( false );
-               }
-               public void Dispose()
-               {
-                       this.Dispose( true );
-                       GC.SuppressFinalize( this );
-               }
-               protected void Dispose( bool Managedも解放する )
-               {
-                       Action サウンドデータを解放する = () => {
-                               if( null != this.サウンドデータ )
-                               {
-                                       FDK.Memory.Free( (void*) this.サウンドデータ );
-                                       this.サウンドデータ = null;
-                               }
-                       };
-
-                       if( Managedも解放する )
-                       {
-                               // C#オブジェクトの解放があればここで。
-
-                               // this.排他利用を使った Unmanaged の解放。
-                               lock( this.排他利用 )
-                               {
-                                       サウンドデータを解放する();
-                               }
-                       }
-                       else
-                       {
-                               // (使える保証がないので)this.排他利用 を使わないUnmanaged の解放。
-                               サウンドデータを解放する();
-                       }
-               }
-               //----------------
-               #endregion
-
-               private bool 作成済み = false;
-               private byte* サウンドデータ = null;
-               private int サウンドデータサイズbyte = 0;
-               private int サウンドデータサイズsample = 0;
-               private int 再生位置sample = 0;
-               private readonly SharpDX.Multimedia.WaveFormat WAVEフォーマット = new SharpDX.Multimedia.WaveFormat( 44100, 16, 2 );      // 固定
-               private readonly object 排他利用 = new object();
-
-               #region " バックストア "
-               //----------------
-               private float bs_音量 = 1.0f;
-               //----------------
-               #endregion
-
-               #region " Win32 API "
-               //-----------------
-               [System.Runtime.InteropServices.DllImport( "kernel32.dll", SetLastError = true )]
-               private static extern unsafe void CopyMemory( void* dst, void* src, int size );
-
-               [System.Runtime.InteropServices.DllImport( "kernel32.dll", SetLastError = true )]
-               private static extern unsafe void ZeroMemory( void* dst, int length );
-               //-----------------
-               #endregion
-       }
-}
diff --git a/FDK24/メディア/サウンド/WASAPIold/SoundTimer.cs b/FDK24/メディア/サウンド/WASAPIold/SoundTimer.cs
deleted file mode 100644 (file)
index 309407b..0000000
+++ /dev/null
@@ -1,68 +0,0 @@
-using System;
-
-namespace FDK.メディア.サウンド.WASAPIold
-{
-       /// <summary>
-       /// WASAPIデバイス(のIAudioClock)をソースとするタイマー。
-       /// </summary>
-       /// <remarks>
-       /// WASAPIデバイスと厳密に同期をとる場合には、QPCTimer ではなく、このクラスを使用する。
-       /// </remarks>
-       public class SoundTimer
-       {
-               /// <summary>
-               /// エラー時は double.NaN を返す。
-               /// </summary>
-               public double 現在のデバイス位置secを取得する( CSCore.CoreAudioAPI.AudioClock audioClock )
-               {
-                       lock( this.スレッド間同期 )
-                       {
-                               int hr = 0;
-                               long デバイス周波数 = 0;// audioClock.Pu64Frequency;
-                               audioClock.GetFrequencyNative( out デバイス周波数 );
-                               long QPC周波数 = FDK.カウンタ.QPCTimer.周波数;
-                               long デバイス位置 = 0;
-                               long デバイス位置取得時のパフォーマンスカウンタを100ns単位に変換した時間 = 0;
-
-                               if( 0.0 >= デバイス周波数 )
-                                       return double.NaN;
-
-                               // IAudioClock::GetPosition() は、S_FALSE を返すことがある。
-                               // これは、WASAPI排他モードにおいて、GetPosition 時に優先度の高いイベントが発生しており
-                               // 既定時間内にデバイス位置を取得できなかった場合に返される。(MSDNより)
-                               for( int リトライ回数 = 0; リトライ回数 < 10; リトライ回数++ )    // 最大10回までリトライ。
-                               {
-                                       hr = audioClock.GetPositionNative( out デバイス位置, out デバイス位置取得時のパフォーマンスカウンタを100ns単位に変換した時間 );
-
-                                       if( ( (int) CSCore.Win32.HResult.S_OK ) == hr )
-                                       {
-                                               break;      // OK
-                                       }
-                                       else if( ( (int) CSCore.Win32.HResult.S_FALSE ) == hr )
-                                       {
-                                               continue;   // リトライ
-                                       }
-                                       else
-                                       {
-                                               throw new CSCore.Win32.Win32ComException( hr, "IAudioClock", "GetPosition" );
-                                       }
-                               }
-                               if( ( (int) CSCore.Win32.HResult.S_FALSE ) == hr )
-                               {
-                                       // 全部リトライしてもまだダメならエラー。
-                                       return double.NaN;
-                               }
-
-                               // デバイス位置は、GetPosition() で取得した瞬間からここに至るまでに、既にいくらか進んでいる。
-                               // そこで、この時点で最新のパフォーマンスカウンタを取得し、時間の増加分をデバイス位置に加えて精度を上げる。(MSDNより)
-                               double QPCから調べた差分sec =
-                                       ( (double) FDK.カウンタ.QPCTimer.生カウント / QPC周波数 ) -
-                                       ( (double) デバイス位置取得時のパフォーマンスカウンタを100ns単位に変換した時間 ) / 10000000.0;
-
-                               return ( (double) デバイス位置 ) / デバイス周波数 + QPCから調べた差分sec;
-                       }
-               }
-
-               private readonly object スレッド間同期 = new object();
-       }
-}
index bf463eb..3cffe6b 100644 (file)
@@ -18,9 +18,9 @@ namespace SST
                {
                        get { return StrokeStyleT.bs_フォルダ; }
                }
-               public static FDK.メディア.サウンド.WASAPIold.Device Wasapiデバイス
+               public static FDK.メディア.サウンド.WASAPI.Device サウンドデバイス
                {
-                       get { return StrokeStyleT.bs_Wasapiデバイス; }
+                       get { return StrokeStyleT.bs_サウンドデバイス; }
                }
                public static System.Random 乱数
                {
@@ -192,7 +192,7 @@ namespace SST
                        if( StrokeStyleT.ビュアーモードではない )
                                return 0f;
 
-                       return ( null != StrokeStyleT.Wasapiデバイス ) ? (float) ( StrokeStyleT.Wasapiデバイス.遅延sec * 1000.0 ) : 0f;
+                       return ( null != StrokeStyleT.サウンドデバイス ) ? (float) ( StrokeStyleT.サウンドデバイス.遅延sec * 1000.0 ) : 0f;
                }
                //----------------
                #endregion
@@ -306,10 +306,9 @@ namespace SST
                                ユーザ.SourcesXmlを読み込む();
                        //-----------------
                        #endregion
-                       #region " WASAPI デバイスを初期化する。"
+                       #region " サウンドデバイスを初期化する。"
                        //----------------
-                       StrokeStyleT.bs_Wasapiデバイス = new FDK.メディア.サウンド.WASAPIold.Device();
-                       StrokeStyleT.bs_Wasapiデバイス.初期化する( CSCore.CoreAudioAPI.AudioClientShareMode.Exclusive, 0.015 );
+                       StrokeStyleT.bs_サウンドデバイス = new FDK.メディア.サウンド.WASAPI.Device( CSCore.CoreAudioAPI.AudioClientShareMode.Shared );
                        //----------------
                        #endregion
                        #region " キーボード入力 を初期化する。"
@@ -385,10 +384,10 @@ namespace SST
                        FDK.Utilities.解放する( ref StrokeStyleT.bs_キーボード入力 );
                        //-----------------
                        #endregion
-                       #region " WASAPIデバイスを解放する。"
+                       #region " サウンドデバイスを解放する。"
                        //----------------
-                       FDK.Log.Info( "WASAPIデバイスを解放します。" );
-                       FDK.Utilities.解放する( ref StrokeStyleT.bs_Wasapiデバイス );
+                       FDK.Log.Info( "サウンドデバイスを解放します。" );
+                       FDK.Utilities.解放する( ref StrokeStyleT.bs_サウンドデバイス );
                        //----------------
                        #endregion
                        
@@ -845,7 +844,7 @@ namespace SST
                private static SST.フォルダ bs_フォルダ = null;
                private static FDK.入力.Keyboard bs_キーボード入力 = null;
                private static FDK.入力.MidiIn bs_MIDI入力 = null;
-               private static FDK.メディア.サウンド.WASAPIold.Device bs_Wasapiデバイス = null;
+               private static FDK.メディア.サウンド.WASAPI.Device bs_サウンドデバイス = null;
                private static readonly System.Random bs_乱数 = new Random( DateTime.Now.Millisecond );
                private static SST.ユーザ.ユーザ管理 bs_ユーザ管理 = null;
                private static SST.曲.曲ツリー管理 bs_曲ツリー管理 = null;
index e9f2819..b5c29fe 100644 (file)
@@ -60,7 +60,7 @@ namespace SST.ステージ.曲読込
                                                        float 作成時遅延ms = StrokeStyleT.演奏スコア.Header.サウンドデバイス遅延ms;
                                                        if( 0f < 作成時遅延ms )
                                                        {
-                                                               float 再生時遅延ms = (float) ( StrokeStyleT.Wasapiデバイス.遅延sec * 1000.0 );
+                                                               float 再生時遅延ms = (float) ( StrokeStyleT.サウンドデバイス.遅延sec * 1000.0 );
                                                                long 加算分ms = (long) ( 作成時遅延ms - 再生時遅延ms );  // 例: 作成時遅延 7ms, 再生時遅延 10ms の場合、発声時刻に 7-10 = -3ms 加算する(3ms 早く発声させる)。
 
                                                                FDK.Log.Info( $"作成時遅延={作成時遅延ms}ms, 再生時遅延={再生時遅延ms}ms => 加算分 = {加算分ms}ms" );
index 18ed76a..afb14ce 100644 (file)
@@ -41,14 +41,14 @@ namespace SST.ステージ.演奏
                                        // 集めた Sounds[] をすべて停止する。
                                        foreach( var sounds in 停止するサウンド群 )
                                                foreach( var sound in sounds )
-                                                       sound.再生を停止する();
+                                                       sound.Stop();
                                }
 
                                // 再生する。
                                if( null != context.Sounds[ context.次に再生するSound番号 ] )
                                {
-                                       context.Sounds[ context.次に再生するSound番号 ].音量 = 音量0to1;
-                                       context.Sounds[ context.次に再生するSound番号 ].再生を開始する();
+                                       context.Sounds[ context.次に再生するSound番号 ].Volume = 音量0to1;
+                                       context.Sounds[ context.次に再生するSound番号 ].Play();
                                }
 
                                // サウンドローテーション。
@@ -62,7 +62,7 @@ namespace SST.ステージ.演奏
                protected readonly string KitXmlファイルパス = @"$(Static)\sounds\Kit.xml";
                protected class Cコンテキスト : IDisposable
                {
-                       public FDK.メディア.サウンド.WASAPIold.Sound[] Sounds = new FDK.メディア.サウンド.WASAPIold.Sound[ ドラムサウンド.多重度 ];
+                       public FDK.メディア.サウンド.WASAPI.Sound[] Sounds = new FDK.メディア.サウンド.WASAPI.Sound[ ドラムサウンド.多重度 ];
                        public int 次に再生するSound番号 = 0;
 
                        public void Dispose()
@@ -71,7 +71,7 @@ namespace SST.ステージ.演奏
                                {
                                        for( int i = 0; i < this.Sounds.Length; i++ )
                                        {
-                                               StrokeStyleT.Wasapiデバイス.サウンドをミキサーから削除する( this.Sounds[ i ] );
+                                               this.Sounds[ i ].Stop();
                                                FDK.Utilities.解放する( ref this.Sounds[ i ] );
                                        }
                                }
@@ -141,16 +141,14 @@ namespace SST.ステージ.演奏
 
                                                                                        // コンテキストを作成する。
                                                                                        var context = new Cコンテキスト() {
-                                                                                               Sounds = new FDK.メディア.サウンド.WASAPIold.Sound[ ドラムサウンド.多重度 ],
+                                                                                               Sounds = new FDK.メディア.サウンド.WASAPI.Sound[ ドラムサウンド.多重度 ],
                                                                                                次に再生するSound番号 = 0,
                                                                                        };
-                                                                                       for( int i = 0; i < context.Sounds.Length; i++ )
-                                                                                       {
-                                                                                               // 多重度分のサウンドを生成しつつ、ミキサーにも登録。
-                                                                                               context.Sounds[ i ] = new FDK.メディア.サウンド.WASAPIold.Sound( サウンドファイルパス );
-                                                                                               StrokeStyleT.Wasapiデバイス.サウンドをミキサーに追加する( context.Sounds[ i ] );
-                                                                                       }
 
+                                                                                       // 多重度分のサウンドを生成する。
+                                                                                       for( int i = 0; i < context.Sounds.Length; i++ )
+                                                                                               context.Sounds[ i ] = StrokeStyleT.サウンドデバイス.CreateSound( サウンドファイルパス );
+                                                                                       
                                                                                        // コンテキストを辞書に追加する。
                                                                                        this.チップtoコンテキスト.Add( チップ種別, context );
                                                                                }
index 5563b26..adc8d74 100644 (file)
@@ -70,7 +70,11 @@ namespace SST.ステージ.演奏
                        this.スクロール譜面.背景動画再生開始 = ( 開始位置sec ) => {
                                this.背景動画.再生を開始する( 開始位置sec );
                                this.背景動画開始済み.Value = true;
-                               this.BGM?.再生を開始する( 開始位置sec );
+                               if( null != this.BGM )
+                               {
+                                       this.BGM.位置sec = 開始位置sec;
+                                       this.BGM?.Play();
+                               }
                                this.BGM再生開始済み = true;
                        };
                        this.スクロール譜面.チップヒット = ( chip ) => {
@@ -102,10 +106,8 @@ namespace SST.ステージ.演奏
                                // 動画を子リストに追加。
                                this.子リスト.Add( this.背景動画 = new 動画( StrokeStyleT.演奏スコア.背景動画ファイル名, StrokeStyleT.Config.動画デコーダのキューサイズ ) );
 
-                               // 動画から BGM を作成してミキサーに追加。
-                               this.BGM = new FDK.メディア.サウンド.WASAPIold.Sound();
-                               this.BGM.ファイルから作成する( StrokeStyleT.演奏スコア.背景動画ファイル名 );
-                               StrokeStyleT.Wasapiデバイス.サウンドをミキサーに追加する( this.BGM ); // 作成に失敗した Sound を追加しても鳴らないだけなので、ノーチェックで大丈夫。
+                               // 動画から BGM を作成。
+                               this.BGM = StrokeStyleT.サウンドデバイス.CreateSound( StrokeStyleT.演奏スコア.背景動画ファイル名 );
                        }
                        else
                        {
@@ -166,9 +168,13 @@ namespace SST.ステージ.演奏
                                        演奏開始位置の先頭からの時間sec = this.スクロール譜面.演奏開始小節番号を設定しその時刻secを返す( msg.演奏開始小節番号 );
                                        this.Autoチップのドラム音を再生する = msg.ドラムチップ発声;
                                }
+
+                               long position, qpcPosition, frequency;
+                               StrokeStyleT.サウンドデバイス.GetClock( out position, out qpcPosition, out frequency );
+
                                this.演奏開始時刻sec = 
-                                       this.サウンドタイマ.現在のデバイス位置secを取得する( StrokeStyleT.Wasapiデバイス.AudioClock ) -        // '+' じゃないので注意!
-                                       演奏開始位置の先頭からの時間sec;
+                                       this.サウンドタイマ.現在のデバイス位置secを取得する( position, qpcPosition, frequency )
+                                       - 演奏開始位置の先頭からの時間sec;                // 「+」じゃないので注意!
                        }
                        //----------------
                        #endregion
@@ -205,7 +211,7 @@ namespace SST.ステージ.演奏
                                // 背景動画が再生されているのにBGMがまだ再生されていないなら、再生を開始する。
                                if( false == this.BGM再生開始済み )
                                {
-                                       this.BGM?.再生を開始する();
+                                       this.BGM?.Play();
                                        this.BGM再生開始済み = true;
                                }
                        }
@@ -259,7 +265,7 @@ namespace SST.ステージ.演奏
                {
                        if( null != this.BGM )  // 背景動画がなければ BGM も null である
                        {
-                               StrokeStyleT.Wasapiデバイス.サウンドをミキサーから削除する( this.BGM );
+                               this.BGM.Stop();
                                FDK.Utilities.解放する( ref this.BGM );
                        }
                }
@@ -270,7 +276,7 @@ namespace SST.ステージ.演奏
                protected FDK.同期.RWLock<double> 現在進行描画中の譜面スクロール速度の倍率 = new FDK.同期.RWLock<double>( 0.0 );
                protected double 演奏開始時刻sec = 0.0;
                protected bool Autoチップのドラム音を再生する = true;
-               protected readonly FDK.メディア.サウンド.WASAPIold.SoundTimer サウンドタイマ = new FDK.メディア.サウンド.WASAPIold.SoundTimer();
+               protected readonly FDK.メディア.サウンド.WASAPI.SoundTimer サウンドタイマ = new FDK.メディア.サウンド.WASAPI.SoundTimer();
                protected readonly SST.ステージ.演奏.コンボ コンボ;
                protected readonly SST.ステージ.演奏.レーンフレーム レーンフレーム;
                protected readonly SST.ステージ.演奏.スクロール譜面 スクロール譜面;
@@ -285,7 +291,7 @@ namespace SST.ステージ.演奏
                /// 解放は、演奏ステージクラスの非活性化後に、外部から行われる。
                /// <see cref="SST.ステージ.演奏.演奏ステージ.BGMを解放する"/>
                /// </remarks>
-               protected FDK.メディア.サウンド.WASAPIold.Sound BGM = null;
+               protected FDK.メディア.サウンド.WASAPI.Sound BGM = null;
                protected FDK.カウンタ.FPS FPS = null;
                /// <summary>
                /// 動的子Activity。背景動画を再生しない場合は null のまま。
@@ -294,7 +300,10 @@ namespace SST.ステージ.演奏
 
                private double 現在の演奏時刻secを返す()
                {
-                       return this.サウンドタイマ.現在のデバイス位置secを取得する( StrokeStyleT.Wasapiデバイス.AudioClock ) - this.演奏開始時刻sec;
+                       long position, qpcPosition, frequency;
+                       StrokeStyleT.サウンドデバイス.GetClock( out position, out qpcPosition, out frequency );
+
+                       return this.サウンドタイマ.現在のデバイス位置secを取得する( position, qpcPosition, frequency ) - this.演奏開始時刻sec;
                }
        }
 }