2 using System.Collections.Generic;
3 using System.Diagnostics;
11 class ドラムサウンド : FDK.Activity
16 protected override void On活性化( デバイスリソース dr )
20 protected override void On非活性化( デバイスリソース dr )
22 this.すべてのコンテキストを初期化する();
24 public void 発声する( SSTFormat.チップ種別 chipType, float 音量0to1 )
28 if( false == this.チップtoコンテキスト.ContainsKey( chipType ) )
29 return; // コンテキスト未登録のチップなら何もしない。
30 var context = this.チップtoコンテキスト[ chipType ];
32 // 現在発声中のサウンドを全部止めるチップ種別の場合は止める。
33 if( 0 != chipType.排他発声グループID() ) // ID = 0 は対象外。
35 // 同じ排他発声グループIDを持つコンテキストの Sounds[] を select する。
37 from kvp in this.チップtoコンテキスト
38 where ( kvp.Key.排他発声グループID() == chipType.排他発声グループID() )
39 select kvp.Value.Sounds;
41 // 集めた Sounds[] をすべて停止する。
42 foreach( var sounds in 停止するサウンド群 )
43 foreach( var sound in sounds )
48 if( null != context.Sounds[ context.次に再生するSound番号 ] )
50 context.Sounds[ context.次に再生するSound番号 ].音量 = 音量0to1;
51 context.Sounds[ context.次に再生するSound番号 ].再生を開始する();
55 context.次に再生するSound番号++;
56 if( context.次に再生するSound番号 >= ドラムサウンド.多重度 )
57 context.次に再生するSound番号 = 0;
61 protected const int 多重度 = 2;
62 protected readonly string KitXmlファイルパス = @"$(Static)\sounds\Kit.xml";
63 protected class Cコンテキスト : IDisposable
65 public FDK.メディア.サウンド.WASAPIold.Sound[] Sounds = new FDK.メディア.サウンド.WASAPIold.Sound[ ドラムサウンド.多重度 ];
66 public int 次に再生するSound番号 = 0;
70 if( null != this.Sounds )
72 for( int i = 0; i < this.Sounds.Length; i++ )
74 StrokeStyleT.Wasapiデバイス.サウンドをミキサーから削除する( this.Sounds[ i ] );
75 FDK.Utilities.解放する( ref this.Sounds[ i ] );
80 protected Dictionary<SSTFormat.チップ種別, Cコンテキスト> チップtoコンテキスト = null;
82 private void すべてのコンテキストを初期化する()
85 if( null != this.チップtoコンテキスト )
87 foreach( var kvp in this.チップtoコンテキスト )
88 ( (Cコンテキスト) kvp.Value ).Dispose();
92 this.チップtoコンテキスト = new Dictionary<SSTFormat.チップ種別, Cコンテキスト>();
94 private void KitXmlを読み込む()
96 this.すべてのコンテキストを初期化する();
98 string ファイルパス = FDK.フォルダ.絶対パスに含まれるフォルダ変数を展開して返す( this.KitXmlファイルパス );
100 if( false == File.Exists( ファイルパス ) )
102 FDK.Log.WARNING( $"Kit ファイルが存在しません。ドラムサウンドは生成されません。[{this.KitXmlファイルパス}]" );
108 var xml文書 = XDocument.Load( ファイルパス );
111 var Root要素 = xml文書.Element( nameof( XML.Root ) );
114 var DrumKit要素 = Root要素.Element( nameof( XML.DrumKit ) ); // 最初の1つのみサポート。
115 var DrumKit要素のVersion属性 = DrumKit要素.Attribute( nameof( XML.Version ) );
116 var DrumKit要素のName属性 = DrumKit要素.Attribute( nameof( XML.Name ) ); // 現在は未使用。
117 if( "1.2" == DrumKit要素のVersion属性.Value )
119 #region " DrumKit ver1.2 "
121 foreach( var DrumKitの子要素 in DrumKit要素.Elements() )
123 switch( DrumKitの子要素.Name.LocalName )
126 case nameof( XML.Sound ):
127 // Name="..." 属性の値は、SSTFormat.チップ種別 の各メンバの名前に等しいものとする。
128 var Sound要素のName属性 = DrumKitの子要素.Attribute( nameof( XML.Name ) );
129 var チップ種別 = SSTFormat.チップ種別.Unknown;
130 if( Enum.TryParse( Sound要素のName属性.Value, out チップ種別 ) )
132 string サウンドファイルパス = Path.Combine( StrokeStyleT.フォルダ.StaticFolder + @"\sounds\", DrumKitの子要素.Value );
133 if( File.Exists( サウンドファイルパス ) )
135 // すでに辞書に存在してるなら、解放して削除する。
136 if( this.チップtoコンテキスト.ContainsKey( チップ種別 ) )
138 this.チップtoコンテキスト[ チップ種別 ]?.Dispose();
139 this.チップtoコンテキスト.Remove( チップ種別 );
143 var context = new Cコンテキスト() {
144 Sounds = new FDK.メディア.サウンド.WASAPIold.Sound[ ドラムサウンド.多重度 ],
147 for( int i = 0; i < context.Sounds.Length; i++ )
149 // 多重度分のサウンドを生成しつつ、ミキサーにも登録。
150 context.Sounds[ i ] = new FDK.メディア.サウンド.WASAPIold.Sound( サウンドファイルパス );
151 StrokeStyleT.Wasapiデバイス.サウンドをミキサーに追加する( context.Sounds[ i ] );
155 this.チップtoコンテキスト.Add( チップ種別, context );
159 FDK.Log.WARNING( $"サウンドファイル {FDK.フォルダ.絶対パスをフォルダ変数付き絶対パスに変換して返す( サウンドファイルパス )} が存在しません。[{this.KitXmlファイルパス}]" );
164 FDK.Log.WARNING( $"未知の要素 {Sound要素のName属性.Value} をスキップします。[{this.KitXmlファイルパス}]" );
176 FDK.Log.ERROR( $"Kitファイルの読み込みに失敗しました。{e.Message}[{this.KitXmlファイルパス}]" );
180 private readonly object スレッド間同期 = new object();