OSDN Git Service

#37189 DirectSoundモード時にサウンド読み込みが遅かった問題を修正。
[dtxmania/dtxmania.git] / DTXMania / コード / スコア、曲 / CDTX.cs
1 using System;
2 using System.Collections.Generic;
3 using System.Text;
4 using System.Runtime.InteropServices;
5 using System.Drawing;
6 using System.Diagnostics;
7 using System.IO;
8 using System.Security.Cryptography;
9 using System.Reflection;
10 using System.Globalization;
11 using System.Threading;
12 using FDK;
13
14 namespace DTXMania
15 {
16         /// <summary>
17         /// CDTX 内で用いる入れ子型を partial にし、ここで定義します。
18         /// </summary>
19         public partial class CDTX : CActivity
20         {
21                 // プロパティ
22                 public int nBGMAdjust
23                 {
24                         get;
25                         private set;
26                 }
27                 public string ARTIST;
28                 public string BACKGROUND;
29                 public string BACKGROUND_GR;
30                 public double BASEBPM;
31                 public bool BLACKCOLORKEY;
32                 public double BPM;
33                 public STチップがある bチップがある;
34                 public string COMMENT;
35                 public double db再生速度;
36                 public EDTX種別 e種別;
37                 public string GENRE;
38                 public bool HIDDENLEVEL;
39                 public STDGBSValue<int> LEVEL;
40                 public Dictionary<int, CAVI> listAVI;
41                 public Dictionary<int, CAVIPAN> listAVIPAN;
42                 public Dictionary<int, CBGA> listBGA;
43                 public Dictionary<int, CBGAPAN> listBGAPAN;
44                 public Dictionary<int, CBMP> listBMP;
45                 public Dictionary<int, CBMPTEX> listBMPTEX;
46                 public Dictionary<int, CBPM> listBPM;
47                 public List<CChip> listChip;
48                 public Dictionary<int, CWAV> listWAV;
49                 public string MIDIFILE;
50                 public bool MIDINOTE;
51                 public int MIDIレベル;
52                 public STDGBSValue<int> n可視チップ数;
53                 public const int n最大音数 = 4;
54                 public const int n小節の解像度 = 384;
55                 public string PANEL;
56                 public string PATH_WAV;
57                 public string PREIMAGE;
58                 public string PREMOVIE;
59                 public string PREVIEW;
60                 public STRESULT RESULTIMAGE;
61                 public STRESULT RESULTMOVIE;
62                 public STRESULT RESULTSOUND;
63                 public string SOUND_AUDIENCE;
64                 public string SOUND_FULLCOMBO;
65                 public string SOUND_NOWLOADING;
66                 public string SOUND_STAGEFAILED;
67                 public string STAGEFILE;
68                 public string strハッシュofDTXファイル;
69                 public string strファイル名;
70                 public string strファイル名の絶対パス;
71                 public string strフォルダ名;
72                 public string TITLE;
73                 public double dbDTXVPlaySpeed;
74                 public bool bMovieをFullscreen再生する;
75                 public bool bUse556x710BGAAVI;
76                 public STDGBSValue<List<int>> listAutoGhostLag;
77                 public STDGBSValue<List<int>> listTargetGhsotLag;
78                 public STDGBSValue<EUseLanes> n使用レーン数;
79
80 #if TEST_NOTEOFFMODE
81                 public STLANEVALUE<bool> b演奏で直前の音を消音する;
82 //              public bool bHH演奏で直前のHHを消音する;
83 //              public bool bGUITAR演奏で直前のGUITARを消音する;
84 //              public bool bBASS演奏で直前のBASSを消音する;
85 #endif
86                 #region [ コンストラクタ ]
87
88                 private CDTX()
89                 {
90                         this.TITLE = "";
91                         this.ARTIST = "";
92                         this.COMMENT = "";
93                         this.PANEL = "";
94                         this.GENRE = "";
95                         this.PREVIEW = "";
96                         this.PREIMAGE = "";
97                         this.PREMOVIE = "";
98                         this.STAGEFILE = "";
99                         this.BACKGROUND = "";
100                         this.BACKGROUND_GR = "";
101                         this.PATH_WAV = "";
102                         this.MIDIFILE = "";
103                         this.SOUND_STAGEFAILED = "";
104                         this.SOUND_FULLCOMBO = "";
105                         this.SOUND_NOWLOADING = "";
106                         this.SOUND_AUDIENCE = "";
107                         this.BPM = 120.0;
108                         this.BLACKCOLORKEY = true;
109                         STDGBSValue<int> stdgbvalue = new STDGBSValue<int>();
110                         stdgbvalue.Drums = 0;
111                         stdgbvalue.Guitar = 0;
112                         stdgbvalue.Bass = 0;
113                         this.LEVEL = stdgbvalue;
114                         for (int i = 0; i < 7; i++)
115                         {
116                                 this.RESULTIMAGE[i] = "";
117                                 this.RESULTMOVIE[i] = "";
118                                 this.RESULTSOUND[i] = "";
119                         }
120                         this.db再生速度 = 1.0;
121                         this.strハッシュofDTXファイル = "";
122                         this.bチップがある = new STチップがある();
123                         this.bチップがある.Drums = false;
124                         this.bチップがある.Guitar = false;
125                         this.bチップがある.Bass = false;
126                         this.bチップがある.HHOpen = false;
127                         this.bチップがある.Ride = false;
128                         this.bチップがある.LeftCymbal = false;
129                         this.bチップがある.OpenGuitar = false;
130                         this.bチップがある.OpenBass = false;
131                         this.bチップがある.BGA = false;
132                         this.bチップがある.Movie = false;
133                         this.bチップがある.LeftPedal = false;
134                         this.bチップがある.LeftBassDrum = false;
135                         this.bMovieをFullscreen再生する = false;
136                         this.strファイル名 = "";
137                         this.strフォルダ名 = "";
138                         this.strファイル名の絶対パス = "";
139                         this.n無限管理WAV = new int[36 * 36];
140                         this.n無限管理BPM = new int[36 * 36];
141                         this.n無限管理VOL = new int[36 * 36];
142                         this.n無限管理PAN = new int[36 * 36];
143                         this.n無限管理SIZE = new int[36 * 36];
144                         this.nRESULTIMAGE用優先順位 = new int[7];
145                         this.nRESULTMOVIE用優先順位 = new int[7];
146                         this.nRESULTSOUND用優先順位 = new int[7];
147                         this.listAutoGhostLag = new STDGBSValue<List<int>>();
148                         this.listTargetGhsotLag = new STDGBSValue<List<int>>();
149
150                         #region [ 2011.1.1 yyagi GDA->DTX変換テーブル リファクタ後 ]
151                         STGDAPARAM[] stgdaparamArray = new STGDAPARAM[] {               // GDA->DTX conversion table
152                                 new STGDAPARAM("TC", EChannel.BPM),
153                                 new STGDAPARAM("BL", EChannel.BarLength),
154                                 new STGDAPARAM("GS", EChannel.flowspeed_gt_nouse),
155                                 new STGDAPARAM("DS", EChannel.flowspeed_dr_nouse),
156                                 new STGDAPARAM("FI", EChannel.FillIn),
157                                 new STGDAPARAM("HH", EChannel.HiHatClose),
158                                 new STGDAPARAM("SD", EChannel.Snare),
159                                 new STGDAPARAM("BD", EChannel.BassDrum),
160                                 new STGDAPARAM("HT", EChannel.HighTom),
161                                 new STGDAPARAM("LT", EChannel.LowTom),
162                                 new STGDAPARAM("CY", EChannel.Cymbal),
163                                 new STGDAPARAM("G1", EChannel.Guitar_xxB),
164                                 new STGDAPARAM("G2", EChannel.Guitar_xGx),
165                                 new STGDAPARAM("G3", EChannel.Guitar_xGB),
166                                 new STGDAPARAM("G4", EChannel.Guitar_Rxx),
167                                 new STGDAPARAM("G5", EChannel.Guitar_RxB),
168                                 new STGDAPARAM("G6", EChannel.Guitar_RGx),
169                                 new STGDAPARAM("G7", EChannel.Guitar_RGB),
170                                 new STGDAPARAM("GW", EChannel.Guitar_Wailing),
171                                 new STGDAPARAM("01", EChannel.SE01),
172                                 new STGDAPARAM("02", EChannel.SE02),
173                                 new STGDAPARAM("03", EChannel.SE03),
174                                 new STGDAPARAM("04", EChannel.SE04),
175                                 new STGDAPARAM("05", EChannel.SE05),
176                                 new STGDAPARAM("06", EChannel.SE06),
177                                 new STGDAPARAM("07", EChannel.SE07),
178                                 new STGDAPARAM("08", EChannel.SE08),
179                                 new STGDAPARAM("09", EChannel.SE09),
180                                 new STGDAPARAM("0A", EChannel.SE10),
181                                 new STGDAPARAM("0B", EChannel.SE11),
182                                 new STGDAPARAM("0C", EChannel.SE12),
183                                 new STGDAPARAM("0D", EChannel.SE13),
184                                 new STGDAPARAM("0E", EChannel.SE14),
185                                 new STGDAPARAM("0F", EChannel.SE15),
186                                 new STGDAPARAM("10", EChannel.SE16),
187                                 new STGDAPARAM("11", EChannel.SE17),
188                                 new STGDAPARAM("12", EChannel.SE18),
189                                 new STGDAPARAM("13", EChannel.SE19),
190                                 new STGDAPARAM("14", EChannel.SE20),
191                                 new STGDAPARAM("15", EChannel.SE21),
192                                 new STGDAPARAM("16", EChannel.SE22),
193                                 new STGDAPARAM("17", EChannel.SE23),
194                                 new STGDAPARAM("18", EChannel.SE24),
195                                 new STGDAPARAM("19", EChannel.SE25),
196                                 new STGDAPARAM("1A", EChannel.SE26),
197                                 new STGDAPARAM("1B", EChannel.SE27),
198                                 new STGDAPARAM("1C", EChannel.SE28),
199                                 new STGDAPARAM("1D", EChannel.SE29),
200                                 new STGDAPARAM("1E", EChannel.SE30),
201                                 new STGDAPARAM("1F", EChannel.SE31),
202                                 new STGDAPARAM("20", EChannel.SE32),
203                                 new STGDAPARAM("B1", EChannel.Bass_xxB),
204                                 new STGDAPARAM("B2", EChannel.Bass_xGx),
205                                 new STGDAPARAM("B3", EChannel.Bass_xGB),
206                                 new STGDAPARAM("B4", EChannel.Bass_Rxx),
207                                 new STGDAPARAM("B5", EChannel.Bass_RxB),
208                                 new STGDAPARAM("B6", EChannel.Bass_RGx),
209                                 new STGDAPARAM("B7", EChannel.Bass_RGB),
210                                 new STGDAPARAM("BW", EChannel.Bass_Wailing),
211                                 new STGDAPARAM("G0", EChannel.Guitar_Open),
212                                 new STGDAPARAM("B0", EChannel.Bass_Open)
213                         };
214                         this.stGDAParam = stgdaparamArray;
215                         #endregion
216                         this.nBGMAdjust = 0;
217                         this.nPolyphonicSounds = CDTXMania.Instance.ConfigIni.nPolyphonicSounds;
218                         this.dbDTXVPlaySpeed = 1.0f;
219                         this.bUse556x710BGAAVI = false;
220                         this.n使用レーン数 = new STDGBSValue<EUseLanes>();
221
222 #if TEST_NOTEOFFMODE
223                         this.bHH演奏で直前のHHを消音する = true;
224                         this.bGUITAR演奏で直前のGUITARを消音する = true;
225                         this.bBASS演奏で直前のBASSを消音する = true;
226 #endif
227
228                 }
229                 private CDTX(string str全入力文字列)
230                         : this()
231                 {
232                         this.On活性化();
233                         this.t入力_全入力文字列から(str全入力文字列);
234                 }
235                 public CDTX(string strファイル名, bool bヘッダのみ)
236                         : this()
237                 {
238                         this.On活性化();
239                         this.t入力(strファイル名, bヘッダのみ);
240                 }
241                 private CDTX(string str全入力文字列, double db再生速度, int nBGMAdjust)
242                         : this()
243                 {
244                         this.On活性化();
245                         this.t入力_全入力文字列から(str全入力文字列, db再生速度, nBGMAdjust);
246                 }
247                 public CDTX(string strファイル名, bool bヘッダのみ, double db再生速度, int nBGMAdjust)
248                         : this()
249                 {
250                         this.On活性化();
251                         this.t入力(strファイル名, bヘッダのみ, db再生速度, nBGMAdjust);
252                 }
253                 #endregion
254
255
256                 // メソッド
257
258                 public int nモニタを考慮した音量(EPart part)
259                 {
260                         switch (part)
261                         {
262                                 case EPart.Drums:
263                                         if (CDTXMania.Instance.ConfigIni.bEmphasizePlaySound.Drums)
264                                         {
265                                                 return CDTXMania.Instance.ConfigIni.nAutoVolume;
266                                         }
267                                         return CDTXMania.Instance.ConfigIni.nChipVolume;
268
269                                 case EPart.Guitar:
270                                         if (CDTXMania.Instance.ConfigIni.bEmphasizePlaySound.Guitar)
271                                         {
272                                                 return CDTXMania.Instance.ConfigIni.nAutoVolume;
273                                         }
274                                         return CDTXMania.Instance.ConfigIni.nChipVolume;
275
276                                 case EPart.Bass:
277                                         if (CDTXMania.Instance.ConfigIni.bEmphasizePlaySound.Bass)
278                                         {
279                                                 return CDTXMania.Instance.ConfigIni.nAutoVolume;
280                                         }
281                                         return CDTXMania.Instance.ConfigIni.nChipVolume;
282                         }
283                         if ((!CDTXMania.Instance.ConfigIni.bEmphasizePlaySound.Drums && !CDTXMania.Instance.ConfigIni.bEmphasizePlaySound.Guitar) && !CDTXMania.Instance.ConfigIni.bEmphasizePlaySound.Bass)
284                         {
285                                 return CDTXMania.Instance.ConfigIni.nChipVolume;
286                         }
287                         return CDTXMania.Instance.ConfigIni.nAutoVolume;
288                 }
289                 public void tAVIの読み込み()
290                 {
291                         if (this.listAVI != null)
292                         {
293                                 foreach (CAVI cavi in this.listAVI.Values)
294                                 {
295                                         cavi.OnDeviceCreated();
296                                 }
297                         }
298                         if (!this.bヘッダのみ)
299                         {
300                                 foreach (CChip chip in this.listChip)
301                                 {
302                                         chip.ApplyAVI(listAVI, listAVIPAN);
303                                 }
304                         }
305                 }
306                 #region [ BMP/BMPTEXの並列読み込み・デコード用メソッド ]
307                 delegate void BackgroundBMPLoadAll(Dictionary<int, CBMP> listB);
308                 static BackgroundBMPLoadAll backgroundBMPLoadAll = new BackgroundBMPLoadAll(BMPLoadAll);
309                 delegate void BackgroundBMPTEXLoadAll(Dictionary<int, CBMPTEX> listB);
310                 static BackgroundBMPTEXLoadAll backgroundBMPTEXLoadAll = new BackgroundBMPTEXLoadAll(BMPTEXLoadAll);
311                 private static void LoadTexture(CBMPbase cbmp)            // バックグラウンドスレッドで動作する、ファイル読み込み部
312                 {
313                         string filename = cbmp.GetFullPathname;
314                         if (!File.Exists(filename))
315                         {
316                                 Trace.TraceWarning("ファイルが存在しません。({0})", filename);
317                                 cbmp.bitmap = null;
318                                 return;
319                         }
320                         try
321                         {
322                                 cbmp.bitmap = new Bitmap(filename);
323                         }
324                         catch (ArgumentException)
325                         {
326                                 Trace.TraceWarning("引数が不正です。ファイルが破損している可能性があります。({0})", filename);
327                                 cbmp.bitmap = null;
328                                 return;
329                         }
330                 }
331                 private static void BMPLoadAll(Dictionary<int, CBMP> listB) // バックグラウンドスレッドで、テクスチャファイルをひたすら読み込んではキューに追加する
332                 {
333                         //Trace.TraceInformation( "Back: ThreadID(BMPLoad)=" + Thread.CurrentThread.ManagedThreadId + ", listCount=" + listB.Count  );
334                         foreach (CBMPbase cbmp in listB.Values)
335                         {
336                                 LoadTexture(cbmp);
337                                 lock (lockQueue)
338                                 {
339                                         queueCBMPbaseDone.Enqueue(cbmp);
340                                         //  Trace.TraceInformation( "Back: Enqueued(" + queueCBMPbaseDone.Count + "): " + cbmp.strファイル名 );
341                                 }
342                                 if (queueCBMPbaseDone.Count > 8)
343                                 {
344                                         Thread.Sleep(10);
345                                 }
346                         }
347                 }
348                 private static void BMPTEXLoadAll(Dictionary<int, CBMPTEX> listB) // ダサい実装だが、Dictionary<>の中には手を出せず、妥協した
349                 {
350                         //Trace.TraceInformation( "Back: ThreadID(BMPLoad)=" + Thread.CurrentThread.ManagedThreadId + ", listCount=" + listB.Count  );
351                         foreach (CBMPbase cbmp in listB.Values)
352                         {
353                                 LoadTexture(cbmp);
354                                 lock (lockQueue)
355                                 {
356                                         queueCBMPbaseDone.Enqueue(cbmp);
357                                         //  Trace.TraceInformation( "Back: Enqueued(" + queueCBMPbaseDone.Count + "): " + cbmp.strファイル名 );
358                                 }
359                                 if (queueCBMPbaseDone.Count > 8)
360                                 {
361                                         Thread.Sleep(10);
362                                 }
363                         }
364                 }
365
366                 private static Queue<CBMPbase> queueCBMPbaseDone = new Queue<CBMPbase>();
367                 private static object lockQueue = new object();
368                 private static int nLoadDone;
369                 #endregion
370
371                 public void tBMP_BMPTEXの読み込み()
372                 {
373                         #region [ CPUコア数の取得 ]
374                         CWin32.SYSTEM_INFO sysInfo = new CWin32.SYSTEM_INFO();
375                         CWin32.GetSystemInfo(ref sysInfo);
376                         int nCPUCores = (int)sysInfo.dwNumberOfProcessors;
377                         #endregion
378                         #region [ BMP読み込み ]
379                         if (this.listBMP != null)
380                         {
381                                 if (nCPUCores <= 1)
382                                 {
383                                         #region [ シングルスレッドで逐次読み出し・デコード・テクスチャ定義 ]
384                                         foreach (CBMP cbmp in this.listBMP.Values)
385                                         {
386                                                 cbmp.OnDeviceCreated();
387                                         }
388                                         #endregion
389                                 }
390                                 else
391                                 {
392                                         #region [ メインスレッド(テクスチャ定義)とバックグラウンドスレッド(読み出し・デコード)を並列動作させ高速化 ]
393                                         //Trace.TraceInformation( "Main: ThreadID(Main)=" + Thread.CurrentThread.ManagedThreadId + ", listCount=" + this.listBMP.Count );
394                                         nLoadDone = 0;
395                                         backgroundBMPLoadAll.BeginInvoke(listBMP, null, null);
396
397                                         // t.Priority = ThreadPriority.Lowest;
398                                         // t.Start( listBMP );
399                                         int c = listBMP.Count;
400                                         while (nLoadDone < c)
401                                         {
402                                                 if (queueCBMPbaseDone.Count > 0)
403                                                 {
404                                                         CBMP cbmp;
405                                                         //Trace.TraceInformation( "Main: Lock Begin for dequeue1." );
406                                                         try
407                                                         {
408                                                                 lock (lockQueue)
409                                                                 {
410                                                                         cbmp = (CBMP)queueCBMPbaseDone.Dequeue();
411                                                                         //  Trace.TraceInformation( "Main: Dequeued(" + queueCBMPbaseDone.Count + "): " + cbmp.strファイル名 );
412                                                                 }
413                                                                 cbmp.OnDeviceCreated(cbmp.bitmap, cbmp.GetFullPathname);
414                                                         }
415                                                         catch (InvalidCastException)  // bmp読み込み失敗時は、キャストに失敗する
416                                                         {
417                                                         }
418                                                         finally
419                                                         {
420                                                                 nLoadDone++;
421                                                         }
422                                                         //Trace.TraceInformation( "Main: OnDeviceCreated: " + cbmp.strファイル名 );
423                                                 }
424                                                 else
425                                                 {
426                                                         //Trace.TraceInformation( "Main: Sleeped.");
427                                                         Thread.Sleep(5);  // WaitOneのイベント待ちにすると、メインスレッド処理中に2個以上イベント完了したときにそれを正しく検出できなくなるので、
428                                                 }           // ポーリングに逃げてしまいました。
429                                         }
430                                         #endregion
431                                 }
432                         }
433                         #endregion
434                         #region [ BMPTEX読み込み ]
435                         if (this.listBMPTEX != null)
436                         {
437                                 if (nCPUCores <= 1)
438                                 {
439                                         #region [ シングルスレッドで逐次読み出し・デコード・テクスチャ定義 ]
440                                         foreach (CBMPTEX cbmptex in this.listBMPTEX.Values)
441                                         {
442                                                 cbmptex.OnDeviceCreated();
443                                         }
444                                         #endregion
445                                 }
446                                 else
447                                 {
448                                         #region [ メインスレッド(テクスチャ定義)とバックグラウンドスレッド(読み出し・デコード)を並列動作させ高速化 ]
449                                         //Trace.TraceInformation( "Main: ThreadID(Main)=" + Thread.CurrentThread.ManagedThreadId + ", listCount=" + this.listBMP.Count );
450                                         nLoadDone = 0;
451                                         backgroundBMPTEXLoadAll.BeginInvoke(listBMPTEX, null, null);
452                                         int c = listBMPTEX.Count;
453                                         while (nLoadDone < c)
454                                         {
455                                                 if (queueCBMPbaseDone.Count > 0)
456                                                 {
457                                                         CBMPTEX cbmptex;
458                                                         //Trace.TraceInformation( "Main: Lock Begin for dequeue1." );
459                                                         try
460                                                         {
461                                                                 lock (lockQueue)
462                                                                 {
463                                                                         cbmptex = (CBMPTEX)queueCBMPbaseDone.Dequeue();
464                                                                         //  Trace.TraceInformation( "Main: Dequeued(" + queueCBMPbaseDone.Count + "): " + cbmp.strファイル名 );
465                                                                 }
466                                                                 cbmptex.OnDeviceCreated(cbmptex.bitmap, cbmptex.GetFullPathname);
467                                                         }
468                                                         catch (InvalidCastException)
469                                                         {
470                                                         }
471                                                         finally
472                                                         {
473                                                                 nLoadDone++;
474                                                         }
475                                                         //Trace.TraceInformation( "Main: OnDeviceCreated: " + cbmp.strファイル名 );
476                                                 }
477                                                 else
478                                                 {
479                                                         //Trace.TraceInformation( "Main: Sleeped.");
480                                                         Thread.Sleep(5);  // WaitOneのイベント待ちにすると、メインスレッド処理中に2個以上イベント完了したときにそれを正しく検出できなくなるので、
481                                                 }           // ポーリングに逃げてしまいました。
482                                         }
483                                         #endregion
484                                 }
485                         }
486                         #endregion
487                         if (!this.bヘッダのみ)
488                         {
489                                 foreach (CChip chip in this.listChip)
490                                 {
491                                         chip.ApplyBMP_BMPTEX(listBGA, listBGAPAN, listBMP, listBMPTEX);
492                                 }
493                         }
494                 }
495                 public void tWave再生位置自動補正()
496                 {
497                         foreach (CWAV cwav in this.listWAV.Values)
498                         {
499                                 this.tWave再生位置自動補正(cwav);
500                         }
501                 }
502                 public void tWave再生位置自動補正(CWAV wc)
503                 {
504                         if (wc.rSound[0] != null && wc.rSound[0].n総演奏時間ms >= 5000)
505                         {
506                                 for (int i = 0; i < nPolyphonicSounds; i++)
507                                 {
508                                         if ((wc.rSound[i] != null) && (wc.rSound[i].b再生中))
509                                         {
510                                                 long nCurrentTime = CSound管理.rc演奏用タイマ.nシステム時刻ms;
511                                                 if (nCurrentTime > wc.n再生開始時刻[i])
512                                                 {
513                                                         long nAbsTimeFromStartPlaying = nCurrentTime - wc.n再生開始時刻[i];
514                                                         //Trace.TraceInformation( "再生位置自動補正: {0}, 実タイマ値={1}, seek先={2}ms, 全音長={3}ms",
515                                                         //      Path.GetFileName( wc.rSound[ 0 ].strファイル名 ),
516                                                         //      nCurrentTime,
517                                                         //      nAbsTimeFromStartPlaying,
518                                                         //      wc.rSound[ 0 ].n総演奏時間ms
519                                                         //);
520                                                         // wc.rSound[ i ].t再生位置を変更する( wc.rSound[ i ].t時刻から位置を返す( nAbsTimeFromStartPlaying ) );
521                                                         wc.rSound[i].t再生位置を変更する(nAbsTimeFromStartPlaying);  // WASAPI/ASIO用
522                                                                                                                                                                                                                                                                         //Debug.WriteLine( "再生位置を変更: " + Path.GetFileName( wc.strファイル名 ) + nAbsTimeFromStartPlaying + "ms");
523                                                 }
524                                         }
525                                 }
526                         }
527                 }
528
529                 /// <summary>
530                 /// デバッグ用
531                 /// </summary>
532                 public void tWaveBGM再生位置表示()
533                 {
534                         foreach (CWAV wc in this.listWAV.Values)
535                         {
536                                 if (wc.rSound[0] != null && wc.rSound[0].n総演奏時間ms >= 5000)
537                                 {
538                                         for (int i = 0; i < nPolyphonicSounds; i++)
539                                         {
540                                                 if ((wc.rSound[i] != null) && (wc.rSound[i].b再生中))
541                                                 {
542                                                         long n位置byte;
543                                                         double db位置ms;
544                                                         wc.rSound[i].t再生位置を取得する(out n位置byte, out db位置ms);
545                                                         Trace.TraceInformation("再生位置: {0}, seek先={1}ms / {2}byte, 全音長={3}ms",
546                                                                 Path.GetFileName(wc.rSound[0].strファイル名),
547                                                                 db位置ms, n位置byte,
548                                                                 wc.rSound[0].n総演奏時間ms
549                                                         );
550                                                 }
551                                         }
552                                 }
553                         }
554                 }
555
556                 public void tWavの再生停止(int nWaveの内部番号)
557                 {
558                         tWavの再生停止(nWaveの内部番号, false);
559                 }
560                 public void tWavの再生停止(int nWaveの内部番号, bool bミキサーからも削除する)
561                 {
562                         if (this.listWAV.ContainsKey(nWaveの内部番号))
563                         {
564                                 CWAV cwav = this.listWAV[nWaveの内部番号];
565                                 for (int i = 0; i < nPolyphonicSounds; i++)
566                                 {
567                                         if (cwav.rSound[i] != null && cwav.rSound[i].b再生中)
568                                         {
569                                                 if (bミキサーからも削除する)
570                                                 {
571                                                         cwav.rSound[i].tサウンドを停止してMixerからも削除する();
572                                                 }
573                                                 else
574                                                 {
575                                                         cwav.rSound[i].t再生を停止する();
576                                                 }
577                                         }
578                                 }
579                         }
580                 }
581                 public void tWAVの読み込み(CWAV cwav)
582                 {
583                         //                      Trace.TraceInformation("WAV files={0}", this.listWAV.Count);
584                         //                      int count = 0;
585                         //                      foreach (CWAV cwav in this.listWAV.Values)
586                         {
587                                 //                              string strCount = count.ToString() + " / " + this.listWAV.Count.ToString();
588                                 //                              Debug.WriteLine(strCount);
589                                 //                              CDTXMania.Instance.app.act文字コンソール.tPrint(0, 0, C文字コンソール.Eフォント種別.白, strCount);
590                                 //                              count++;
591
592                                 string str = string.IsNullOrEmpty(this.PATH_WAV) ? this.strフォルダ名 : this.PATH_WAV;
593                                 str = str + cwav.strファイル名;
594                                 bool bIsDirectSound = (CDTXMania.Instance.Sound管理.GetCurrentSoundDeviceType() == "DirectSound");
595                                 try
596                                 {
597                                         //try
598                                         //{
599                                         //    cwav.rSound[ 0 ] = CDTXMania.Instance.app.Sound管理.tサウンドを生成する( str );
600                                         //    cwav.rSound[ 0 ].n音量 = 100;
601                                         //    if ( CDTXMania.Instance.app.ConfigIni.bLog作成解放ログ出力 )
602                                         //    {
603                                         //        Trace.TraceInformation( "サウンドを作成しました。({3})({0})({1})({2}bytes)", cwav.strコメント文, str, cwav.rSound[ 0 ].nサウンドバッファサイズ, cwav.rSound[ 0 ].bストリーム再生する ? "Stream" : "OnMemory" );
604                                         //    }
605                                         //}
606                                         //catch
607                                         //{
608                                         //    cwav.rSound[ 0 ] = null;
609                                         //    Trace.TraceError( "サウンドの作成に失敗しました。({0})({1})", cwav.strコメント文, str );
610                                         //}
611                                         //if ( cwav.rSound[ 0 ] == null )       // #xxxxx 2012.5.3 yyagi rSound[1-3]もClone()するようにし、これらのストリーム再生がおかしくなる問題を修正
612                                         //{
613                                         //    for ( int j = 1; j < nPolyphonicSounds; j++ )
614                                         //    {
615                                         //        cwav.rSound[ j ] = null;
616                                         //    }
617                                         //}
618                                         //else
619                                         //{
620                                         //    for ( int j = 1; j < nPolyphonicSounds; j++ )
621                                         //    {
622                                         //        cwav.rSound[ j ] = (CSound) cwav.rSound[ 0 ].Clone(); // #24007 2011.9.5 yyagi add: to accelerate loading chip sounds
623                                         //        CDTXMania.Instance.app.Sound管理.tサウンドを登録する( cwav.rSound[ j ] );
624                                         //    }
625                                         //}
626
627                                         // まず1つめを登録する
628                                         try
629                                         {
630                                                 cwav.rSound[0] = CDTXMania.Instance.Sound管理.tサウンドを生成する(str);
631                                                 cwav.rSound[0].n音量 = 100;
632                                                 if (!CDTXMania.Instance.ConfigIni.bDynamicBassMixerManagement)
633                                                 {
634                                                         cwav.rSound[0].tBASSサウンドをミキサーに追加する();
635                                                 }
636                                                 if (CDTXMania.Instance.ConfigIni.bLogCreateRelease)
637                                                 {
638                                                         Trace.TraceInformation("サウンドを作成しました。({3})({0})({1})({2}bytes)", cwav.strコメント文, str, cwav.rSound[0].nサウンドバッファサイズ, cwav.rSound[0].bストリーム再生する ? "Stream" : "OnMemory");
639                                                 }
640                                         }
641                                         catch (Exception e)
642                                         {
643                                                 cwav.rSound[0] = null;
644                                                 Trace.TraceError("サウンドの作成に失敗しました。({0})({1})", cwav.strコメント文, str);
645                                                 Trace.TraceError("例外: " + e.Message);
646                                         }
647
648                                         #region [ 同時発音数を、チャンネルによって変える ]
649                                         int nPoly = nPolyphonicSounds;
650                                         if (!bIsDirectSound)  // DShowでの再生の場合はミキシング負荷が高くないため、
651                                         {                                   // チップのライフタイム管理を行わない
652                                                 if (cwav.bIsBassSound) nPoly = (nPolyphonicSounds >= 2) ? 2 : 1;
653                                                 else if (cwav.bIsGuitarSound) nPoly = (nPolyphonicSounds >= 2) ? 2 : 1;
654                                                 else if (cwav.bIsSESound) nPoly = 1;
655                                                 else if (cwav.bIsBGMSound) nPoly = 1;
656                                         }
657                                         if (cwav.bIsBGMSound) nPoly = 1;
658                                         #endregion
659
660                                         // 残りはClone等で登録する
661                                         if (bIsDirectSound)     // DirectSoundでの再生の場合はCloneする
662                                         {
663                                                 for (int i = 1; i < nPoly; i++)
664                                                 {
665                                                         cwav.rSound[i] = (CSound)cwav.rSound[0].Clone();    // #24007 2011.9.5 yyagi add: to accelerate loading chip sounds
666                                                                                                                                                                 // CDTXMania.Instance.app.Sound管理.tサウンドを登録する( cwav.rSound[ j ] );
667                                                 }
668                                                 for (int i = nPoly; i < nPolyphonicSounds; i++)
669                                                 {
670                                                         cwav.rSound[i] = null;
671                                                 }
672                                         }
673                                         else                                                            // WASAPI/ASIO時は通常通り登録
674                                         {
675                                                 for (int i = 1; i < nPoly; i++)
676                                                 {
677                                                         try
678                                                         {
679                                                                 cwav.rSound[i] = CDTXMania.Instance.Sound管理.tサウンドを生成する(str);
680                                                                 cwav.rSound[i].n音量 = 100;
681                                                                 if (!CDTXMania.Instance.ConfigIni.bDynamicBassMixerManagement)
682                                                                 {
683                                                                         cwav.rSound[i].tBASSサウンドをミキサーに追加する();
684                                                                 }
685                                                                 if (CDTXMania.Instance.ConfigIni.bLogCreateRelease)
686                                                                 {
687                                                                         Trace.TraceInformation("サウンドを作成しました。({3})({0})({1})({2}bytes)", cwav.strコメント文, str, cwav.rSound[0].nサウンドバッファサイズ, cwav.rSound[0].bストリーム再生する ? "Stream" : "OnMemory");
688                                                                 }
689                                                         }
690                                                         catch (Exception e)
691                                                         {
692                                                                 cwav.rSound[i] = null;
693                                                                 Trace.TraceError("サウンドの作成に失敗しました。({0})({1})", cwav.strコメント文, str);
694                                                                 Trace.TraceError("例外: " + e.Message);
695                                                         }
696                                                 }
697                                         }
698                                 }
699                                 catch (Exception exception)
700                                 {
701                                         Trace.TraceError("サウンドの生成に失敗しました。({0})({1})({2})", exception.Message, cwav.strコメント文, str);
702                                         for (int j = 0; j < nPolyphonicSounds; j++)
703                                         {
704                                                 cwav.rSound[j] = null;
705                                         }
706                                         //continue;
707                                 }
708                         }
709                 }
710                 public static string tZZ(int n)
711                 {
712                         if (n < 0 || n >= 36 * 36)
713                                 return "!!";  // オーバー/アンダーフロー。
714
715                         // n を36進数2桁の文字列にして返す。
716
717                         string str = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ";
718                         return new string(new char[] { str[n / 36], str[n % 36] });
719                 }
720                 public void tギターとベースのランダム化(EPart part, ERandom eRandom)
721                 {
722                         if (((part == EPart.Guitar) || (part == EPart.Bass)) && (eRandom != ERandom.Off))
723                         {
724                                 int rndVal = 0;
725                                 foreach (CChip chip in this.listChip)
726                                 {
727                                         bool bOpenChip = (chip.bGuitar可視チップ && this.bチップがある.OpenGuitar) || ((chip.bBass可視チップ) && this.bチップがある.OpenBass);
728                                         if (chip[EChannel.BarLine])   // 小節が変化したら
729                                         {
730                                                 rndVal = CDTXMania.Instance.Random.Next(6);
731                                         }
732
733                                         chip.RandomizeRGB(eRandom, rndVal, bOpenChip);// #23546 2010.10.28 yyagi fixed (bチップがある.Bass→bチップがある.OpenBass)
734                                 }
735                         }
736                 }
737
738                 #region [ チップの再生と停止 ]
739                 public void tチップの再生(CChip rChip, long n再生開始システム時刻ms)
740                 {
741                         this.tチップの再生(rChip, n再生開始システム時刻ms, CDTXMania.Instance.ConfigIni.nAutoVolume, false, false);
742                 }
743                 public void tチップの再生(CChip rChip, long n再生開始システム時刻ms, int nVol)
744                 {
745                         this.tチップの再生(rChip, n再生開始システム時刻ms, nVol, false, false);
746                 }
747                 public void tチップの再生(CChip rChip, long n再生開始システム時刻ms, int nVol, bool bMIDIMonitor)
748                 {
749                         this.tチップの再生(rChip, n再生開始システム時刻ms, nVol, bMIDIMonitor, false);
750                 }
751                 public void tチップの再生(CChip pChip, long n再生開始システム時刻ms, int nVol, bool bMIDIMonitor, bool bBad)
752                 {
753                         if (pChip.n整数値_内部番号 >= 0)
754                         {
755                                 if (this.listWAV.ContainsKey(pChip.n整数値_内部番号))
756                                 {
757                                         CWAV wc = this.listWAV[pChip.n整数値_内部番号];
758                                         int index = wc.n現在再生中のサウンド番号 = (wc.n現在再生中のサウンド番号 + 1) % nPolyphonicSounds;
759                                         if ((wc.rSound[0] != null) &&
760                                                 (wc.rSound[0].bストリーム再生する || wc.rSound[index] == null))
761                                         {
762                                                 index = wc.n現在再生中のサウンド番号 = 0;
763                                         }
764                                         CSound sound = wc.rSound[index];
765                                         if (sound != null)
766                                         {
767                                                 if (bBad)
768                                                 {
769                                                         sound.db周波数倍率 = ((float)(100 + (((CDTXMania.Instance.Random.Next(3) + 1) * 7) * (1 - (CDTXMania.Instance.Random.Next(2) * 2))))) / 100f;
770                                                 }
771                                                 else
772                                                 {
773                                                         sound.db周波数倍率 = 1.0;
774                                                 }
775                                                 sound.db再生速度 = ((double)CDTXMania.Instance.ConfigIni.nPlaySpeed) / 20.0;
776                                                 // 再生速度によって、WASAPI/ASIOで使う使用mixerが決まるため、付随情報の設定(音量/PAN)は、再生速度の設定後に行う
777                                                 sound.n音量 = (int)(((double)(nVol * wc.n音量)) / 100.0);
778                                                 sound.n位置 = wc.n位置;
779                                                 sound.t再生を開始する();
780                                         }
781                                         wc.n再生開始時刻[wc.n現在再生中のサウンド番号] = n再生開始システム時刻ms;
782                                         this.tWave再生位置自動補正(wc);
783                                 }
784                         }
785                 }
786                 public void t各自動再生音チップの再生時刻を変更する(int nBGMAdjustの増減値)
787                 {
788                         this.nBGMAdjust += nBGMAdjustの増減値;
789                         foreach (CChip chip in listChip)
790                         {
791                                 chip.AddPlayPositionMsForSE(nBGMAdjustの増減値);
792                         }
793                         foreach (CWAV cwav in this.listWAV.Values)
794                         {
795                                 for (int j = 0; j < nPolyphonicSounds; j++)
796                                 {
797                                         if ((cwav.rSound[j] != null) && cwav.rSound[j].b再生中)
798                                         {
799                                                 cwav.n再生開始時刻[j] += nBGMAdjustの増減値;
800                                         }
801                                 }
802                         }
803                 }
804                 public void t全チップの再生一時停止()
805                 {
806                         foreach (CWAV cwav in this.listWAV.Values)
807                         {
808                                 for (int i = 0; i < nPolyphonicSounds; i++)
809                                 {
810                                         if ((cwav.rSound[i] != null) && cwav.rSound[i].b再生中)
811                                         {
812                                                 cwav.n一時停止時刻[i] = CSound管理.rc演奏用タイマ.nシステム時刻ms;
813                                                 cwav.rSound[i].t再生を一時停止する();
814                                         }
815                                 }
816                         }
817                 }
818                 /// <summary>
819                 /// 全チップの再生を再開する。しかし一時停止と再開を繰り返すと、再生位置が徐々にずれる問題あり。
820                 /// 泥臭い回避方法は、CStage演奏画面共通.cs の tキー入力()を参照のこと。
821                 /// </summary>
822                 public void t全チップの再生再開()
823                 {
824                         foreach (CWAV cwav in this.listWAV.Values)
825                         {
826                                 for (int i = 0; i < nPolyphonicSounds; i++)
827                                 {
828                                         if ((cwav.rSound[i] != null) && cwav.rSound[i].b一時停止中)
829                                         {
830                                                 cwav.n再生開始時刻[i] += CSound管理.rc演奏用タイマ.nシステム時刻ms - cwav.n一時停止時刻[i];
831                                         }
832                                 }
833                         }
834                 }
835                 public void t全チップの再生停止()
836                 {
837                         foreach (CWAV cwav in this.listWAV.Values)
838                         {
839                                 this.tWavの再生停止(cwav.n内部番号);
840                         }
841                 }
842                 public void t全チップの再生停止とミキサーからの削除()
843                 {
844                         foreach (CWAV cwav in this.listWAV.Values)
845                         {
846                                 this.tWavの再生停止(cwav.n内部番号, true);
847                         }
848                 }
849                 #endregion
850
851                 /// <summary>
852                 /// サウンドミキサーにサウンドを登録・削除する時刻を事前に算出する
853                 /// </summary>
854                 public void PlanToAddMixerChannel()
855                 {
856                         if (CDTXMania.Instance.Sound管理.GetCurrentSoundDeviceType() == "DirectSound")  // DShowでの再生の場合はミキシング負荷が高くないため、
857                         {                                   // チップのライフタイム管理を行わない
858                                 return;
859                         }
860
861                         List<CChip> listAddMixerChannel = new List<CChip>(128); ;
862                         List<CChip> listRemoveMixerChannel = new List<CChip>(128);
863                         List<CChip> listRemoveTiming = new List<CChip>(128);
864
865                         //foreach ( CChip pChip in listChip )
866                         for (int i = 0; i < listChip.Count; i++)
867                         {
868                                 CChip pChip = listChip[i];
869                                 if (pChip.bWAVを使うチャンネルである)
870                                 {
871                                         #region [ 発音1秒前のタイミングを記録 ]
872                                         int n発音前余裕ms = 1000, n発音後余裕ms = 800;            // Drums
873                                         {
874                                                 // Guitar / Bass
875                                                 if (pChip.e楽器パート == EPart.Guitar || pChip.e楽器パート == EPart.Bass)
876                                                 {
877                                                         n発音前余裕ms = 800;
878                                                         //n発音後余裕ms = 500;
879                                                 }
880                                                 // SE
881                                                 if (pChip.ESoundChipTypeを得る == ESoundChipType.SE)
882                                                 {
883                                                         n発音前余裕ms = 200;
884                                                         //n発音後余裕ms = 500;
885                                                 }
886                                         }
887                                         #endregion
888                                         #region [ BGMチップならば即ミキサーに追加・・・はしない (全て注釈化) ]
889                                         //if ( pChip.nチャンネル番号 == 0x01 )   // BGMチップは即ミキサーに追加
890                                         //{
891                                         //    if ( listWAV.ContainsKey( pChip.n整数値・内部番号 ) )
892                                         //    {
893                                         //        CDTX.CWAV wc = CDTXMania.Instance.app.DTX.listWAV[ pChip.n整数値・内部番号 ];
894                                         //        if ( wc.rSound[ 0 ] != null )
895                                         //        {
896                                         //            CDTXMania.Instance.app.Sound管理.AddMixer( wc.rSound[ 0 ] );    // BGMは多重再生しない仕様としているので、1個目だけミキサーに登録すればよい
897                                         //        }
898                                         //    }
899                                         //}
900                                         #endregion
901                                         #region [ 発音1秒前のタイミングを算出 ]
902                                         int nAddMixer時刻ms, nAddMixer位置 = 0;
903                                         //Debug.WriteLine("==================================================================");
904                                         //Debug.WriteLine( "Start: ch=" + pChip.nチャンネル番号.ToString("x2") + ", nWAV番号=" + pChip.n整数値 + ", time=" + pChip.n発声時刻ms + ", lasttime=" + listChip[ listChip.Count - 1 ].n発声時刻ms );
905                                         t発声時刻msと発声位置を取得する(pChip.n発声時刻ms - n発音前余裕ms, out nAddMixer時刻ms, out nAddMixer位置);
906                                         //Debug.WriteLine( "nAddMixer時刻ms=" + nAddMixer時刻ms + ",nAddMixer位置=" + nAddMixer位置 );
907
908                                         CChip c_AddMixer = new CChip(nAddMixer位置, pChip.n整数値, pChip.n整数値_内部番号, EChannel.MixerAdd, nAddMixer時刻ms, false);
909                                         listAddMixerChannel.Add(c_AddMixer);
910                                         //Debug.WriteLine("listAddMixerChannel:" );
911                                         //DebugOut_CChipList( listAddMixerChannel );
912                                         #endregion
913
914                                         #region [ そのチップ音のfullduration(チップ音wavの最大再生時間)を取得 ]
915                                         int fullduration = 0;
916                                         if (listWAV.ContainsKey(pChip.n整数値_内部番号))
917                                         {
918                                                 CDTX.CWAV wc = CDTXMania.Instance.DTX.listWAV[pChip.n整数値_内部番号];
919                                                 double _db再生速度 = (CDTXMania.Instance.DTXVmode.Enabled) ? this.dbDTXVPlaySpeed : this.db再生速度;
920                                                 fullduration = (wc.rSound[0] == null) ? 0 : (int)(wc.rSound[0].n総演奏時間ms / _db再生速度); // #23664 durationに再生速度が加味されておらず、低速再生でBGMが途切れる問題を修正 (発声時刻msは、DTX読み込み時に再生速度加味済)
921                                         }
922                                         //Debug.WriteLine("fullduration=" + fullduration );
923                                         #endregion
924
925                                         #region [ そのチップのduration (GtBsが次の音にかき消されることを加味した再生時間) を取得・・・のコードは未使用。mixing抑制の効果が薄いため。]
926                                         int duration = 0;
927                                         //{
928                                         //    int ch = ( pChip.nチャンネル番号 >> 4 );
929                                         //    bool bGtBs = ( ch == 0x02 || ch == 0x0A );
930                                         //    if ( bGtBs )                      // Guitar/Bassの場合
931                                         //    {
932                                         //        int p = i;
933                                         //        int chNext;
934                                         //        do
935                                         //        {
936                                         //            if ( ++p >= listChip.Count )
937                                         //            {
938                                         //                break;
939                                         //            }
940                                         //            chNext = ( listChip[ p ].nチャンネル番号 >> 4 );
941                                         //            duration = listChip[ p ].n発声時刻ms - pChip.n発声時刻ms;
942                                         //            if ( ch == chNext )
943                                         //            {
944                                         //                break;
945                                         //            }
946                                         //        }
947                                         //        while ( duration < fullduration );
948                                         //    }
949                                         //    else                                      // ドラムスの場合
950                                         //    {
951                                         //        duration = fullduration;
952                                         //    }
953                                         //}
954                                         #endregion
955                                         //Debug.WriteLine( i + ": duration diff= " + (fullduration - duration ) );
956                                         duration = fullduration;
957                                         int n新RemoveMixer時刻ms, n新RemoveMixer位置;
958                                         t発声時刻msと発声位置を取得する(pChip.n発声時刻ms + duration + n発音後余裕ms, out n新RemoveMixer時刻ms, out n新RemoveMixer位置);
959                                         //Debug.WriteLine( "n新RemoveMixer時刻ms=" + n新RemoveMixer時刻ms + ",n新RemoveMixer位置=" + n新RemoveMixer位置 );
960                                         if (n新RemoveMixer時刻ms < pChip.n発声時刻ms + duration) // 曲の最後でサウンドが切れるような場合は
961                                         {
962                                                 CChip c_AddMixer_noremove = c_AddMixer;
963                                                 c_AddMixer_noremove.SetSoundAfterPlayEnd(true);
964                                                 listAddMixerChannel[listAddMixerChannel.Count - 1] = c_AddMixer_noremove;
965                                                 continue;                       // 発声位置の計算ができないので、Mixer削除をあきらめる・・・のではなく
966                                                                                                                                                                                 // #32248 2013.10.15 yyagi 演奏終了後も再生を続けるチップであるというフラグをpChip内に立てる
967                                         }
968                                         #region [ 未使用コード ]
969                                         //if ( n新RemoveMixer時刻ms < pChip.n発声時刻ms + duration )     // 曲の最後でサウンドが切れるような場合
970                                         //{
971                                         //    n新RemoveMixer時刻ms = pChip.n発声時刻ms + duration;
972                                         //    // 「位置」は比例計算で求めてお茶を濁す...このやり方だと誤動作したため対応中止
973                                         //    n新RemoveMixer位置 = listChip[ listChip.Count - 1 ].n発声位置 * n新RemoveMixer時刻ms / listChip[ listChip.Count - 1 ].n発声時刻ms;
974                                         //}
975                                         #endregion
976
977                                         #region [ 発音終了2秒後にmixerから削除するが、その前に再発音することになるのかを確認(再発音ならmixer削除タイミングを延期) ]
978                                         int n整数値 = pChip.n整数値;
979                                         int index = listRemoveTiming.FindIndex(
980                                                 delegate (CChip cchip) { return cchip.n整数値 == n整数値; }
981                                         );
982                                         //Debug.WriteLine( "index=" + index );
983                                         if (index >= 0)                         // 過去に同じチップで発音中のものが見つかった場合
984                                         {                                 // 過去の発音のmixer削除を確定させるか、延期するかの2択。
985                                                 int n旧RemoveMixer時刻ms = listRemoveTiming[index].n発声時刻ms;
986                                                 int n旧RemoveMixer位置 = listRemoveTiming[index].n発声位置;
987
988                                                 //Debug.WriteLine( "n旧RemoveMixer時刻ms=" + n旧RemoveMixer時刻ms + ",n旧RemoveMixer位置=" + n旧RemoveMixer位置 );
989                                                 if (pChip.n発声時刻ms - n発音前余裕ms <= n旧RemoveMixer時刻ms)  // mixer削除前に、同じ音の再発音がある場合は、
990                                                 {                                 // mixer削除時刻を遅延させる(if-else後に行う)
991                                                                                                                                                                                         //Debug.WriteLine( "remove TAIL of listAddMixerChannel. TAIL INDEX=" + listAddMixerChannel.Count );
992                                                                                                                                                                                         //DebugOut_CChipList( listAddMixerChannel );
993                                                         listAddMixerChannel.RemoveAt(listAddMixerChannel.Count - 1);  // また、同じチップ音の「mixerへの再追加」は削除する
994                                                                                                                                                                                                                                                                                                                 //Debug.WriteLine( "removed result:" );
995                                                                                                                                                                                                                                                                                                                 //DebugOut_CChipList( listAddMixerChannel );
996                                                 }
997                                                 else                              // 逆に、時間軸上、mixer削除後に再発音するような流れの場合は
998                                                 {
999                                                         //Debug.WriteLine( "Publish the value(listRemoveTiming[index] to listRemoveMixerChannel." );
1000                                                         listRemoveMixerChannel.Add(listRemoveTiming[index]);  // mixer削除を確定させる
1001                                                                                                                                                                                                                                                                                 //Debug.WriteLine( "listRemoveMixerChannel:" );
1002                                                                                                                                                                                                                                                                                 //DebugOut_CChipList( listRemoveMixerChannel );
1003                                                                                                                                                                                                                                                                                 //listRemoveTiming.RemoveAt( index );
1004                                                 }
1005                                                 CChip c = new CChip(n新RemoveMixer位置, listRemoveTiming[index].n整数値, listRemoveTiming[index].n整数値_内部番号, EChannel.MixerRemove, n新RemoveMixer時刻ms, false);// mixer削除時刻を更新(遅延)する
1006                                                 listRemoveTiming[index] = c;
1007                                                 //listRemoveTiming[ index ].n発声時刻ms = n新RemoveMixer時刻ms;  // mixer削除時刻を更新(遅延)する
1008                                                 //listRemoveTiming[ index ].n発声位置 = n新RemoveMixer位置;
1009                                                 //Debug.WriteLine( "listRemoveTiming: modified" );
1010                                                 //DebugOut_CChipList( listRemoveTiming );
1011                                         }
1012                                         else                                // 過去に同じチップを発音していないor
1013                                         {                                 // 発音していたが既にmixer削除確定していたなら
1014                                                 CChip c = new CChip(n新RemoveMixer位置, pChip.n整数値, pChip.n整数値_内部番号, EChannel.MixerRemove, n新RemoveMixer時刻ms, false);// 新しくmixer削除候補として追加する
1015                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                         //Debug.WriteLine( "Add new chip to listRemoveMixerTiming: " );
1016                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                         //Debug.WriteLine( "ch=" + c.nチャンネル番号.ToString( "x2" ) + ", nWAV番号=" + c.n整数値 + ", time=" + c.n発声時刻ms + ", lasttime=" + listChip[ listChip.Count - 1 ].n発声時刻ms );
1017                                                 listRemoveTiming.Add(c);
1018                                                 //Debug.WriteLine( "listRemoveTiming:" );
1019                                                 //DebugOut_CChipList( listRemoveTiming );
1020                                         }
1021                                         #endregion
1022                                 }
1023                         }
1024                         //Debug.WriteLine("==================================================================");
1025                         //Debug.WriteLine( "Result:" );
1026                         //Debug.WriteLine( "listAddMixerChannel:" );
1027                         //DebugOut_CChipList( listAddMixerChannel );
1028                         //Debug.WriteLine( "listRemoveMixerChannel:" );
1029                         //DebugOut_CChipList( listRemoveMixerChannel );
1030                         //Debug.WriteLine( "listRemoveTiming:" );
1031                         //DebugOut_CChipList( listRemoveTiming );
1032                         //Debug.WriteLine( "==================================================================" );
1033
1034                         listChip.AddRange(listAddMixerChannel);
1035                         listChip.AddRange(listRemoveMixerChannel);
1036                         listChip.AddRange(listRemoveTiming);
1037                         listChip.Sort();
1038                 }
1039                 private void DebugOut_CChipList(List<CChip> c)
1040                 {
1041                         //Debug.WriteLine( "Count=" + c.Count );
1042                         for (int i = 0; i < c.Count; i++)
1043                         {
1044                                 Debug.WriteLine(i + ": ch=" + c[i].eチャンネル番号.ToString("x2") + ", WAV番号=" + c[i].n整数値 + ", time=" + c[i].n発声時刻ms);
1045                         }
1046                 }
1047
1048                 /// <summary>
1049                 /// 発声時刻msから発声位置を逆算することはできないため、近似計算する。
1050                 /// 具体的には、希望発声位置前後の2つのチップの発声位置の中間を取る。
1051                 /// </summary>
1052                 /// <param name="n希望発声時刻ms"></param>
1053                 /// <param name="n新発声時刻ms"></param>
1054                 /// <param name="n新発声位置"></param>
1055                 /// <returns></returns>
1056                 private bool t発声時刻msと発声位置を取得する(int n希望発声時刻ms, out int n新発声時刻ms, out int n新発声位置)
1057                 {
1058                         // 発声時刻msから発声位置を逆算することはできないため、近似計算する。
1059                         // 具体的には、希望発声位置前後の2つのチップの発声位置の中間を取る。
1060
1061                         if (n希望発声時刻ms < 0)
1062                         {
1063                                 n希望発声時刻ms = 0;
1064                         }
1065                         //else if ( n希望発声時刻ms > listChip[ listChip.Count - 1 ].n発声時刻ms )            // BGMの最後の余韻を殺してしまうので、この条件は外す
1066                         //{
1067                         //    n希望発声時刻ms = listChip[ listChip.Count - 1 ].n発声時刻ms;
1068                         //}
1069
1070                         int index_min = -1, index_max = -1;
1071                         for (int i = 0; i < listChip.Count; i++)    // 希望発声位置前後の「前」の方のチップを検索
1072                         {
1073                                 if (listChip[i].n発声時刻ms >= n希望発声時刻ms)
1074                                 {
1075                                         index_min = i;
1076                                         break;
1077                                 }
1078                         }
1079                         if (index_min < 0)  // 希望発声時刻に至らずに曲が終了してしまう場合
1080                         {
1081                                 // listの最終項目の時刻をそのまま使用する
1082                                 //・・・のではダメ。BGMが尻切れになる。
1083                                 // そこで、listの最終項目の発声時刻msと発生位置から、希望発声時刻に相当する希望発声位置を比例計算して求める。
1084                                 //n新発声時刻ms = n希望発声時刻ms;
1085                                 //n新発声位置 = listChip[ listChip.Count - 1 ].n発声位置 * n希望発声時刻ms / listChip[ listChip.Count - 1 ].n発声時刻ms;
1086                                 n新発声時刻ms = listChip[listChip.Count - 1].n発声時刻ms;
1087                                 n新発声位置 = listChip[listChip.Count - 1].n発声位置;
1088                                 return false;
1089                         }
1090                         index_max = index_min + 1;
1091                         if (index_max >= listChip.Count)
1092                         {
1093                                 index_max = index_min;
1094                         }
1095                         n新発声時刻ms = (listChip[index_max].n発声時刻ms + listChip[index_min].n発声時刻ms) / 2;
1096                         n新発声位置 = (listChip[index_max].n発声位置 + listChip[index_min].n発声位置) / 2;
1097
1098                         return true;
1099                 }
1100
1101
1102                 /// <summary>
1103                 /// Swap infos between Guitar and Bass (notes, level, n可視チップ数, bチップがある)
1104                 /// </summary>
1105                 public void SwapGuitarBassInfos()           // #24063 2011.1.24 yyagi ギターとベースの譜面情報入替
1106                 {
1107                         foreach (CChip chip in listChip)
1108                         {
1109                                 chip.SwapGB();
1110                         }
1111                         int t = this.LEVEL.Bass;
1112                         this.LEVEL.Bass = this.LEVEL.Guitar;
1113                         this.LEVEL.Guitar = t;
1114
1115                         t = this.n可視チップ数.Bass;
1116                         this.n可視チップ数.Bass = this.n可視チップ数.Guitar;
1117                         this.n可視チップ数.Guitar = t;
1118
1119                         bool ts = this.bチップがある.Bass;
1120                         this.bチップがある.Bass = this.bチップがある.Guitar;
1121                         this.bチップがある.Guitar = ts;
1122
1123                         //                      SwapGuitarBassInfos_AutoFlags();
1124                 }
1125
1126                 // SwapGuitarBassInfos_AutoFlags()は、CDTXからCConfigIniに移動。
1127
1128                 // CActivity 実装
1129
1130                 public override void On活性化()
1131                 {
1132                         this.listWAV = new Dictionary<int, CWAV>();
1133                         this.listBMP = new Dictionary<int, CBMP>();
1134                         this.listBMPTEX = new Dictionary<int, CBMPTEX>();
1135                         this.listBPM = new Dictionary<int, CBPM>();
1136                         this.listBGAPAN = new Dictionary<int, CBGAPAN>();
1137                         this.listBGA = new Dictionary<int, CBGA>();
1138                         this.listAVIPAN = new Dictionary<int, CAVIPAN>();
1139                         this.listAVI = new Dictionary<int, CAVI>();
1140                         this.listChip = new List<CChip>();
1141                         base.On活性化();
1142                 }
1143                 public override void On非活性化()
1144                 {
1145                         if (this.listWAV != null)
1146                         {
1147                                 foreach (CWAV cwav in this.listWAV.Values)
1148                                 {
1149                                         cwav.Dispose();
1150                                 }
1151                                 this.listWAV = null;
1152                         }
1153                         if (this.listBMP != null)
1154                         {
1155                                 foreach (CBMP cbmp in this.listBMP.Values)
1156                                 {
1157                                         cbmp.Dispose();
1158                                 }
1159                                 this.listBMP = null;
1160                         }
1161                         if (this.listBMPTEX != null)
1162                         {
1163                                 foreach (CBMPTEX cbmptex in this.listBMPTEX.Values)
1164                                 {
1165                                         cbmptex.Dispose();
1166                                 }
1167                                 this.listBMPTEX = null;
1168                         }
1169                         if (this.listAVI != null)
1170                         {
1171                                 foreach (CAVI cavi in this.listAVI.Values)
1172                                 {
1173                                         cavi.Dispose();
1174                                 }
1175                                 this.listAVI = null;
1176                         }
1177                         if (this.listBPM != null)
1178                         {
1179                                 this.listBPM.Clear();
1180                                 this.listBPM = null;
1181                         }
1182                         if (this.listBGAPAN != null)
1183                         {
1184                                 this.listBGAPAN.Clear();
1185                                 this.listBGAPAN = null;
1186                         }
1187                         if (this.listBGA != null)
1188                         {
1189                                 this.listBGA.Clear();
1190                                 this.listBGA = null;
1191                         }
1192                         if (this.listAVIPAN != null)
1193                         {
1194                                 this.listAVIPAN.Clear();
1195                                 this.listAVIPAN = null;
1196                         }
1197                         if (this.listChip != null)
1198                         {
1199                                 this.listChip.Clear();
1200                         }
1201                         base.On非活性化();
1202                 }
1203                 public override void OnManagedリソースの作成()
1204                 {
1205                         if (!base.b活性化してない)
1206                         {
1207                                 this.tBMP_BMPTEXの読み込み();
1208                                 this.tAVIの読み込み();
1209                                 base.OnManagedリソースの作成();
1210                         }
1211                 }
1212                 public override void OnManagedリソースの解放()
1213                 {
1214                         if (!base.b活性化してない)
1215                         {
1216                                 if (this.listBMP != null)
1217                                 {
1218                                         foreach (CBMP cbmp in this.listBMP.Values)
1219                                         {
1220                                                 cbmp.Dispose();
1221                                         }
1222                                 }
1223                                 if (this.listBMPTEX != null)
1224                                 {
1225                                         foreach (CBMPTEX cbmptex in this.listBMPTEX.Values)
1226                                         {
1227                                                 cbmptex.Dispose();
1228                                         }
1229                                 }
1230                                 if (this.listAVI != null)
1231                                 {
1232                                         foreach (CAVI cavi in this.listAVI.Values)
1233                                         {
1234                                                 cavi.Dispose();
1235                                         }
1236                                 }
1237                                 base.OnManagedリソースの解放();
1238                         }
1239                 }
1240
1241
1242                 // その他
1243
1244                 #region [ private ]
1245                 //-----------------
1246                 /// <summary>
1247                 /// <para>GDAチャンネル番号に対応するDTXチャンネル番号。</para>
1248                 /// </summary>
1249                 [StructLayout(LayoutKind.Sequential)]
1250                 private struct STGDAPARAM
1251                 {
1252                         public string strGDAのチャンネル文字列;
1253                         public EChannel eDTXのチャンネル番号;
1254
1255                         public STGDAPARAM(string strGDAのチャンネル文字列, EChannel eDTXのチャンネル番号)    // 2011.1.1 yyagi 構造体のコンストラクタ追加(初期化簡易化のため)
1256                         {
1257                                 this.strGDAのチャンネル文字列 = strGDAのチャンネル文字列;
1258                                 this.eDTXのチャンネル番号 = eDTXのチャンネル番号;
1259                         }
1260                 }
1261
1262                 private readonly STGDAPARAM[] stGDAParam;
1263                 private bool bヘッダのみ;
1264                 private Stack<bool> bstackIFからENDIFをスキップする;
1265
1266                 private int n現在の行数;
1267                 private int n現在の乱数;
1268
1269                 private int nPolyphonicSounds = 4;              // #28228 2012.5.1 yyagi
1270
1271                 private int n内部番号BPM1to;
1272                 private int n内部番号WAV1to;
1273                 private int[] n無限管理BPM;
1274                 private int[] n無限管理PAN;
1275                 private int[] n無限管理SIZE;
1276                 private int[] n無限管理VOL;
1277                 private int[] n無限管理WAV;
1278                 private int[] nRESULTIMAGE用優先順位;
1279                 private int[] nRESULTMOVIE用優先順位;
1280                 private int[] nRESULTSOUND用優先順位;
1281
1282                 #region [#23880 2010.12.30 yyagi: コンマとスペースの両方を小数点として扱うTryParse]
1283                 /// <summary>
1284                 /// 小数点としてコンマとピリオドの両方を受け付けるTryParse()
1285                 /// </summary>
1286                 /// <param name="s">strings convert to double</param>
1287                 /// <param name="result">parsed double value</param>
1288                 /// <returns>s が正常に変換された場合は true。それ以外の場合は false。</returns>
1289                 /// <exception cref="ArgumentException">style が NumberStyles 値でないか、style に NumberStyles.AllowHexSpecifier 値が含まれている</exception>
1290                 private bool TryParse(string s, out double result)
1291                 { // #23880 2010.12.30 yyagi: alternative TryParse to permit both '.' and ',' for decimal point
1292                         // EU諸国での #BPM 123,45 のような記述に対応するため、
1293                         // 小数点の最終位置を検出して、それをlocaleにあった
1294                         // 文字に置き換えてからTryParse()する
1295                         // 桁区切りの文字はスキップする
1296
1297                         const string DecimalSeparators = ".,";        // 小数点文字
1298                         const string GroupSeparators = ".,' ";        // 桁区切り文字
1299                         const string NumberSymbols = "0123456789";      // 数値文字
1300
1301                         int len = s.Length;                 // 文字列長
1302                         int decimalPosition = len;              // 真の小数点の位置 最初は文字列終端位置に仮置きする
1303
1304                         for (int i = 0; i < len; i++)
1305                         {             // まず、真の小数点(一番最後に現れる小数点)の位置を求める
1306                                 char c = s[i];
1307                                 if (NumberSymbols.IndexOf(c) >= 0)
1308                                 {       // 数値だったらスキップ
1309                                         continue;
1310                                 }
1311                                 else if (DecimalSeparators.IndexOf(c) >= 0)
1312                                 {   // 小数点文字だったら、その都度位置を上書き記憶
1313                                         decimalPosition = i;
1314                                 }
1315                                 else if (GroupSeparators.IndexOf(c) >= 0)
1316                                 {   // 桁区切り文字の場合もスキップ
1317                                         continue;
1318                                 }
1319                                 else
1320                                 {                     // 数値・小数点・区切り文字以外がきたらループ終了
1321                                         break;
1322                                 }
1323                         }
1324
1325                         StringBuilder decimalStr = new StringBuilder(16);
1326                         for (int i = 0; i < len; i++)
1327                         {             // 次に、localeにあった数値文字列を生成する
1328                                 char c = s[i];
1329                                 if (NumberSymbols.IndexOf(c) >= 0)
1330                                 {       // 数値だったら
1331                                         decimalStr.Append(c);             // そのままコピー
1332                                 }
1333                                 else if (DecimalSeparators.IndexOf(c) >= 0)
1334                                 {   // 小数点文字だったら
1335                                         if (i == decimalPosition)
1336                                         {           // 最後に出現した小数点文字なら、localeに合った小数点を出力する
1337                                                 decimalStr.Append(CultureInfo.CurrentCulture.NumberFormat.NumberDecimalSeparator);
1338                                         }
1339                                 }
1340                                 else if (GroupSeparators.IndexOf(c) >= 0)
1341                                 {   // 桁区切り文字だったら
1342                                         continue;                   // 何もしない(スキップ)
1343                                 }
1344                                 else
1345                                 {
1346                                         break;
1347                                 }
1348                         }
1349                         return double.TryParse(decimalStr.ToString(), out result);  // 最後に、自分のlocale向けの文字列に対してTryParse実行
1350                 }
1351                 #endregion
1352                 //-----------------
1353                 #endregion
1354
1355                 internal void t全AVIの一時停止()
1356                 {
1357                         // AVI の一時停止
1358                         foreach (var avi in listAVI)
1359                         {
1360                                 if (avi.Value.avi != null && avi.Value.avi.b再生中)
1361                                 {
1362                                         avi.Value.avi.Pause();
1363                                 }
1364                         }
1365
1366                         // AVIPAN の一時停止
1367                         foreach (var avi in listAVIPAN)
1368                         {
1369                                 //if ( avi.Value.avi != null && avi.Value.avi.b再生中 )
1370                                 //{
1371                                 //      avi.Value.avi.ToggleRun();
1372                                 //}
1373                         }
1374                 }
1375                 internal void t全AVIの再生再開()
1376                 {
1377                         // AVI の再生再開
1378                         foreach (var avi in listAVI)
1379                         {
1380                                 if (avi.Value.avi != null && avi.Value.avi.b一時停止中)
1381                                 {
1382                                         avi.Value.avi.ToggleRun();
1383                                 }
1384                         }
1385                         // AVIPAN の再生再開
1386                         foreach (var avi in listAVIPAN)
1387                         {
1388                                 //if ( avi.Value.avi != null && avi.Value.avi.b一時停止中 )
1389                                 //{
1390                                 //      avi.Value.avi.ToggleRun();
1391                                 //}
1392                         }
1393                 }
1394         }
1395 }