2 using System.Collections.Generic;
\r
4 using System.Runtime.InteropServices;
\r
5 using System.Drawing;
\r
6 using System.Diagnostics;
\r
8 using System.Security.Cryptography;
\r
9 using System.Reflection;
\r
10 using System.Globalization;
\r
11 using System.Threading;
\r
17 /// CDTX 内で用いる入れ子型を partial にし、ここで定義します。
\r
19 public partial class CDTX : CActivity
\r
22 public int nBGMAdjust
\r
27 public string ARTIST;
\r
28 public string BACKGROUND;
\r
29 public string BACKGROUND_GR;
\r
30 public double BASEBPM;
\r
31 public bool BLACKCOLORKEY;
\r
33 public STチップがある bチップがある;
\r
34 public string COMMENT;
\r
35 public double db再生速度;
\r
37 public string GENRE;
\r
38 public bool HIDDENLEVEL;
\r
39 public STDGBVALUE<int> LEVEL;
\r
40 public Dictionary<int, CAVI> listAVI;
\r
41 public Dictionary<int, CAVIPAN> listAVIPAN;
\r
42 public Dictionary<int, CBGA> listBGA;
\r
43 public Dictionary<int, CBGAPAN> listBGAPAN;
\r
44 public Dictionary<int, CBMP> listBMP;
\r
45 public Dictionary<int, CBMPTEX> listBMPTEX;
\r
46 public Dictionary<int, CBPM> listBPM;
\r
47 public List<CChip> listChip;
\r
48 public Dictionary<int, CWAV> listWAV;
\r
49 public string MIDIFILE;
\r
50 public bool MIDINOTE;
\r
52 public STDGBVALUE<int> n可視チップ数;
\r
53 public const int n最大音数 = 4;
\r
54 public const int n小節の解像度 = 384;
\r
55 public string PANEL;
\r
56 public string PATH_WAV;
\r
57 public string PREIMAGE;
\r
58 public string PREMOVIE;
\r
59 public string PREVIEW;
\r
60 public STRESULT RESULTIMAGE;
\r
61 public STRESULT RESULTMOVIE;
\r
62 public STRESULT RESULTSOUND;
\r
63 public string SOUND_AUDIENCE;
\r
64 public string SOUND_FULLCOMBO;
\r
65 public string SOUND_NOWLOADING;
\r
66 public string SOUND_STAGEFAILED;
\r
67 public string STAGEFILE;
\r
68 public string strハッシュofDTXファイル;
\r
69 public string strファイル名;
\r
70 public string strファイル名の絶対パス;
\r
71 public string strフォルダ名;
\r
72 public string TITLE;
\r
73 public double dbDTXVPlaySpeed;
\r
74 public bool bMovieをFullscreen再生する;
\r
75 public bool bUse556x710BGAAVI;
\r
76 public STDGBVALUE<List<int>> listAutoGhostLag;
\r
77 public STDGBVALUE<List<int>> listTargetGhsotLag;
\r
78 public STDGBVALUE<int> n使用レーン数;
\r
80 #if TEST_NOTEOFFMODE
\r
81 public STLANEVALUE<bool> b演奏で直前の音を消音する;
\r
82 // public bool bHH演奏で直前のHHを消音する;
\r
83 // public bool bGUITAR演奏で直前のGUITARを消音する;
\r
84 // public bool bBASS演奏で直前のBASSを消音する;
\r
98 this.STAGEFILE = "";
\r
99 this.BACKGROUND = "";
\r
100 this.BACKGROUND_GR = "";
\r
101 this.PATH_WAV = "";
\r
102 this.MIDIFILE = "";
\r
103 this.SOUND_STAGEFAILED = "";
\r
104 this.SOUND_FULLCOMBO = "";
\r
105 this.SOUND_NOWLOADING = "";
\r
106 this.SOUND_AUDIENCE = "";
\r
108 this.BLACKCOLORKEY = true;
\r
109 STDGBVALUE<int> stdgbvalue = new STDGBVALUE<int>();
\r
110 stdgbvalue.Drums = 0;
\r
111 stdgbvalue.Guitar = 0;
\r
112 stdgbvalue.Bass = 0;
\r
113 this.LEVEL = stdgbvalue;
\r
114 for (int i = 0; i < 7; i++)
\r
116 this.RESULTIMAGE[i] = "";
\r
117 this.RESULTMOVIE[i] = "";
\r
118 this.RESULTSOUND[i] = "";
\r
121 this.strハッシュofDTXファイル = "";
\r
122 this.bチップがある = new STチップがある();
\r
123 this.bチップがある.Drums = false;
\r
124 this.bチップがある.Guitar = false;
\r
125 this.bチップがある.Bass = false;
\r
126 this.bチップがある.HHOpen = false;
\r
127 this.bチップがある.Ride = false;
\r
128 this.bチップがある.LeftCymbal = false;
\r
129 this.bチップがある.OpenGuitar = false;
\r
130 this.bチップがある.OpenBass = false;
\r
131 this.bチップがある.BGA = false;
\r
132 this.bチップがある.Movie = false;
\r
133 this.bチップがある.LeftPedal = false;
\r
134 this.bチップがある.LeftBassDrum = false;
\r
135 this.bMovieをFullscreen再生する = false;
\r
136 this.strファイル名 = "";
\r
137 this.strフォルダ名 = "";
\r
138 this.strファイル名の絶対パス = "";
\r
139 this.n無限管理WAV = new int[36 * 36];
\r
140 this.n無限管理BPM = new int[36 * 36];
\r
141 this.n無限管理VOL = new int[36 * 36];
\r
142 this.n無限管理PAN = new int[36 * 36];
\r
143 this.n無限管理SIZE = new int[36 * 36];
\r
144 this.nRESULTIMAGE用優先順位 = new int[7];
\r
145 this.nRESULTMOVIE用優先順位 = new int[7];
\r
146 this.nRESULTSOUND用優先順位 = new int[7];
\r
147 this.listAutoGhostLag = new STDGBVALUE<List<int>>();
\r
148 this.listTargetGhsotLag = new STDGBVALUE<List<int>>();
\r
150 #region [ 2011.1.1 yyagi GDA->DTX変換テーブル リファクタ後 ]
\r
151 STGDAPARAM[] stgdaparamArray = new STGDAPARAM[] { // GDA->DTX conversion table
\r
152 new STGDAPARAM("TC", Ech定義.BPM),
\r
153 new STGDAPARAM("BL", Ech定義.BarLength),
\r
154 new STGDAPARAM("GS", Ech定義.flowspeed_gt_nouse),
\r
155 new STGDAPARAM("DS", Ech定義.flowspeed_dr_nouse),
\r
156 new STGDAPARAM("FI", Ech定義.FillIn),
\r
157 new STGDAPARAM("HH", Ech定義.HiHatClose),
\r
158 new STGDAPARAM("SD", Ech定義.Snare),
\r
159 new STGDAPARAM("BD", Ech定義.BassDrum),
\r
160 new STGDAPARAM("HT", Ech定義.HighTom),
\r
161 new STGDAPARAM("LT", Ech定義.LowTom),
\r
162 new STGDAPARAM("CY", Ech定義.Cymbal),
\r
163 new STGDAPARAM("G1", Ech定義.Guitar_xxB),
\r
164 new STGDAPARAM("G2", Ech定義.Guitar_xGx),
\r
165 new STGDAPARAM("G3", Ech定義.Guitar_xGB),
\r
166 new STGDAPARAM("G4", Ech定義.Guitar_Rxx),
\r
167 new STGDAPARAM("G5", Ech定義.Guitar_RxB),
\r
168 new STGDAPARAM("G6", Ech定義.Guitar_RGx),
\r
169 new STGDAPARAM("G7", Ech定義.Guitar_RGB),
\r
170 new STGDAPARAM("GW", Ech定義.Guitar_Wailing),
\r
171 new STGDAPARAM("01", Ech定義.SE01),
\r
172 new STGDAPARAM("02", Ech定義.SE02),
\r
173 new STGDAPARAM("03", Ech定義.SE03),
\r
174 new STGDAPARAM("04", Ech定義.SE04),
\r
175 new STGDAPARAM("05", Ech定義.SE05),
\r
176 new STGDAPARAM("06", Ech定義.SE06),
\r
177 new STGDAPARAM("07", Ech定義.SE07),
\r
178 new STGDAPARAM("08", Ech定義.SE08),
\r
179 new STGDAPARAM("09", Ech定義.SE09),
\r
180 new STGDAPARAM("0A", Ech定義.SE10),
\r
181 new STGDAPARAM("0B", Ech定義.SE11),
\r
182 new STGDAPARAM("0C", Ech定義.SE12),
\r
183 new STGDAPARAM("0D", Ech定義.SE13),
\r
184 new STGDAPARAM("0E", Ech定義.SE14),
\r
185 new STGDAPARAM("0F", Ech定義.SE15),
\r
186 new STGDAPARAM("10", Ech定義.SE16),
\r
187 new STGDAPARAM("11", Ech定義.SE17),
\r
188 new STGDAPARAM("12", Ech定義.SE18),
\r
189 new STGDAPARAM("13", Ech定義.SE19),
\r
190 new STGDAPARAM("14", Ech定義.SE20),
\r
191 new STGDAPARAM("15", Ech定義.SE21),
\r
192 new STGDAPARAM("16", Ech定義.SE22),
\r
193 new STGDAPARAM("17", Ech定義.SE23),
\r
194 new STGDAPARAM("18", Ech定義.SE24),
\r
195 new STGDAPARAM("19", Ech定義.SE25),
\r
196 new STGDAPARAM("1A", Ech定義.SE26),
\r
197 new STGDAPARAM("1B", Ech定義.SE27),
\r
198 new STGDAPARAM("1C", Ech定義.SE28),
\r
199 new STGDAPARAM("1D", Ech定義.SE29),
\r
200 new STGDAPARAM("1E", Ech定義.SE30),
\r
201 new STGDAPARAM("1F", Ech定義.SE31),
\r
202 new STGDAPARAM("20", Ech定義.SE32),
\r
203 new STGDAPARAM("B1", Ech定義.Bass_xxB),
\r
204 new STGDAPARAM("B2", Ech定義.Bass_xGx),
\r
205 new STGDAPARAM("B3", Ech定義.Bass_xGB),
\r
206 new STGDAPARAM("B4", Ech定義.Bass_Rxx),
\r
207 new STGDAPARAM("B5", Ech定義.Bass_RxB),
\r
208 new STGDAPARAM("B6", Ech定義.Bass_RGx),
\r
209 new STGDAPARAM("B7", Ech定義.Bass_RGB),
\r
210 new STGDAPARAM("BW", Ech定義.Bass_Wailing),
\r
211 new STGDAPARAM("G0", Ech定義.Guitar_Open),
\r
212 new STGDAPARAM("B0", Ech定義.Bass_Open)
\r
214 this.stGDAParam = stgdaparamArray;
\r
216 this.nBGMAdjust = 0;
\r
217 this.nPolyphonicSounds = CDTXMania.Instance.ConfigIni.nPoliphonicSounds;
\r
218 this.dbDTXVPlaySpeed = 1.0f;
\r
219 this.bUse556x710BGAAVI = false;
\r
220 this.n使用レーン数 = new STDGBVALUE<int>();
\r
222 #if TEST_NOTEOFFMODE
\r
223 this.bHH演奏で直前のHHを消音する = true;
\r
224 this.bGUITAR演奏で直前のGUITARを消音する = true;
\r
225 this.bBASS演奏で直前のBASSを消音する = true;
\r
229 private CDTX(string str全入力文字列)
\r
233 this.t入力_全入力文字列から(str全入力文字列);
\r
235 public CDTX(string strファイル名, bool bヘッダのみ)
\r
239 this.t入力(strファイル名, bヘッダのみ);
\r
241 private CDTX(string str全入力文字列, double db再生速度, int nBGMAdjust)
\r
245 this.t入力_全入力文字列から(str全入力文字列, db再生速度, nBGMAdjust);
\r
247 public CDTX(string strファイル名, bool bヘッダのみ, double db再生速度, int nBGMAdjust)
\r
251 this.t入力(strファイル名, bヘッダのみ, db再生速度, nBGMAdjust);
\r
258 public int nモニタを考慮した音量(E楽器パート part)
\r
260 CConfigIni configIni = CDTXMania.Instance.ConfigIni;
\r
264 if (configIni.b演奏音を強調する.Drums)
\r
266 return configIni.n自動再生音量;
\r
268 return configIni.n手動再生音量;
\r
270 case E楽器パート.GUITAR:
\r
271 if (configIni.b演奏音を強調する.Guitar)
\r
273 return configIni.n自動再生音量;
\r
275 return configIni.n手動再生音量;
\r
278 if (configIni.b演奏音を強調する.Bass)
\r
280 return configIni.n自動再生音量;
\r
282 return configIni.n手動再生音量;
\r
284 if ((!configIni.b演奏音を強調する.Drums && !configIni.b演奏音を強調する.Guitar) && !configIni.b演奏音を強調する.Bass)
\r
286 return configIni.n手動再生音量;
\r
288 return configIni.n自動再生音量;
\r
290 public void tAVIの読み込み()
\r
292 if (this.listAVI != null)
\r
294 foreach (CAVI cavi in this.listAVI.Values)
\r
296 cavi.OnDeviceCreated();
\r
301 foreach (CChip chip in this.listChip)
\r
303 chip.ApplyAVI(listAVI, listAVIPAN);
\r
307 #region [ BMP/BMPTEXの並列読み込み・デコード用メソッド ]
\r
308 delegate void BackgroundBMPLoadAll(Dictionary<int, CBMP> listB);
\r
309 static BackgroundBMPLoadAll backgroundBMPLoadAll = new BackgroundBMPLoadAll(BMPLoadAll);
\r
310 delegate void BackgroundBMPTEXLoadAll(Dictionary<int, CBMPTEX> listB);
\r
311 static BackgroundBMPTEXLoadAll backgroundBMPTEXLoadAll = new BackgroundBMPTEXLoadAll(BMPTEXLoadAll);
\r
312 private static void LoadTexture(CBMPbase cbmp) // バックグラウンドスレッドで動作する、ファイル読み込み部
\r
314 string filename = cbmp.GetFullPathname;
\r
315 if (!File.Exists(filename))
\r
317 Trace.TraceWarning("ファイルが存在しません。({0})", filename);
\r
318 cbmp.bitmap = null;
\r
323 cbmp.bitmap = new Bitmap(filename);
\r
325 catch (ArgumentException)
\r
327 Trace.TraceWarning("引数が不正です。ファイルが破損している可能性があります。({0})", filename);
\r
328 cbmp.bitmap = null;
\r
332 private static void BMPLoadAll(Dictionary<int, CBMP> listB) // バックグラウンドスレッドで、テクスチャファイルをひたすら読み込んではキューに追加する
\r
334 //Trace.TraceInformation( "Back: ThreadID(BMPLoad)=" + Thread.CurrentThread.ManagedThreadId + ", listCount=" + listB.Count );
\r
335 foreach (CBMPbase cbmp in listB.Values)
\r
340 queueCBMPbaseDone.Enqueue(cbmp);
\r
341 // Trace.TraceInformation( "Back: Enqueued(" + queueCBMPbaseDone.Count + "): " + cbmp.strファイル名 );
\r
343 if (queueCBMPbaseDone.Count > 8)
\r
349 private static void BMPTEXLoadAll(Dictionary<int, CBMPTEX> listB) // ダサい実装だが、Dictionary<>の中には手を出せず、妥協した
\r
351 //Trace.TraceInformation( "Back: ThreadID(BMPLoad)=" + Thread.CurrentThread.ManagedThreadId + ", listCount=" + listB.Count );
\r
352 foreach (CBMPbase cbmp in listB.Values)
\r
357 queueCBMPbaseDone.Enqueue(cbmp);
\r
358 // Trace.TraceInformation( "Back: Enqueued(" + queueCBMPbaseDone.Count + "): " + cbmp.strファイル名 );
\r
360 if (queueCBMPbaseDone.Count > 8)
\r
367 private static Queue<CBMPbase> queueCBMPbaseDone = new Queue<CBMPbase>();
\r
368 private static object lockQueue = new object();
\r
369 private static int nLoadDone;
\r
372 public void tBMP_BMPTEXの読み込み()
\r
374 #region [ CPUコア数の取得 ]
\r
375 CWin32.SYSTEM_INFO sysInfo = new CWin32.SYSTEM_INFO();
\r
376 CWin32.GetSystemInfo(ref sysInfo);
\r
377 int nCPUCores = (int)sysInfo.dwNumberOfProcessors;
\r
379 #region [ BMP読み込み ]
\r
380 if (this.listBMP != null)
\r
382 if (nCPUCores <= 1)
\r
384 #region [ シングルスレッドで逐次読み出し・デコード・テクスチャ定義 ]
\r
385 foreach (CBMP cbmp in this.listBMP.Values)
\r
387 cbmp.OnDeviceCreated();
\r
393 #region [ メインスレッド(テクスチャ定義)とバックグラウンドスレッド(読み出し・デコード)を並列動作させ高速化 ]
\r
394 //Trace.TraceInformation( "Main: ThreadID(Main)=" + Thread.CurrentThread.ManagedThreadId + ", listCount=" + this.listBMP.Count );
\r
396 backgroundBMPLoadAll.BeginInvoke(listBMP, null, null);
\r
398 // t.Priority = ThreadPriority.Lowest;
\r
399 // t.Start( listBMP );
\r
400 int c = listBMP.Count;
\r
401 while (nLoadDone < c)
\r
403 if (queueCBMPbaseDone.Count > 0)
\r
406 //Trace.TraceInformation( "Main: Lock Begin for dequeue1." );
\r
411 cbmp = (CBMP)queueCBMPbaseDone.Dequeue();
\r
412 // Trace.TraceInformation( "Main: Dequeued(" + queueCBMPbaseDone.Count + "): " + cbmp.strファイル名 );
\r
414 cbmp.OnDeviceCreated(cbmp.bitmap, cbmp.GetFullPathname);
\r
416 catch (InvalidCastException) // bmp読み込み失敗時は、キャストに失敗する
\r
423 //Trace.TraceInformation( "Main: OnDeviceCreated: " + cbmp.strファイル名 );
\r
427 //Trace.TraceInformation( "Main: Sleeped.");
\r
428 Thread.Sleep(5); // WaitOneのイベント待ちにすると、メインスレッド処理中に2個以上イベント完了したときにそれを正しく検出できなくなるので、
\r
429 } // ポーリングに逃げてしまいました。
\r
435 #region [ BMPTEX読み込み ]
\r
436 if (this.listBMPTEX != null)
\r
438 if (nCPUCores <= 1)
\r
440 #region [ シングルスレッドで逐次読み出し・デコード・テクスチャ定義 ]
\r
441 foreach (CBMPTEX cbmptex in this.listBMPTEX.Values)
\r
443 cbmptex.OnDeviceCreated();
\r
449 #region [ メインスレッド(テクスチャ定義)とバックグラウンドスレッド(読み出し・デコード)を並列動作させ高速化 ]
\r
450 //Trace.TraceInformation( "Main: ThreadID(Main)=" + Thread.CurrentThread.ManagedThreadId + ", listCount=" + this.listBMP.Count );
\r
452 backgroundBMPTEXLoadAll.BeginInvoke(listBMPTEX, null, null);
\r
453 int c = listBMPTEX.Count;
\r
454 while (nLoadDone < c)
\r
456 if (queueCBMPbaseDone.Count > 0)
\r
459 //Trace.TraceInformation( "Main: Lock Begin for dequeue1." );
\r
464 cbmptex = (CBMPTEX)queueCBMPbaseDone.Dequeue();
\r
465 // Trace.TraceInformation( "Main: Dequeued(" + queueCBMPbaseDone.Count + "): " + cbmp.strファイル名 );
\r
467 cbmptex.OnDeviceCreated(cbmptex.bitmap, cbmptex.GetFullPathname);
\r
469 catch (InvalidCastException)
\r
476 //Trace.TraceInformation( "Main: OnDeviceCreated: " + cbmp.strファイル名 );
\r
480 //Trace.TraceInformation( "Main: Sleeped.");
\r
481 Thread.Sleep(5); // WaitOneのイベント待ちにすると、メインスレッド処理中に2個以上イベント完了したときにそれを正しく検出できなくなるので、
\r
482 } // ポーリングに逃げてしまいました。
\r
490 foreach (CChip chip in this.listChip)
\r
492 chip.ApplyBMP_BMPTEX(listBGA, listBGAPAN, listBMP, listBMPTEX);
\r
496 public void tWave再生位置自動補正()
\r
498 foreach (CWAV cwav in this.listWAV.Values)
\r
500 this.tWave再生位置自動補正(cwav);
\r
503 public void tWave再生位置自動補正(CWAV wc)
\r
505 if (wc.rSound[0] != null && wc.rSound[0].n総演奏時間ms >= 5000)
\r
507 for (int i = 0; i < nPolyphonicSounds; i++)
\r
509 if ((wc.rSound[i] != null) && (wc.rSound[i].b再生中))
\r
511 long nCurrentTime = CSound管理.rc演奏用タイマ.nシステム時刻ms;
\r
512 if (nCurrentTime > wc.n再生開始時刻[i])
\r
514 long nAbsTimeFromStartPlaying = nCurrentTime - wc.n再生開始時刻[i];
\r
515 //Trace.TraceInformation( "再生位置自動補正: {0}, seek先={1}ms, 全音長={2}ms",
\r
516 // Path.GetFileName( wc.rSound[ 0 ].strファイル名 ),
\r
517 // nAbsTimeFromStartPlaying,
\r
518 // wc.rSound[ 0 ].n総演奏時間ms
\r
520 // wc.rSound[ i ].t再生位置を変更する( wc.rSound[ i ].t時刻から位置を返す( nAbsTimeFromStartPlaying ) );
\r
521 wc.rSound[i].t再生位置を変更する(nAbsTimeFromStartPlaying); // WASAPI/ASIO用
\r
522 //Debug.WriteLine( "再生位置を変更: " + Path.GetFileName( wc.strファイル名 ) + nAbsTimeFromStartPlaying + "ms");
\r
532 public void tWaveBGM再生位置表示()
\r
534 foreach (CWAV wc in this.listWAV.Values)
\r
536 if (wc.rSound[0] != null && wc.rSound[0].n総演奏時間ms >= 5000)
\r
538 for (int i = 0; i < nPolyphonicSounds; i++)
\r
540 if ((wc.rSound[i] != null) && (wc.rSound[i].b再生中))
\r
544 wc.rSound[i].t再生位置を取得する(out n位置byte, out db位置ms);
\r
545 Trace.TraceInformation("再生位置: {0}, seek先={1}ms / {2}byte, 全音長={3}ms",
\r
546 Path.GetFileName(wc.rSound[0].strファイル名),
\r
548 wc.rSound[0].n総演奏時間ms
\r
556 public void tWavの再生停止(int nWaveの内部番号)
\r
558 tWavの再生停止(nWaveの内部番号, false);
\r
560 public void tWavの再生停止(int nWaveの内部番号, bool bミキサーからも削除する)
\r
562 if (this.listWAV.ContainsKey(nWaveの内部番号))
\r
564 CWAV cwav = this.listWAV[nWaveの内部番号];
\r
565 for (int i = 0; i < nPolyphonicSounds; i++)
\r
567 if (cwav.rSound[i] != null && cwav.rSound[i].b再生中)
\r
571 cwav.rSound[i].tサウンドを停止してMixerからも削除する();
\r
575 cwav.rSound[i].t再生を停止する();
\r
581 public void tWAVの読み込み(CWAV cwav)
\r
583 // Trace.TraceInformation("WAV files={0}", this.listWAV.Count);
\r
585 // foreach (CWAV cwav in this.listWAV.Values)
\r
587 // string strCount = count.ToString() + " / " + this.listWAV.Count.ToString();
\r
588 // Debug.WriteLine(strCount);
\r
589 // CDTXMania.Instance.app.act文字コンソール.tPrint(0, 0, C文字コンソール.Eフォント種別.白, strCount);
\r
592 string str = string.IsNullOrEmpty(this.PATH_WAV) ? this.strフォルダ名 : this.PATH_WAV;
\r
593 str = str + cwav.strファイル名;
\r
594 bool bIsDirectSound = (CDTXMania.Instance.Sound管理.GetCurrentSoundDeviceType() == "DirectSound");
\r
599 // cwav.rSound[ 0 ] = CDTXMania.Instance.app.Sound管理.tサウンドを生成する( str );
\r
600 // cwav.rSound[ 0 ].n音量 = 100;
\r
601 // if ( CDTXMania.Instance.app.ConfigIni.bLog作成解放ログ出力 )
\r
603 // Trace.TraceInformation( "サウンドを作成しました。({3})({0})({1})({2}bytes)", cwav.strコメント文, str, cwav.rSound[ 0 ].nサウンドバッファサイズ, cwav.rSound[ 0 ].bストリーム再生する ? "Stream" : "OnMemory" );
\r
608 // cwav.rSound[ 0 ] = null;
\r
609 // Trace.TraceError( "サウンドの作成に失敗しました。({0})({1})", cwav.strコメント文, str );
\r
611 //if ( cwav.rSound[ 0 ] == null ) // #xxxxx 2012.5.3 yyagi rSound[1-3]もClone()するようにし、これらのストリーム再生がおかしくなる問題を修正
\r
613 // for ( int j = 1; j < nPolyphonicSounds; j++ )
\r
615 // cwav.rSound[ j ] = null;
\r
620 // for ( int j = 1; j < nPolyphonicSounds; j++ )
\r
622 // cwav.rSound[ j ] = (CSound) cwav.rSound[ 0 ].Clone(); // #24007 2011.9.5 yyagi add: to accelerate loading chip sounds
\r
623 // CDTXMania.Instance.app.Sound管理.tサウンドを登録する( cwav.rSound[ j ] );
\r
630 cwav.rSound[0] = CDTXMania.Instance.Sound管理.tサウンドを生成する(str);
\r
631 cwav.rSound[0].n音量 = 100;
\r
632 if (!CDTXMania.Instance.ConfigIni.bDynamicBassMixerManagement)
\r
634 cwav.rSound[0].tBASSサウンドをミキサーに追加する();
\r
636 if (CDTXMania.Instance.ConfigIni.bLog作成解放ログ出力)
\r
638 Trace.TraceInformation("サウンドを作成しました。({3})({0})({1})({2}bytes)", cwav.strコメント文, str, cwav.rSound[0].nサウンドバッファサイズ, cwav.rSound[0].bストリーム再生する ? "Stream" : "OnMemory");
\r
641 catch (Exception e)
\r
643 cwav.rSound[0] = null;
\r
644 Trace.TraceError("サウンドの作成に失敗しました。({0})({1})", cwav.strコメント文, str);
\r
645 Trace.TraceError("例外: " + e.Message);
\r
648 #region [ 同時発音数を、チャンネルによって変える ]
\r
649 int nPoly = nPolyphonicSounds;
\r
650 if (CDTXMania.Instance.Sound管理.GetCurrentSoundDeviceType() != "DirectSound") // DShowでの再生の場合はミキシング負荷が高くないため、
\r
651 { // チップのライフタイム管理を行わない
\r
652 if (cwav.bIsBassSound) nPoly = (nPolyphonicSounds >= 2) ? 2 : 1;
\r
653 else if (cwav.bIsGuitarSound) nPoly = (nPolyphonicSounds >= 2) ? 2 : 1;
\r
654 else if (cwav.bIsSESound) nPoly = 1;
\r
655 else if (cwav.bIsBGMSound) nPoly = 1;
\r
657 if (cwav.bIsBGMSound) nPoly = 1;
\r
661 //if ( bIsDirectSound ) // DShowでの再生の場合はCloneする
\r
663 // for ( int i = 1; i < nPoly; i++ )
\r
665 // cwav.rSound[ i ] = (CSound) cwav.rSound[ 0 ].Clone(); // #24007 2011.9.5 yyagi add: to accelerate loading chip sounds
\r
666 // // CDTXMania.Instance.app.Sound管理.tサウンドを登録する( cwav.rSound[ j ] );
\r
668 // for ( int i = nPoly; i < nPolyphonicSounds; i++ )
\r
670 // cwav.rSound[ i ] = null;
\r
673 //else // WASAPI/ASIO時は通常通り登録
\r
675 for (int i = 1; i < nPoly; i++)
\r
679 cwav.rSound[i] = CDTXMania.Instance.Sound管理.tサウンドを生成する(str);
\r
680 cwav.rSound[i].n音量 = 100;
\r
681 if (!CDTXMania.Instance.ConfigIni.bDynamicBassMixerManagement)
\r
683 cwav.rSound[i].tBASSサウンドをミキサーに追加する();
\r
685 if (CDTXMania.Instance.ConfigIni.bLog作成解放ログ出力)
\r
687 Trace.TraceInformation("サウンドを作成しました。({3})({0})({1})({2}bytes)", cwav.strコメント文, str, cwav.rSound[0].nサウンドバッファサイズ, cwav.rSound[0].bストリーム再生する ? "Stream" : "OnMemory");
\r
690 catch (Exception e)
\r
692 cwav.rSound[i] = null;
\r
693 Trace.TraceError("サウンドの作成に失敗しました。({0})({1})", cwav.strコメント文, str);
\r
694 Trace.TraceError("例外: " + e.Message);
\r
699 catch (Exception exception)
\r
701 Trace.TraceError("サウンドの生成に失敗しました。({0})({1})({2})", exception.Message, cwav.strコメント文, str);
\r
702 for (int j = 0; j < nPolyphonicSounds; j++)
\r
704 cwav.rSound[j] = null;
\r
710 public static string tZZ(int n)
\r
712 if (n < 0 || n >= 36 * 36)
\r
713 return "!!"; // オーバー/アンダーフロー。
\r
715 // n を36進数2桁の文字列にして返す。
\r
717 string str = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ";
\r
718 return new string(new char[] { str[n / 36], str[n % 36] });
\r
720 public void tギターとベースのランダム化(E楽器パート part, Eランダムモード eRandom)
\r
722 if (((part == E楽器パート.GUITAR) || (part == E楽器パート.BASS)) && (eRandom != Eランダムモード.OFF))
\r
725 foreach (CChip chip in this.listChip)
\r
727 bool bOpenChip = (chip.bGuitar可視チップ && this.bチップがある.OpenGuitar) || ((chip.bBass可視チップ) && this.bチップがある.OpenBass);
\r
728 if (chip[Ech定義.BarLine]) // 小節が変化したら
\r
730 rndVal = CDTXMania.Instance.Random.Next(6);
\r
733 chip.RandomizeRGB(eRandom, rndVal, bOpenChip);// #23546 2010.10.28 yyagi fixed (bチップがある.Bass→bチップがある.OpenBass)
\r
738 #region [ チップの再生と停止 ]
\r
739 public void tチップの再生(CChip rChip, long n再生開始システム時刻ms, int nLane)
\r
741 this.tチップの再生(rChip, n再生開始システム時刻ms, nLane, CDTXMania.Instance.ConfigIni.n自動再生音量, false, false);
\r
743 public void tチップの再生(CChip rChip, long n再生開始システム時刻ms, int nLane, int nVol)
\r
745 this.tチップの再生(rChip, n再生開始システム時刻ms, nLane, nVol, false, false);
\r
747 public void tチップの再生(CChip rChip, long n再生開始システム時刻ms, int nLane, int nVol, bool bMIDIMonitor)
\r
749 this.tチップの再生(rChip, n再生開始システム時刻ms, nLane, nVol, bMIDIMonitor, false);
\r
751 public void tチップの再生(CChip pChip, long n再生開始システム時刻ms, int nLane, int nVol, bool bMIDIMonitor, bool bBad)
\r
753 if (pChip.n整数値_内部番号 >= 0)
\r
755 if ((nLane < (int)Eレーン.LC) || ((int)Eレーン.BGM < nLane))
\r
757 throw new ArgumentOutOfRangeException();
\r
759 if (this.listWAV.ContainsKey(pChip.n整数値_内部番号))
\r
761 CWAV wc = this.listWAV[pChip.n整数値_内部番号];
\r
762 int index = wc.n現在再生中のサウンド番号 = (wc.n現在再生中のサウンド番号 + 1) % nPolyphonicSounds;
\r
763 if ((wc.rSound[0] != null) &&
\r
764 (wc.rSound[0].bストリーム再生する || wc.rSound[index] == null))
\r
766 index = wc.n現在再生中のサウンド番号 = 0;
\r
768 CSound sound = wc.rSound[index];
\r
773 sound.db周波数倍率 = ((float)(100 + (((CDTXMania.Instance.Random.Next(3) + 1) * 7) * (1 - (CDTXMania.Instance.Random.Next(2) * 2))))) / 100f;
\r
777 sound.db周波数倍率 = 1.0;
\r
779 sound.db再生速度 = ((double)CDTXMania.Instance.ConfigIni.n演奏速度) / 20.0;
\r
780 // 再生速度によって、WASAPI/ASIOで使う使用mixerが決まるため、付随情報の設定(音量/PAN)は、再生速度の設定後に行う
\r
781 sound.n音量 = (int)(((double)(nVol * wc.n音量)) / 100.0);
\r
782 sound.n位置 = wc.n位置;
\r
785 wc.n再生開始時刻[wc.n現在再生中のサウンド番号] = n再生開始システム時刻ms;
\r
786 this.tWave再生位置自動補正(wc);
\r
790 public void t各自動再生音チップの再生時刻を変更する(int nBGMAdjustの増減値)
\r
792 this.nBGMAdjust += nBGMAdjustの増減値;
\r
793 foreach (CChip chip in listChip)
\r
795 chip.AddPlayPositionMsForSE(nBGMAdjustの増減値);
\r
797 foreach (CWAV cwav in this.listWAV.Values)
\r
799 for (int j = 0; j < nPolyphonicSounds; j++)
\r
801 if ((cwav.rSound[j] != null) && cwav.rSound[j].b再生中)
\r
803 cwav.n再生開始時刻[j] += nBGMAdjustの増減値;
\r
808 public void t全チップの再生一時停止()
\r
810 foreach (CWAV cwav in this.listWAV.Values)
\r
812 for (int i = 0; i < nPolyphonicSounds; i++)
\r
814 if ((cwav.rSound[i] != null) && cwav.rSound[i].b再生中)
\r
816 cwav.n一時停止時刻[i] = CSound管理.rc演奏用タイマ.nシステム時刻ms;
\r
817 cwav.rSound[i].t再生を一時停止する();
\r
823 /// 全チップの再生を再開する。しかし一時停止と再開を繰り返すと、再生位置が徐々にずれる問題あり。
\r
824 /// 泥臭い回避方法は、CStage演奏画面共通.cs の tキー入力()を参照のこと。
\r
826 public void t全チップの再生再開()
\r
828 foreach (CWAV cwav in this.listWAV.Values)
\r
830 for (int i = 0; i < nPolyphonicSounds; i++)
\r
832 if ((cwav.rSound[i] != null) && cwav.rSound[i].b一時停止中)
\r
834 cwav.n再生開始時刻[i] += CSound管理.rc演奏用タイマ.nシステム時刻ms - cwav.n一時停止時刻[i];
\r
839 public void t全チップの再生停止()
\r
841 foreach (CWAV cwav in this.listWAV.Values)
\r
843 this.tWavの再生停止(cwav.n内部番号);
\r
846 public void t全チップの再生停止とミキサーからの削除()
\r
848 foreach (CWAV cwav in this.listWAV.Values)
\r
850 this.tWavの再生停止(cwav.n内部番号, true);
\r
856 /// サウンドミキサーにサウンドを登録・削除する時刻を事前に算出する
\r
858 public void PlanToAddMixerChannel()
\r
860 if (CDTXMania.Instance.Sound管理.GetCurrentSoundDeviceType() == "DirectSound") // DShowでの再生の場合はミキシング負荷が高くないため、
\r
861 { // チップのライフタイム管理を行わない
\r
865 List<CChip> listAddMixerChannel = new List<CChip>(128); ;
\r
866 List<CChip> listRemoveMixerChannel = new List<CChip>(128);
\r
867 List<CChip> listRemoveTiming = new List<CChip>(128);
\r
869 //foreach ( CChip pChip in listChip )
\r
870 for (int i = 0; i < listChip.Count; i++)
\r
872 CChip pChip = listChip[i];
\r
873 if (pChip.bWAVを使うチャンネルである)
\r
875 #region [ 発音1秒前のタイミングを記録 ]
\r
876 int n発音前余裕ms = 1000, n発音後余裕ms = 800; // Drums
\r
879 if ( pChip.e楽器パート == E楽器パート.GUITAR || pChip.e楽器パート == E楽器パート.BASS )
\r
885 if ( pChip.ESoundChipTypeを得る == ESoundChipType.SE )
\r
892 #region [ BGMチップならば即ミキサーに追加・・・はしない (全て注釈化) ]
\r
893 //if ( pChip.nチャンネル番号 == 0x01 ) // BGMチップは即ミキサーに追加
\r
895 // if ( listWAV.ContainsKey( pChip.n整数値・内部番号 ) )
\r
897 // CDTX.CWAV wc = CDTXMania.Instance.app.DTX.listWAV[ pChip.n整数値・内部番号 ];
\r
898 // if ( wc.rSound[ 0 ] != null )
\r
900 // CDTXMania.Instance.app.Sound管理.AddMixer( wc.rSound[ 0 ] ); // BGMは多重再生しない仕様としているので、1個目だけミキサーに登録すればよい
\r
905 #region [ 発音1秒前のタイミングを算出 ]
\r
906 int nAddMixer時刻ms, nAddMixer位置 = 0;
\r
907 //Debug.WriteLine("==================================================================");
\r
908 //Debug.WriteLine( "Start: ch=" + pChip.nチャンネル番号.ToString("x2") + ", nWAV番号=" + pChip.n整数値 + ", time=" + pChip.n発声時刻ms + ", lasttime=" + listChip[ listChip.Count - 1 ].n発声時刻ms );
\r
909 t発声時刻msと発声位置を取得する(pChip.n発声時刻ms - n発音前余裕ms, out nAddMixer時刻ms, out nAddMixer位置);
\r
910 //Debug.WriteLine( "nAddMixer時刻ms=" + nAddMixer時刻ms + ",nAddMixer位置=" + nAddMixer位置 );
\r
912 CChip c_AddMixer = new CChip(nAddMixer位置, pChip.n整数値, pChip.n整数値_内部番号, Ech定義.MixerAdd, nAddMixer時刻ms, false);
\r
913 listAddMixerChannel.Add(c_AddMixer);
\r
914 //Debug.WriteLine("listAddMixerChannel:" );
\r
915 //DebugOut_CChipList( listAddMixerChannel );
\r
918 #region [ そのチップ音のfullduration(チップ音wavの最大再生時間)を取得 ]
\r
919 int fullduration = 0;
\r
920 if (listWAV.ContainsKey(pChip.n整数値_内部番号))
\r
922 CDTX.CWAV wc = CDTXMania.Instance.DTX.listWAV[pChip.n整数値_内部番号];
\r
923 double _db再生速度 = (CDTXMania.Instance.DTXVmode.Enabled) ? this.dbDTXVPlaySpeed : this.db再生速度;
\r
924 fullduration = (wc.rSound[0] == null) ? 0 : (int)(wc.rSound[0].n総演奏時間ms / _db再生速度); // #23664 durationに再生速度が加味されておらず、低速再生でBGMが途切れる問題を修正 (発声時刻msは、DTX読み込み時に再生速度加味済)
\r
926 //Debug.WriteLine("fullduration=" + fullduration );
\r
929 #region [ そのチップのduration (GtBsが次の音にかき消されることを加味した再生時間) を取得・・・のコードは未使用。mixing抑制の効果が薄いため。]
\r
932 // int ch = ( pChip.nチャンネル番号 >> 4 );
\r
933 // bool bGtBs = ( ch == 0x02 || ch == 0x0A );
\r
934 // if ( bGtBs ) // Guitar/Bassの場合
\r
940 // if ( ++p >= listChip.Count )
\r
944 // chNext = ( listChip[ p ].nチャンネル番号 >> 4 );
\r
945 // duration = listChip[ p ].n発声時刻ms - pChip.n発声時刻ms;
\r
946 // if ( ch == chNext )
\r
951 // while ( duration < fullduration );
\r
955 // duration = fullduration;
\r
959 //Debug.WriteLine( i + ": duration diff= " + (fullduration - duration ) );
\r
960 duration = fullduration;
\r
961 int n新RemoveMixer時刻ms, n新RemoveMixer位置;
\r
962 t発声時刻msと発声位置を取得する(pChip.n発声時刻ms + duration + n発音後余裕ms, out n新RemoveMixer時刻ms, out n新RemoveMixer位置);
\r
963 //Debug.WriteLine( "n新RemoveMixer時刻ms=" + n新RemoveMixer時刻ms + ",n新RemoveMixer位置=" + n新RemoveMixer位置 );
\r
964 if (n新RemoveMixer時刻ms < pChip.n発声時刻ms + duration) // 曲の最後でサウンドが切れるような場合は
\r
966 CChip c_AddMixer_noremove = c_AddMixer;
\r
967 c_AddMixer_noremove.SetSoundAfterPlayEnd(true);
\r
968 listAddMixerChannel[listAddMixerChannel.Count - 1] = c_AddMixer_noremove;
\r
969 continue; // 発声位置の計算ができないので、Mixer削除をあきらめる・・・のではなく
\r
970 // #32248 2013.10.15 yyagi 演奏終了後も再生を続けるチップであるというフラグをpChip内に立てる
\r
973 //if ( n新RemoveMixer時刻ms < pChip.n発声時刻ms + duration ) // 曲の最後でサウンドが切れるような場合
\r
975 // n新RemoveMixer時刻ms = pChip.n発声時刻ms + duration;
\r
976 // // 「位置」は比例計算で求めてお茶を濁す...このやり方だと誤動作したため対応中止
\r
977 // n新RemoveMixer位置 = listChip[ listChip.Count - 1 ].n発声位置 * n新RemoveMixer時刻ms / listChip[ listChip.Count - 1 ].n発声時刻ms;
\r
981 #region [ 発音終了2秒後にmixerから削除するが、その前に再発音することになるのかを確認(再発音ならmixer削除タイミングを延期) ]
\r
982 int n整数値 = pChip.n整数値;
\r
983 int index = listRemoveTiming.FindIndex(
\r
984 delegate(CChip cchip) { return cchip.n整数値 == n整数値; }
\r
986 //Debug.WriteLine( "index=" + index );
\r
987 if (index >= 0) // 過去に同じチップで発音中のものが見つかった場合
\r
988 { // 過去の発音のmixer削除を確定させるか、延期するかの2択。
\r
989 int n旧RemoveMixer時刻ms = listRemoveTiming[index].n発声時刻ms;
\r
990 int n旧RemoveMixer位置 = listRemoveTiming[index].n発声位置;
\r
992 //Debug.WriteLine( "n旧RemoveMixer時刻ms=" + n旧RemoveMixer時刻ms + ",n旧RemoveMixer位置=" + n旧RemoveMixer位置 );
\r
993 if (pChip.n発声時刻ms - n発音前余裕ms <= n旧RemoveMixer時刻ms) // mixer削除前に、同じ音の再発音がある場合は、
\r
994 { // mixer削除時刻を遅延させる(if-else後に行う)
\r
995 //Debug.WriteLine( "remove TAIL of listAddMixerChannel. TAIL INDEX=" + listAddMixerChannel.Count );
\r
996 //DebugOut_CChipList( listAddMixerChannel );
\r
997 listAddMixerChannel.RemoveAt(listAddMixerChannel.Count - 1); // また、同じチップ音の「mixerへの再追加」は削除する
\r
998 //Debug.WriteLine( "removed result:" );
\r
999 //DebugOut_CChipList( listAddMixerChannel );
\r
1001 else // 逆に、時間軸上、mixer削除後に再発音するような流れの場合は
\r
1003 //Debug.WriteLine( "Publish the value(listRemoveTiming[index] to listRemoveMixerChannel." );
\r
1004 listRemoveMixerChannel.Add(listRemoveTiming[index]); // mixer削除を確定させる
\r
1005 //Debug.WriteLine( "listRemoveMixerChannel:" );
\r
1006 //DebugOut_CChipList( listRemoveMixerChannel );
\r
1007 //listRemoveTiming.RemoveAt( index );
\r
1009 CChip c = new CChip(n新RemoveMixer位置, listRemoveTiming[index].n整数値, listRemoveTiming[index].n整数値_内部番号, Ech定義.MixerRemove, n新RemoveMixer時刻ms, false);// mixer削除時刻を更新(遅延)する
\r
1010 listRemoveTiming[index] = c;
\r
1011 //listRemoveTiming[ index ].n発声時刻ms = n新RemoveMixer時刻ms; // mixer削除時刻を更新(遅延)する
\r
1012 //listRemoveTiming[ index ].n発声位置 = n新RemoveMixer位置;
\r
1013 //Debug.WriteLine( "listRemoveTiming: modified" );
\r
1014 //DebugOut_CChipList( listRemoveTiming );
\r
1016 else // 過去に同じチップを発音していないor
\r
1017 { // 発音していたが既にmixer削除確定していたなら
\r
1018 CChip c = new CChip(n新RemoveMixer位置, pChip.n整数値, pChip.n整数値_内部番号, Ech定義.MixerRemove, n新RemoveMixer時刻ms, false);// 新しくmixer削除候補として追加する
\r
1019 //Debug.WriteLine( "Add new chip to listRemoveMixerTiming: " );
\r
1020 //Debug.WriteLine( "ch=" + c.nチャンネル番号.ToString( "x2" ) + ", nWAV番号=" + c.n整数値 + ", time=" + c.n発声時刻ms + ", lasttime=" + listChip[ listChip.Count - 1 ].n発声時刻ms );
\r
1021 listRemoveTiming.Add(c);
\r
1022 //Debug.WriteLine( "listRemoveTiming:" );
\r
1023 //DebugOut_CChipList( listRemoveTiming );
\r
1028 //Debug.WriteLine("==================================================================");
\r
1029 //Debug.WriteLine( "Result:" );
\r
1030 //Debug.WriteLine( "listAddMixerChannel:" );
\r
1031 //DebugOut_CChipList( listAddMixerChannel );
\r
1032 //Debug.WriteLine( "listRemoveMixerChannel:" );
\r
1033 //DebugOut_CChipList( listRemoveMixerChannel );
\r
1034 //Debug.WriteLine( "listRemoveTiming:" );
\r
1035 //DebugOut_CChipList( listRemoveTiming );
\r
1036 //Debug.WriteLine( "==================================================================" );
\r
1038 listChip.AddRange(listAddMixerChannel);
\r
1039 listChip.AddRange(listRemoveMixerChannel);
\r
1040 listChip.AddRange(listRemoveTiming);
\r
1043 private void DebugOut_CChipList(List<CChip> c)
\r
1045 //Debug.WriteLine( "Count=" + c.Count );
\r
1046 for (int i = 0; i < c.Count; i++)
\r
1048 Debug.WriteLine(i + ": ch=" + c[i].eチャンネル番号.ToString("x2") + ", WAV番号=" + c[i].n整数値 + ", time=" + c[i].n発声時刻ms);
\r
1053 /// 発声時刻msから発声位置を逆算することはできないため、近似計算する。
\r
1054 /// 具体的には、希望発声位置前後の2つのチップの発声位置の中間を取る。
\r
1056 /// <param name="n希望発声時刻ms"></param>
\r
1057 /// <param name="n新発声時刻ms"></param>
\r
1058 /// <param name="n新発声位置"></param>
\r
1059 /// <returns></returns>
\r
1060 private bool t発声時刻msと発声位置を取得する(int n希望発声時刻ms, out int n新発声時刻ms, out int n新発声位置)
\r
1062 // 発声時刻msから発声位置を逆算することはできないため、近似計算する。
\r
1063 // 具体的には、希望発声位置前後の2つのチップの発声位置の中間を取る。
\r
1065 if (n希望発声時刻ms < 0)
\r
1069 //else if ( n希望発声時刻ms > listChip[ listChip.Count - 1 ].n発声時刻ms ) // BGMの最後の余韻を殺してしまうので、この条件は外す
\r
1071 // n希望発声時刻ms = listChip[ listChip.Count - 1 ].n発声時刻ms;
\r
1074 int index_min = -1, index_max = -1;
\r
1075 for (int i = 0; i < listChip.Count; i++) // 希望発声位置前後の「前」の方のチップを検索
\r
1077 if (listChip[i].n発声時刻ms >= n希望発声時刻ms)
\r
1083 if (index_min < 0) // 希望発声時刻に至らずに曲が終了してしまう場合
\r
1085 // listの最終項目の時刻をそのまま使用する
\r
1086 //・・・のではダメ。BGMが尻切れになる。
\r
1087 // そこで、listの最終項目の発声時刻msと発生位置から、希望発声時刻に相当する希望発声位置を比例計算して求める。
\r
1088 //n新発声時刻ms = n希望発声時刻ms;
\r
1089 //n新発声位置 = listChip[ listChip.Count - 1 ].n発声位置 * n希望発声時刻ms / listChip[ listChip.Count - 1 ].n発声時刻ms;
\r
1090 n新発声時刻ms = listChip[listChip.Count - 1].n発声時刻ms;
\r
1091 n新発声位置 = listChip[listChip.Count - 1].n発声位置;
\r
1094 index_max = index_min + 1;
\r
1095 if (index_max >= listChip.Count)
\r
1097 index_max = index_min;
\r
1099 n新発声時刻ms = (listChip[index_max].n発声時刻ms + listChip[index_min].n発声時刻ms) / 2;
\r
1100 n新発声位置 = (listChip[index_max].n発声位置 + listChip[index_min].n発声位置) / 2;
\r
1107 /// Swap infos between Guitar and Bass (notes, level, n可視チップ数, bチップがある)
\r
1109 public void SwapGuitarBassInfos() // #24063 2011.1.24 yyagi ギターとベースの譜面情報入替
\r
1111 foreach (CChip chip in listChip)
\r
1115 int t = this.LEVEL.Bass;
\r
1116 this.LEVEL.Bass = this.LEVEL.Guitar;
\r
1117 this.LEVEL.Guitar = t;
\r
1119 t = this.n可視チップ数.Bass;
\r
1120 this.n可視チップ数.Bass = this.n可視チップ数.Guitar;
\r
1121 this.n可視チップ数.Guitar = t;
\r
1123 bool ts = this.bチップがある.Bass;
\r
1124 this.bチップがある.Bass = this.bチップがある.Guitar;
\r
1125 this.bチップがある.Guitar = ts;
\r
1127 // SwapGuitarBassInfos_AutoFlags();
\r
1130 // SwapGuitarBassInfos_AutoFlags()は、CDTXからCConfigIniに移動。
\r
1134 public override void On活性化()
\r
1136 this.listWAV = new Dictionary<int, CWAV>();
\r
1137 this.listBMP = new Dictionary<int, CBMP>();
\r
1138 this.listBMPTEX = new Dictionary<int, CBMPTEX>();
\r
1139 this.listBPM = new Dictionary<int, CBPM>();
\r
1140 this.listBGAPAN = new Dictionary<int, CBGAPAN>();
\r
1141 this.listBGA = new Dictionary<int, CBGA>();
\r
1142 this.listAVIPAN = new Dictionary<int, CAVIPAN>();
\r
1143 this.listAVI = new Dictionary<int, CAVI>();
\r
1144 this.listChip = new List<CChip>();
\r
1147 public override void On非活性化()
\r
1149 if (this.listWAV != null)
\r
1151 foreach (CWAV cwav in this.listWAV.Values)
\r
1155 this.listWAV = null;
\r
1157 if (this.listBMP != null)
\r
1159 foreach (CBMP cbmp in this.listBMP.Values)
\r
1163 this.listBMP = null;
\r
1165 if (this.listBMPTEX != null)
\r
1167 foreach (CBMPTEX cbmptex in this.listBMPTEX.Values)
\r
1169 cbmptex.Dispose();
\r
1171 this.listBMPTEX = null;
\r
1173 if (this.listAVI != null)
\r
1175 foreach (CAVI cavi in this.listAVI.Values)
\r
1179 this.listAVI = null;
\r
1181 if (this.listBPM != null)
\r
1183 this.listBPM.Clear();
\r
1184 this.listBPM = null;
\r
1186 if (this.listBGAPAN != null)
\r
1188 this.listBGAPAN.Clear();
\r
1189 this.listBGAPAN = null;
\r
1191 if (this.listBGA != null)
\r
1193 this.listBGA.Clear();
\r
1194 this.listBGA = null;
\r
1196 if (this.listAVIPAN != null)
\r
1198 this.listAVIPAN.Clear();
\r
1199 this.listAVIPAN = null;
\r
1201 if (this.listChip != null)
\r
1203 this.listChip.Clear();
\r
1207 public override void OnManagedリソースの作成()
\r
1209 if (!base.b活性化してない)
\r
1211 this.tBMP_BMPTEXの読み込み();
\r
1213 base.OnManagedリソースの作成();
\r
1216 public override void OnManagedリソースの解放()
\r
1218 if (!base.b活性化してない)
\r
1220 if (this.listBMP != null)
\r
1222 foreach (CBMP cbmp in this.listBMP.Values)
\r
1227 if (this.listBMPTEX != null)
\r
1229 foreach (CBMPTEX cbmptex in this.listBMPTEX.Values)
\r
1231 cbmptex.Dispose();
\r
1234 if (this.listAVI != null)
\r
1236 foreach (CAVI cavi in this.listAVI.Values)
\r
1241 base.OnManagedリソースの解放();
\r
1248 #region [ private ]
\r
1249 //-----------------
\r
1251 /// <para>GDAチャンネル番号に対応するDTXチャンネル番号。</para>
\r
1253 [StructLayout(LayoutKind.Sequential)]
\r
1254 private struct STGDAPARAM
\r
1256 public string strGDAのチャンネル文字列;
\r
1257 public Ech定義 eDTXのチャンネル番号;
\r
1259 public STGDAPARAM(string strGDAのチャンネル文字列, Ech定義 eDTXのチャンネル番号) // 2011.1.1 yyagi 構造体のコンストラクタ追加(初期化簡易化のため)
\r
1261 this.strGDAのチャンネル文字列 = strGDAのチャンネル文字列;
\r
1262 this.eDTXのチャンネル番号 = eDTXのチャンネル番号;
\r
1266 private readonly STGDAPARAM[] stGDAParam;
\r
1267 private bool bヘッダのみ;
\r
1268 private Stack<bool> bstackIFからENDIFをスキップする;
\r
1270 private int n現在の行数;
\r
1271 private int n現在の乱数;
\r
1273 private int nPolyphonicSounds = 4; // #28228 2012.5.1 yyagi
\r
1275 private int n内部番号BPM1to;
\r
1276 private int n内部番号WAV1to;
\r
1277 private int[] n無限管理BPM;
\r
1278 private int[] n無限管理PAN;
\r
1279 private int[] n無限管理SIZE;
\r
1280 private int[] n無限管理VOL;
\r
1281 private int[] n無限管理WAV;
\r
1282 private int[] nRESULTIMAGE用優先順位;
\r
1283 private int[] nRESULTMOVIE用優先順位;
\r
1284 private int[] nRESULTSOUND用優先順位;
\r
1286 #region [#23880 2010.12.30 yyagi: コンマとスペースの両方を小数点として扱うTryParse]
\r
1288 /// 小数点としてコンマとピリオドの両方を受け付けるTryParse()
\r
1290 /// <param name="s">strings convert to double</param>
\r
1291 /// <param name="result">parsed double value</param>
\r
1292 /// <returns>s が正常に変換された場合は true。それ以外の場合は false。</returns>
\r
1293 /// <exception cref="ArgumentException">style が NumberStyles 値でないか、style に NumberStyles.AllowHexSpecifier 値が含まれている</exception>
\r
1294 private bool TryParse(string s, out double result)
\r
1295 { // #23880 2010.12.30 yyagi: alternative TryParse to permit both '.' and ',' for decimal point
\r
1296 // EU諸国での #BPM 123,45 のような記述に対応するため、
\r
1297 // 小数点の最終位置を検出して、それをlocaleにあった
\r
1298 // 文字に置き換えてからTryParse()する
\r
1301 const string DecimalSeparators = ".,"; // 小数点文字
\r
1302 const string GroupSeparators = ".,' "; // 桁区切り文字
\r
1303 const string NumberSymbols = "0123456789"; // 数値文字
\r
1305 int len = s.Length; // 文字列長
\r
1306 int decimalPosition = len; // 真の小数点の位置 最初は文字列終端位置に仮置きする
\r
1308 for (int i = 0; i < len; i++)
\r
1309 { // まず、真の小数点(一番最後に現れる小数点)の位置を求める
\r
1311 if (NumberSymbols.IndexOf(c) >= 0)
\r
1315 else if (DecimalSeparators.IndexOf(c) >= 0)
\r
1316 { // 小数点文字だったら、その都度位置を上書き記憶
\r
1317 decimalPosition = i;
\r
1319 else if (GroupSeparators.IndexOf(c) >= 0)
\r
1320 { // 桁区切り文字の場合もスキップ
\r
1324 { // 数値・小数点・区切り文字以外がきたらループ終了
\r
1329 StringBuilder decimalStr = new StringBuilder(16);
\r
1330 for (int i = 0; i < len; i++)
\r
1331 { // 次に、localeにあった数値文字列を生成する
\r
1333 if (NumberSymbols.IndexOf(c) >= 0)
\r
1335 decimalStr.Append(c); // そのままコピー
\r
1337 else if (DecimalSeparators.IndexOf(c) >= 0)
\r
1339 if (i == decimalPosition)
\r
1340 { // 最後に出現した小数点文字なら、localeに合った小数点を出力する
\r
1341 decimalStr.Append(CultureInfo.CurrentCulture.NumberFormat.NumberDecimalSeparator);
\r
1344 else if (GroupSeparators.IndexOf(c) >= 0)
\r
1346 continue; // 何もしない(スキップ)
\r
1353 return double.TryParse(decimalStr.ToString(), out result); // 最後に、自分のlocale向けの文字列に対してTryParse実行
\r
1356 //-----------------
\r
1359 internal void t全AVIの一時停止()
\r
1362 foreach (var avi in listAVI)
\r
1364 if (avi.Value.avi != null && avi.Value.avi.b再生中)
\r
1366 avi.Value.avi.Pause();
\r
1371 foreach (var avi in listAVIPAN)
\r
1373 //if ( avi.Value.avi != null && avi.Value.avi.b再生中 )
\r
1375 // avi.Value.avi.ToggleRun();
\r
1379 internal void t全AVIの再生再開()
\r
1382 foreach (var avi in listAVI)
\r
1384 if (avi.Value.avi != null && avi.Value.avi.b一時停止中)
\r
1386 avi.Value.avi.ToggleRun();
\r
1390 foreach (var avi in listAVIPAN)
\r
1392 //if ( avi.Value.avi != null && avi.Value.avi.b一時停止中 )
\r
1394 // avi.Value.avi.ToggleRun();
\r