2 using System.Collections.Generic;
3 using System.Diagnostics;
11 class ドラムサウンド : FDK.Activity
17 protected override void On活性化( デバイスリソース dr )
22 protected override void On非活性化( デバイスリソース dr )
24 this._すべてのコンテキストを初期化する();
27 public void 発声する( SSTFormat.チップ種別 chipType, float 音量0to1 )
31 if( false == this._チップtoコンテキスト.ContainsKey( chipType ) )
32 return; // コンテキスト未登録のチップなら何もしない。
33 var context = this._チップtoコンテキスト[ chipType ];
35 // 現在発声中のサウンドを全部止めるチップ種別の場合は止める。
36 if( 0 != chipType.排他発声グループID() ) // ID = 0 は対象外。
38 // 消音対象のコンテキストの Sounds[] を select する。
40 from kvp in this._チップtoコンテキスト
41 where ( chipType.直前のチップを消音する( kvp.Key ) )
42 select kvp.Value.Sounds;
44 // 集めた Sounds[] をすべて停止する。
45 foreach( var sounds in 停止するサウンド群 )
46 foreach( var sound in sounds )
51 if( null != context.Sounds[ context.次に再生するSound番号 ] )
53 context.Sounds[ context.次に再生するSound番号 ].Volume = 音量0to1;
54 context.Sounds[ context.次に再生するSound番号 ].Play();
58 context.次に再生するSound番号++;
59 if( context.次に再生するSound番号 >= ドラムサウンド._多重度 )
60 context.次に再生するSound番号 = 0;
64 private const int _多重度 = 2;
66 private class Cコンテキスト : IDisposable
68 public FDK.メディア.サウンド.WASAPI.Sound[] Sounds = new FDK.メディア.サウンド.WASAPI.Sound[ ドラムサウンド._多重度 ];
69 public int 次に再生するSound番号 = 0;
73 if( null != this.Sounds )
75 for( int i = 0; i < this.Sounds.Length; i++ )
77 this.Sounds[ i ].Stop();
78 FDK.Utilities.解放する( ref this.Sounds[ i ] );
84 private Dictionary<SSTFormat.チップ種別, Cコンテキスト> _チップtoコンテキスト = null;
86 private readonly string _KitXmlファイルパス = @"$(Static)\sounds\Kit.xml";
88 private readonly object _スレッド間同期 = new object();
90 private void _すべてのコンテキストを初期化する()
93 if( null != this._チップtoコンテキスト )
95 foreach( var kvp in this._チップtoコンテキスト )
96 ( (Cコンテキスト) kvp.Value ).Dispose();
100 this._チップtoコンテキスト = new Dictionary<SSTFormat.チップ種別, Cコンテキスト>();
103 private void _KitXmlを読み込む()
105 this._すべてのコンテキストを初期化する();
107 string ファイルパス = FDK.フォルダ.絶対パスに含まれるフォルダ変数を展開して返す( this._KitXmlファイルパス );
109 if( false == File.Exists( ファイルパス ) )
111 FDK.Log.WARNING( $"Kit ファイルが存在しません。ドラムサウンドは生成されません。[{this._KitXmlファイルパス}]" );
117 var xml文書 = XDocument.Load( ファイルパス );
120 var Root要素 = xml文書.Element( nameof( XML.Root ) );
123 var DrumKit要素 = Root要素.Element( nameof( XML.DrumKit ) ); // 最初の1つのみサポート。
124 var DrumKit要素のVersion属性 = DrumKit要素.Attribute( nameof( XML.Version ) );
125 var DrumKit要素のName属性 = DrumKit要素.Attribute( nameof( XML.Name ) ); // 現在は未使用。
126 if( "1.2" == DrumKit要素のVersion属性.Value )
128 #region " DrumKit ver1.2 "
130 foreach( var DrumKitの子要素 in DrumKit要素.Elements() )
132 switch( DrumKitの子要素.Name.LocalName )
135 case nameof( XML.Sound ):
136 // Name="..." 属性の値は、SSTFormat.チップ種別 の各メンバの名前に等しいものとする。
137 var Sound要素のName属性 = DrumKitの子要素.Attribute( nameof( XML.Name ) );
138 var チップ種別 = SSTFormat.チップ種別.Unknown;
139 if( Enum.TryParse( Sound要素のName属性.Value, out チップ種別 ) )
141 string サウンドファイルパス = Path.Combine( StrokeStyleT.フォルダ.StaticFolder + @"\sounds\", DrumKitの子要素.Value );
142 if( File.Exists( サウンドファイルパス ) )
144 // すでに辞書に存在してるなら、解放して削除する。
145 if( this._チップtoコンテキスト.ContainsKey( チップ種別 ) )
147 this._チップtoコンテキスト[ チップ種別 ]?.Dispose();
148 this._チップtoコンテキスト.Remove( チップ種別 );
152 var context = new Cコンテキスト() {
153 Sounds = new FDK.メディア.サウンド.WASAPI.Sound[ ドラムサウンド._多重度 ],
158 for( int i = 0; i < context.Sounds.Length; i++ )
159 context.Sounds[ i ] = StrokeStyleT.サウンドデバイス.CreateSound( サウンドファイルパス );
162 this._チップtoコンテキスト.Add( チップ種別, context );
166 FDK.Log.WARNING( $"サウンドファイル {FDK.フォルダ.絶対パスをフォルダ変数付き絶対パスに変換して返す( サウンドファイルパス )} が存在しません。[{this._KitXmlファイルパス}]" );
171 FDK.Log.WARNING( $"未知の要素 {Sound要素のName属性.Value} をスキップします。[{this._KitXmlファイルパス}]" );
183 FDK.Log.ERROR( $"Kitファイルの読み込みに失敗しました。{e.Message}[{this._KitXmlファイルパス}]" );