2 using System.Collections.Generic;
4 using System.Runtime.InteropServices;
6 using System.Diagnostics;
8 using System.Security.Cryptography;
9 using System.Reflection;
10 using System.Globalization;
11 using System.Threading;
16 public partial class CDTX
18 public void t入力(string strファイル名, bool bEnumerating, bool bレーン情報を確認する)
20 this.t入力(strファイル名, bEnumerating, bレーン情報を確認する, 1.0, 0);
22 public void t入力(string strファイル名, bool bEnumerating, bool bレーン情報を確認する, double db再生速度, int nBGMAdjust)
24 this.bヘッダのみ = bEnumerating;
25 this.bレーン情報を確認する = bレーン情報を確認する;
26 this.strファイル名の絶対パス = Path.GetFullPath(strファイル名);
27 this.strファイル名 = Path.GetFileName(this.strファイル名の絶対パス);
28 this.strフォルダ名 = Path.GetDirectoryName(this.strファイル名の絶対パス) + @"\";
29 string ext = Path.GetExtension(this.strファイル名).ToLower();
36 this.e種別 = EDTX種別.GDA;
38 else if (ext == ".g2d")
40 this.e種別 = EDTX種別.G2D;
42 else if (ext == ".bms")
44 this.e種別 = EDTX種別.BMS;
46 else if (ext == ".bme")
48 this.e種別 = EDTX種別.BME;
50 else if (ext == ".mid")
52 this.e種別 = EDTX種別.SMF;
57 this.e種別 = EDTX種別.DTX;
60 if (this.e種別 != EDTX種別.SMF)
64 //DateTime timeBeginLoad = DateTime.Now;
67 StreamReader reader = new StreamReader(strファイル名, Encoding.GetEncoding("Shift_JIS"));
68 string str2 = reader.ReadToEnd();
70 //span = (TimeSpan) ( DateTime.Now - timeBeginLoad );
71 //Trace.TraceInformation( "DTXfileload時間: {0}", span.ToString() );
73 this.t入力_全入力文字列から(str2, db再生速度, nBGMAdjust);
81 Trace.TraceWarning("SMF の演奏は未対応です。(検討中)");
84 public void t入力_全入力文字列から(string str全入力文字列)
86 this.t入力_全入力文字列から(str全入力文字列, 1.0, 0);
88 public unsafe void t入力_全入力文字列から(string str全入力文字列, double db再生速度, int nBGMAdjust)
90 //DateTime timeBeginLoad = DateTime.Now;
93 if (!string.IsNullOrEmpty(str全入力文字列))
97 str全入力文字列 = str全入力文字列.Replace(Environment.NewLine, "\n");
98 str全入力文字列 = str全入力文字列.Replace('\t', ' ');
99 str全入力文字列 = str全入力文字列 + "\n";
101 //span = (TimeSpan) ( DateTime.Now - timeBeginLoad );
102 //Trace.TraceInformation( "改行カット時間: {0}", span.ToString() );
103 //timeBeginLoad = DateTime.Now;
105 for (int j = 0; j < 36 * 36; j++)
107 this.n無限管理WAV[j] = -j;
108 this.n無限管理BPM[j] = -j;
109 this.n無限管理VOL[j] = -j;
110 this.n無限管理PAN[j] = -10000 - j;
111 this.n無限管理SIZE[j] = -j;
113 this.n内部番号WAV1to = 1;
114 this.n内部番号BPM1to = 1;
115 this.bstackIFからENDIFをスキップする = new Stack<bool>();
116 this.bstackIFからENDIFをスキップする.Push(false);
118 for (int k = 0; k < 7; k++)
120 this.nRESULTIMAGE用優先順位[k] = 0;
121 this.nRESULTMOVIE用優先順位[k] = 0;
122 this.nRESULTSOUND用優先順位[k] = 0;
126 CharEnumerator ce = str全入力文字列.GetEnumerator();
132 if (!this.t入力_空白と改行をスキップする(ref ce))
136 if (ce.Current == '#')
140 StringBuilder builder = new StringBuilder(0x20);
141 if (this.t入力_コマンド文字列を抜き出す(ref ce, ref builder))
143 StringBuilder builder2 = new StringBuilder(0x400);
144 if (this.t入力_パラメータ文字列を抜き出す(ref ce, ref builder2))
146 StringBuilder builder3 = new StringBuilder(0x400);
147 if (this.t入力_コメント文字列を抜き出す(ref ce, ref builder3))
149 this.t入力_行解析(ref builder, ref builder2, ref builder3);
159 while (this.t入力_コメントをスキップする(ref ce));
161 //span = (TimeSpan) ( DateTime.Now - timeBeginLoad );
162 //Trace.TraceInformation( "抜き出し時間: {0}", span.ToString() );
163 //timeBeginLoad = DateTime.Now;
164 this.n無限管理WAV = null;
165 this.n無限管理BPM = null;
166 this.n無限管理VOL = null;
167 this.n無限管理PAN = null;
168 this.n無限管理SIZE = null;
169 if (!this.bヘッダのみ && this.bレーン情報を確認する)
171 #region [ BPM/BMP初期化 ]
173 foreach (CBPM cbpm2 in this.listBPM.Values)
175 if (cbpm2.n表記上の番号 == 0)
184 cbpm.n内部番号 = this.n内部番号BPM1to++;
187 this.listBPM.Add(cbpm.n内部番号, cbpm);
188 CChip chip = new CChip(0, 0, cbpm.n内部番号, EChannel.BPMEx);
189 this.listChip.Insert(0, chip);
193 CChip chip = new CChip(0, 0, cbpm.n内部番号, EChannel.BPMEx);
194 this.listChip.Insert(0, chip);
196 if (this.listBMP.ContainsKey(0))
198 CChip chip = new CChip(0, 0, 0, EChannel.BGALayer1);
199 this.listChip.Insert(0, chip);
202 //span = (TimeSpan) ( DateTime.Now - timeBeginLoad );
203 //Trace.TraceInformation( "前準備完了時間: {0}", span.ToString() );
204 //timeBeginLoad = DateTime.Now;
206 foreach (CWAV cwav in this.listWAV.Values)
208 if (cwav.nチップサイズ < 0)
212 if (cwav.n位置 <= -10000)
222 //span = (TimeSpan) ( DateTime.Now - timeBeginLoad );
223 //Trace.TraceInformation( "CWAV前準備時間: {0}", span.ToString() );
224 //timeBeginLoad = DateTime.Now;
225 #region [ チップ倍率設定 ] // #28145 2012.4.22 yyagi 二重ループを1重ループに変更して高速化)
226 //foreach ( CWAV cwav in this.listWAV.Values )
228 // foreach( CChip chip in this.listChip )
230 // if( chip.n整数値・内部番号 == cwav.n内部番号 )
232 // chip.dbチップサイズ倍率 = ( (double) cwav.nチップサイズ ) / 100.0;
233 // if (chip.nチャンネル番号 == 0x01 ) // BGMだったら
235 // cwav.bIsOnBGMLane = true;
240 foreach (CChip chip in this.listChip)
242 if (this.listWAV.ContainsKey(chip.n整数値_内部番号))
243 //foreach ( CWAV cwav in this.listWAV.Values )
245 CWAV cwav = this.listWAV[chip.n整数値_内部番号];
246 // if ( chip.n整数値・内部番号 == cwav.n内部番号 )
248 chip.SetDBChipSizeFactor(((double)cwav.nチップサイズ) / 100.0);
249 //if ( chip.nチャンネル番号 == 0x01 ) // BGMだったら
251 // cwav.bIsOnBGMLane = true;
257 //span = (TimeSpan) ( DateTime.Now - timeBeginLoad );
258 //Trace.TraceInformation( "CWAV全準備時間: {0}", span.ToString() );
259 //timeBeginLoad = DateTime.Now;
260 #region [ 必要に応じて空打ち音を0小節に定義する ]
261 //for ( int m = 0xb1; m <= 0xbc; m++ ) // #28146 2012.4.21 yyagi; bb -> bc
263 // foreach ( CChip chip in this.listChip )
265 // if ( chip.nチャンネル番号 == m )
267 // CChip c = new CChip();
269 // c.nチャンネル番号 = chip.nチャンネル番号;
270 // c.n整数値 = chip.n整数値;
271 // c.n整数値・内部番号 = chip.n整数値・内部番号;
272 // this.listChip.Insert( 0, c );
278 //span = (TimeSpan) ( DateTime.Now - timeBeginLoad );
279 //Trace.TraceInformation( "空打確認時間: {0}", span.ToString() );
280 //timeBeginLoad = DateTime.Now;
281 #region [ 拍子・拍線の挿入と、クリック音の挿入と、最初に再生するサウンド直前へのマーカー挿入(録音開始トリガ) ]
282 if (this.listChip.Count > 0)
284 this.listChip.Sort(); // 高速化のためにはこれを削りたいが、listChipの最後がn発声位置の終端である必要があるので、
285 // 保守性確保を優先してここでのソートは残しておく
286 // なお、093時点では、このソートを削除しても動作するようにはしてある。
287 // (ここまでの一部チップ登録を、listChip.Add(c)から同Insert(0,c)に変更してある)
288 // これにより、数ms程度ながらここでのソートも高速化されている。
289 double barlength = 1.0;
290 int nEndOfSong = (this.listChip[this.listChip.Count - 1].n発声位置 + 384) - (this.listChip[this.listChip.Count - 1].n発声位置 % 384);
291 bool bClickOffBeat = (CDTXMania.Instance.ConfigIni.eClickType == EClickType.OffBeat); // 裏拍でメトロノーム再生
292 for (int tick384 = 0; tick384 <= nEndOfSong; tick384 += 384) // 小節線の挿入 (後に出てくる拍子線とループをまとめようとするなら、forループの終了条件の微妙な違いに注意が必要)
294 CChip chip = new CChip(tick384, 36 * 36 - 1, EChannel.BarLine);
295 this.listChip.Add(chip);
297 //this.listChip.Sort(); // ここでのソートは不要。ただし最後にソートすること
298 int nChipNo_BarLength = 0;
300 for (int tick384 = 0; tick384 < nEndOfSong; tick384 += 384)
302 int n発声位置_C1_同一小節内 = 0;
303 while ((nChipNo_C1 < this.listChip.Count) && (this.listChip[nChipNo_C1].n発声位置 < (tick384 + 384)))
305 if (this.listChip[nChipNo_C1].eチャンネル番号 == EChannel.BeatLineShift) // 拍線シフトの検出
307 n発声位置_C1_同一小節内 = this.listChip[nChipNo_C1].n発声位置 - tick384;
311 if ((this.e種別 == EDTX種別.BMS) || (this.e種別 == EDTX種別.BME))
315 while ((nChipNo_BarLength < this.listChip.Count) && (this.listChip[nChipNo_BarLength].n発声位置 <= tick384))
317 if (this.listChip[nChipNo_BarLength].eチャンネル番号 == EChannel.BarLength) // bar lengthの検出
319 barlength = this.listChip[nChipNo_BarLength].db実数値;
325 int deltaOffBeat = (int) ( 384.0 / 8 / barlength );
326 if ( !bClickOffBeat ) // 裏拍でのメトロノーム再生の設定でなければ(Off設定であっても)
328 this.listChip.Add( new CChip( tick384, 1, EChannel.Click ) ); // 小節線上に、表拍のクリック音を挿入
330 else if ( tick384 + 384 / 8 <= nEndOfSong ) // 裏拍設定で、かつ曲長内に収まるなら
332 this.listChip.Add( new CChip( tick384 + deltaOffBeat, 1, EChannel.Click ) ); // 小節線から8分音符だけ後に、裏拍のクリック音を挿入
336 for (int i = 0; i < 100; i++) // 拍線の挿入
338 int tickBeat = (int)(((double)(384 * i)) / (4.0 * barlength));
339 if ((tickBeat + n発声位置_C1_同一小節内) >= 384)
343 if (((tickBeat + n発声位置_C1_同一小節内) % 384) != 0)
345 CChip chip = new CChip(tick384 + (tickBeat + n発声位置_C1_同一小節内), 36 * 36 - 1, EChannel.BeatLine);
346 this.listChip.Add(chip);
347 if ( !bClickOffBeat ) // メトロノーム設定が裏拍設定でなければ、拍音を挿入
349 this.listChip.Add( new CChip( tick384 + ( tickBeat + n発声位置_C1_同一小節内 ), 2, EChannel.Click ) );
351 else if ( ( tickBeat + deltaOffBeat + n発声位置_C1_同一小節内 ) < 384 ) // 裏拍設定、かつ小節内に収まっていれば、拍音を挿入
353 this.listChip.Add( new CChip( tick384 + ( tickBeat + deltaOffBeat + n発声位置_C1_同一小節内 ), 2, EChannel.Click ) );
360 // 最初にサウンドの再生を開始するチップの位置に、録音開始トリガのマーカーを挿入
361 for (int i = 0; i < listChip.Count; i++)
363 if (listChip[i].bWAVを使うチャンネルである)
365 int playPosition = listChip[i].n発声位置;
366 CChip chip = new CChip(playPosition, 36 * 36 - 1, EChannel.FirstSoundChip);
367 this.listChip.Insert(i, chip);
372 this.listChip.Sort();
375 //span = (TimeSpan) ( DateTime.Now - timeBeginLoad );
376 //Trace.TraceInformation( "拍子・拍線挿入時間: {0}", span.ToString() );
377 //timeBeginLoad = DateTime.Now;
378 #region [ C2 [拍線・小節線表示指定] の処理 ] // #28145 2012.4.21 yyagi; 2重ループをほぼ1重にして高速化
379 bool bShowBeatBarLine = true;
380 for (int i = 0; i < this.listChip.Count; i++)
382 bool bChangedBeatBarStatus = false;
383 if ((this.listChip[i].eチャンネル番号 == EChannel.BeatLineDisplay))
385 if (this.listChip[i].n整数値 == 1) // BAR/BEAT LINE = ON
387 bShowBeatBarLine = true;
388 bChangedBeatBarStatus = true;
390 else if (this.listChip[i].n整数値 == 2) // BAR/BEAT LINE = OFF
392 bShowBeatBarLine = false;
393 bChangedBeatBarStatus = true;
397 if (bChangedBeatBarStatus) // C2チップの前に50/51チップが来ている可能性に配慮
399 while (startIndex > 0 && this.listChip[startIndex].n発声位置 == this.listChip[i].n発声位置)
403 startIndex++; // 1つ小さく過ぎているので、戻す
405 for (int j = startIndex; j <= i; j++)
407 if (((this.listChip[j].eチャンネル番号 == EChannel.BarLine) || (this.listChip[j].eチャンネル番号 == EChannel.BeatLine)) &&
408 (this.listChip[j].n整数値 == (36 * 36 - 1)))
410 this.listChip[j].b可視 = bShowBeatBarLine;
415 //span = (TimeSpan) ( DateTime.Now - timeBeginLoad );
416 //Trace.TraceInformation( "C2 [拍線・小節線表示指定]: {0}", span.ToString() );
417 //timeBeginLoad = DateTime.Now;
420 double dbBarLength = 1.0;
421 int nPlayPosition = 0;
424 foreach (CChip chip in this.listChip)
426 chip.CalculatePlayPositionMs(e種別, BASEBPM, listBPM, listAVIPAN, listBGAPAN,
427 ref bpm, ref dbBarLength, ref nPlayPosition, ref ms, ref nBar);
429 if (this.db再生速度 > 0.0)
431 double _db再生速度 = (CDTXMania.Instance.DTXVmode.Enabled) ? this.dbDTXVPlaySpeed : this.db再生速度;
432 foreach (CChip chip in this.listChip)
434 chip.ApplyPlaySpeed(_db再生速度);
438 //span = (TimeSpan) ( DateTime.Now - timeBeginLoad );
439 //Trace.TraceInformation( "発声時刻計算: {0}", span.ToString() );
440 //timeBeginLoad = DateTime.Now;
442 this.t各自動再生音チップの再生時刻を変更する(nBGMAdjust);
443 //span = (TimeSpan) ( DateTime.Now - timeBeginLoad );
444 //Trace.TraceInformation( "再生時刻変更: {0}", span.ToString() );
445 //timeBeginLoad = DateTime.Now;
446 #region [ 可視チップ数カウント ]
447 for (EPart inst = EPart.Drums; inst <= EPart.Bass; ++inst)
449 this.n可視チップ数[inst] = 0;
451 foreach (CChip chip in this.listChip)
453 if (chip.bDrums可視チップ && !chip.b空打ちチップである)
455 this.n可視チップ数.Drums++;
457 if (chip.bGuitar可視チップ)
459 this.n可視チップ数.Guitar++;
467 //span = (TimeSpan) ( DateTime.Now - timeBeginLoad );
468 //Trace.TraceInformation( "可視チップ数カウント {0}", span.ToString() );
469 //timeBeginLoad = DateTime.Now;
470 #region [ チップの種類を分類し、対応するフラグを立てる ]
471 foreach (CChip chip in this.listChip)
474 chip.bWAVを使うチャンネルである &&
475 this.listWAV.ContainsKey(chip.n整数値_内部番号)) &&
476 !this.listWAV[chip.n整数値_内部番号].listこのWAVを使用するチャンネル番号の集合.Contains(chip.eチャンネル番号))
478 this.listWAV[chip.n整数値_内部番号].listこのWAVを使用するチャンネル番号の集合.Add(chip.eチャンネル番号);
480 switch (chip.ESoundChipTypeを得る)
482 case ESoundChipType.Drums:
483 if (!chip.b空打ちチップである)
485 this.listWAV[chip.n整数値_内部番号].bIsDrumsSound = true;
488 case ESoundChipType.Guitar:
489 this.listWAV[chip.n整数値_内部番号].bIsGuitarSound = true; break;
490 case ESoundChipType.Bass:
491 this.listWAV[chip.n整数値_内部番号].bIsBassSound = true; break;
492 case ESoundChipType.SE:
493 this.listWAV[chip.n整数値_内部番号].bIsSESound = true; break;
494 case ESoundChipType.BGM:
495 this.listWAV[chip.n整数値_内部番号].bIsBGMSound = true; break;
500 //span = (TimeSpan) ( DateTime.Now - timeBeginLoad );
501 //Trace.TraceInformation( "ch番号集合確認: {0}", span.ToString() );
502 //timeBeginLoad = DateTime.Now;
504 byte[] buffer = null;
507 FileStream stream = new FileStream(this.strファイル名の絶対パス, FileMode.Open, FileAccess.Read);
508 buffer = new byte[stream.Length];
509 stream.Read(buffer, 0, (int)stream.Length);
512 catch (Exception exception)
514 Trace.TraceError(exception.Message);
515 Trace.TraceError("DTXのハッシュの計算に失敗しました。({0})", this.strファイル名の絶対パス);
519 byte[] buffer2 = new MD5CryptoServiceProvider().ComputeHash(buffer);
520 StringBuilder sb = new StringBuilder();
521 foreach (byte b in buffer2)
523 sb.Append(b.ToString("x2"));
525 this.strハッシュofDTXファイル = sb.ToString();
529 this.strハッシュofDTXファイル = "00000000000000000000000000000000";
533 // #36177 使用レーン数の表示 add ikanick 16.03.20
534 #region [ 使用レーン数カウント ]
536 for (EPart inst = EPart.Drums; inst <= EPart.Bass; ++inst)
538 this.n使用レーン数[inst] = EUseLanes.Other;
540 foreach (CChip chip in this.listChip)
542 int ch = (int)chip.eチャンネル番号;
543 if (chip.bDrums可視チップ)
545 if (this.n使用レーン数.Drums == EUseLanes.Other) this.n使用レーン数.Drums = EUseLanes.Dr_6;
546 if ( ( this.n使用レーン数.Drums != EUseLanes.Dr_10 ) && ( this.n使用レーン数.Drums != EUseLanes.Dr_12 ) )
548 if ((chip.eチャンネル番号 == EChannel.FloorTom)
549 || (chip.eチャンネル番号 == EChannel.HiHatOpen)
550 || (chip.eチャンネル番号 == EChannel.RideCymbal)
551 || (chip.eチャンネル番号 == EChannel.LeftCymbal))
553 this.n使用レーン数.Drums = EUseLanes.Dr_10;
556 if (this.n使用レーン数.Drums != EUseLanes.Dr_12)
558 if ((chip.eチャンネル番号 == EChannel.LeftPedal)
559 || (chip.eチャンネル番号 == EChannel.LeftBassDrum))
561 this.n使用レーン数.Drums = EUseLanes.Dr_12;
565 if (chip.bGuitar可視チップ)
568 if ( this.n使用レーン数.Guitar == EUseLanes.Other ) this.n使用レーン数.Guitar = EUseLanes.GB_3;
573 if ( this.n使用レーン数.Bass == EUseLanes.Other ) this.n使用レーン数.Bass = EUseLanes.GB_3;
576 //Trace.TraceInformation( "LeftPedal使用=" + this.bチップがある.LeftPedal );
577 //Trace.TraceInformation( "LeftBass使用 =" + this.bチップがある.LeftBassDrum );
578 //Trace.TraceInformation( "Lane Type =" + this.n使用レーン数.Drums );
581 //span = (TimeSpan) ( DateTime.Now - timeBeginLoad );
582 //Trace.TraceInformation( "hash計算: {0}", span.ToString() );
583 //timeBeginLoad = DateTime.Now;
584 #region [ bLogDTX詳細ログ出力 ]
585 if (CDTXMania.Instance.ConfigIni.bLogDTX)
587 foreach (CWAV cwav in this.listWAV.Values)
589 Trace.TraceInformation(cwav.ToString());
591 foreach (CAVI cavi in this.listAVI.Values)
593 Trace.TraceInformation(cavi.ToString());
595 foreach (CAVIPAN cavipan in this.listAVIPAN.Values)
597 Trace.TraceInformation(cavipan.ToString());
599 foreach (CBGA cbga in this.listBGA.Values)
601 Trace.TraceInformation(cbga.ToString());
603 foreach (CBGAPAN cbgapan in this.listBGAPAN.Values)
605 Trace.TraceInformation(cbgapan.ToString());
607 foreach (CBMP cbmp in this.listBMP.Values)
609 Trace.TraceInformation(cbmp.ToString());
611 foreach (CBMPTEX cbmptex in this.listBMPTEX.Values)
613 Trace.TraceInformation(cbmptex.ToString());
615 foreach (CBPM cbpm3 in this.listBPM.Values)
617 Trace.TraceInformation(cbpm3.ToString());
619 foreach (CChip chip in this.listChip)
621 Trace.TraceInformation(chip.ToString());
633 /// #34016 LP/LBD使用譜面の吸収
635 public void ReassignLP()
637 if ( this.bチップがある.LeftPedal )
639 if ( this.bチップがある.LeftBassDrum )
642 // * LPは、HO(foot splash)に割り当て。あるいは、HO(foot splash)とHC(close)のいずれかに割り当てる。
643 // BPMから4分音符の長さを計算し、それより長いかどうかでHO/HCの仕分けを決定。
644 // * チップ音にサウンドファイルが割り当てられていない場合は、HCに割り当て
645 // * HO未使用の譜面の場合は、HCに割り当て
647 double bpm = this.BPM + this.BASEBPM;
648 double dbBarLength = 1.0;
649 double nLen4thNoteMs = (int) ( ( 60.0 / bpm / dbBarLength ) * 10 * 10 * 10 );
651 for ( int i = 0; i < this.listChip.Count; i++ )
653 // switch-caseにすると、listchip[i]の書き換えができないので、if-elseで記述
654 if ( this.listChip[ i ].eチャンネル番号 == EChannel.LeftBassDrum )
656 this.listChip[ i ].eチャンネル番号 = EChannel.BassDrum;
658 else if ( this.listChip[ i ].eチャンネル番号 == EChannel.LeftPedal )
660 int len = this.listChip[ i ].GetDuration(); // WAV未割当の場合は0が返る
661 // HHOpen未使用の譜面であれば、無条件にHHCloseに落としこむ
662 this.listChip[ i ].eチャンネル番号 = ( len < nLen4thNoteMs || !this.bチップがある.HHOpen ) ? EChannel.HiHatClose : EChannel.HiHatOpen;
664 else if ( this.listChip[ i ].eチャンネル番号 == EChannel.BPM )
666 bpm = this.BPM + this.BASEBPM;
667 nLen4thNoteMs = (int) ( ( 60.0 / bpm / dbBarLength / 2 ) * 10 * 10 * 10 );
669 else if ( this.listChip[ i ].eチャンネル番号 == EChannel.BPMEx )
671 int n内部番号 = listChip[ i ].n整数値_内部番号;
672 if ( listBPM.ContainsKey( n内部番号 ) )
674 bpm = ( ( listBPM[ n内部番号 ].n表記上の番号 == 0 ) ? 0.0 : this.BASEBPM ) + listBPM[ n内部番号 ].dbBPM値;
677 else if ( this.listChip[ i ].eチャンネル番号 == EChannel.BarLength )
679 dbBarLength = this.listChip[ i ].db実数値;
685 // → LPを、BD, HO, HCに割り当てる必要がある。
686 // * BDへの割り当ては、BDレーンで同じ音を使っているかどうかで決定
687 // * HO, HCへの割り当ては、(BDの可能性を除いた後) HOにアサイン、あるいはチップの長さを見てHC/HOにアサイン
688 // * チップ音にサウンドファイルが割り当てられていない場合は、HCに割り当て
689 // * HO未使用の譜面の場合は、HCに割り当て
691 double bpm = this.BPM + this.BASEBPM;
692 double dbBarLength = 1.0;
693 double nLen4thNoteMs = (int) ( ( 60.0 / bpm / dbBarLength ) * 10 * 10 * 10 );
695 #region [ BassDrumのファイル名一覧を作成 ]
696 List<string> listBDFilenames = new List<string>();
697 foreach ( CChip chip in listChip )
699 if (chip.eチャンネル番号 == EChannel.BassDrum)
701 string s = chip.GetSoundFilename();
702 if (s != null && !listBDFilenames.Contains(s))
704 listBDFilenames.Add(s);
710 for ( int i = 0; i < this.listChip.Count; i++ )
712 if ( this.listChip[ i ].eチャンネル番号 == EChannel.LeftPedal )
714 string s = listChip[i].GetSoundFilename();
715 if (listBDFilenames.Contains(s))
717 this.listChip[i].eチャンネル番号 = EChannel.BassDrum;
721 int len = this.listChip[ i ].GetDuration(); // WAV未割当の場合は0が返る
722 // HHOpen未使用の譜面であれば、無条件にHHCloseに落としこむ
723 this.listChip[ i ].eチャンネル番号 = ( len < nLen4thNoteMs || !this.bチップがある.HHOpen ) ? EChannel.HiHatClose : EChannel.HiHatOpen;
726 else if ( this.listChip[ i ].eチャンネル番号 == EChannel.BPM )
728 bpm = this.BPM + this.BASEBPM;
729 nLen4thNoteMs = (int) ( ( 60.0 / bpm / dbBarLength / 2 ) * 10 * 10 * 10 );
731 else if ( this.listChip[ i ].eチャンネル番号 == EChannel.BPMEx )
733 int n内部番号 = listChip[ i ].n整数値_内部番号;
734 if ( listBPM.ContainsKey( n内部番号 ) )
736 bpm = ( ( listBPM[ n内部番号 ].n表記上の番号 == 0 ) ? 0.0 : this.BASEBPM ) + listBPM[ n内部番号 ].dbBPM値;
739 else if ( this.listChip[ i ].eチャンネル番号 == EChannel.BarLength )
741 dbBarLength = this.listChip[ i ].db実数値;
744 listBDFilenames.Clear();
745 listBDFilenames = null;
748 else if ( this.bチップがある.LeftBassDrum )
751 for ( int i = 0; i < this.listChip.Count; i++ )
753 if ( this.listChip[ i ].eチャンネル番号 == EChannel.LeftBassDrum )
755 this.listChip[ i ].eチャンネル番号 = EChannel.BassDrum;
764 private bool t入力_コマンド文字列を抜き出す(ref CharEnumerator ce, ref StringBuilder sb文字列)
766 if (!this.t入力_空白をスキップする(ref ce))
767 return false; // 文字が尽きた
769 #region [ コマンド終端文字(':')、半角空白、コメント開始文字(';')、改行のいずれかが出現するまでをコマンド文字列と見なし、sb文字列 にコピーする。]
771 while (ce.Current != ':' && ce.Current != ' ' && ce.Current != ';' && ce.Current != '\n')
773 sb文字列.Append(ce.Current);
776 return false; // 文字が尽きた
781 #region [ コマンド終端文字(':')で終端したなら、その次から空白をスキップしておく。]
783 if (ce.Current == ':')
786 return false; // 文字が尽きた
788 if (!this.t入力_空白をスキップする(ref ce))
789 return false; // 文字が尽きた
796 private bool t入力_コメントをスキップする(ref CharEnumerator ce)
798 // 改行が現れるまでをコメントと見なしてスキップする。
800 while (ce.Current != '\n')
803 return false; // 文字が尽きた
806 // 改行の次の文字へ移動した結果を返す。
808 return ce.MoveNext();
810 private bool t入力_コメント文字列を抜き出す(ref CharEnumerator ce, ref StringBuilder sb文字列)
812 if (ce.Current != ';') // コメント開始文字(';')じゃなければ正常帰還。
815 if (!ce.MoveNext()) // ';' の次で文字列が終わってたら終了帰還。
818 #region [ ';' の次の文字から '\n' の1つ前までをコメント文字列と見なし、sb文字列にコピーする。]
820 while (ce.Current != '\n')
822 sb文字列.Append(ce.Current);
832 private void t入力_パラメータ食い込みチェック(string strコマンド名, ref string strコマンド, ref string strパラメータ)
834 if ((strコマンド.Length > strコマンド名.Length) && strコマンド.StartsWith(strコマンド名, StringComparison.OrdinalIgnoreCase))
836 strパラメータ = strコマンド.Substring(strコマンド名.Length).Trim();
837 strコマンド = strコマンド.Substring(0, strコマンド名.Length);
840 private bool t入力_パラメータ文字列を抜き出す(ref CharEnumerator ce, ref StringBuilder sb文字列)
842 if (!this.t入力_空白をスキップする(ref ce))
843 return false; // 文字が尽きた
845 #region [ 改行またはコメント開始文字(';')が出現するまでをパラメータ文字列と見なし、sb文字列 にコピーする。]
847 while (ce.Current != '\n' && ce.Current != ';')
849 sb文字列.Append(ce.Current);
859 private bool t入力_空白と改行をスキップする(ref CharEnumerator ce)
861 // 空白と改行が続く間はこれらをスキップする。
863 while (ce.Current == ' ' || ce.Current == '\n')
865 if (ce.Current == '\n')
866 this.n現在の行数++; // 改行文字では行番号が増える。
869 return false; // 文字が尽きた
874 private bool t入力_空白をスキップする(ref CharEnumerator ce)
878 while (ce.Current == ' ')
881 return false; // 文字が尽きた
886 private void t入力_行解析(ref StringBuilder sbコマンド, ref StringBuilder sbパラメータ, ref StringBuilder sbコメント)
888 string strコマンド = sbコマンド.ToString();
889 string strパラメータ = sbパラメータ.ToString().Trim();
890 string strコメント = sbコメント.ToString();
896 if (strコマンド.StartsWith("IF", StringComparison.OrdinalIgnoreCase))
898 this.t入力_パラメータ食い込みチェック("IF", ref strコマンド, ref strパラメータ);
900 if (this.bstackIFからENDIFをスキップする.Count == 255)
902 Trace.TraceWarning("#IF の入れ子の数が 255 を超えました。この #IF を無視します。[{0}: {1}行]", this.strファイル名の絶対パス, this.n現在の行数);
904 else if (this.bstackIFからENDIFをスキップする.Peek())
906 this.bstackIFからENDIFをスキップする.Push(true); // 親が true ならその入れ子も問答無用で true 。
908 else // 親が false なら入れ子はパラメータと乱数を比較して結果を判断する。
912 if (!int.TryParse(strパラメータ, out n数値))
915 this.bstackIFからENDIFをスキップする.Push(n数値 != this.n現在の乱数); // 乱数と数値が一致したら true 。
922 else if (strコマンド.StartsWith("ENDIF", StringComparison.OrdinalIgnoreCase))
924 this.t入力_パラメータ食い込みチェック("ENDIF", ref strコマンド, ref strパラメータ);
926 if (this.bstackIFからENDIFをスキップする.Count > 1)
928 this.bstackIFからENDIFをスキップする.Pop(); // 入れ子を1つ脱出。
932 Trace.TraceWarning("#ENDIF に対応する #IF がありません。この #ENDIF を無視します。[{0}: {1}行]", this.strファイル名の絶対パス, this.n現在の行数);
938 else if (!this.bstackIFからENDIFをスキップする.Peek()) // IF~ENDIF をスキップするなら以下はすべて無視。
942 if (strコマンド.StartsWith("PATH_WAV", StringComparison.OrdinalIgnoreCase))
944 this.t入力_パラメータ食い込みチェック("PATH_WAV", ref strコマンド, ref strパラメータ);
945 this.PATH_WAV = strパラメータ;
951 else if (strコマンド.StartsWith("TITLE", StringComparison.OrdinalIgnoreCase))
953 this.t入力_パラメータ食い込みチェック("TITLE", ref strコマンド, ref strパラメータ);
954 this.TITLE = strパラメータ;
960 else if (strコマンド.StartsWith("ARTIST", StringComparison.OrdinalIgnoreCase))
962 this.t入力_パラメータ食い込みチェック("ARTIST", ref strコマンド, ref strパラメータ);
963 this.ARTIST = strパラメータ;
969 else if (strコマンド.StartsWith("COMMENT", StringComparison.OrdinalIgnoreCase))
971 this.t入力_パラメータ食い込みチェック("COMMENT", ref strコマンド, ref strパラメータ);
972 this.COMMENT = strパラメータ;
976 #region [ DLEVEL, PLAYLEVEL ]
979 strコマンド.StartsWith("DLEVEL", StringComparison.OrdinalIgnoreCase) ||
980 strコマンド.StartsWith("PLAYLEVEL", StringComparison.OrdinalIgnoreCase))
982 this.t入力_パラメータ食い込みチェック("DLEVEL", ref strコマンド, ref strパラメータ);
983 this.t入力_パラメータ食い込みチェック("PLAYLEVEL", ref strコマンド, ref strパラメータ);
986 if (int.TryParse(strパラメータ, out dlevel))
988 this.LEVEL.Drums = Math.Min(Math.Max(dlevel, 0), 100); // 0~100 に丸める
995 else if (strコマンド.StartsWith("GLEVEL", StringComparison.OrdinalIgnoreCase))
997 this.t入力_パラメータ食い込みチェック("GLEVEL", ref strコマンド, ref strパラメータ);
1000 if (int.TryParse(strパラメータ, out glevel))
1002 this.LEVEL.Guitar = Math.Min(Math.Max(glevel, 0), 100); // 0~100 に丸める
1009 else if (strコマンド.StartsWith("BLEVEL", StringComparison.OrdinalIgnoreCase))
1011 this.t入力_パラメータ食い込みチェック("BLEVEL", ref strコマンド, ref strパラメータ);
1014 if (int.TryParse(strパラメータ, out blevel))
1016 this.LEVEL.Bass = Math.Min(Math.Max(blevel, 0), 100); // 0~100 に丸める
1021 #if TEST_NOTEOFFMODE
1022 else if (str.StartsWith("SUPRESSNOTEOFF_HIHAT", StringComparison.OrdinalIgnoreCase)) {
1023 this.t入力・パラメータ食い込みチェック("SUPRESSNOTEOFF_HIHAT", ref str, ref str2);
1024 this.bHH演奏で直前のHHを消音する = !str2.ToLower().Equals("on");
1026 else if (str.StartsWith("SUPRESSNOTEOFF_GUITAR", StringComparison.OrdinalIgnoreCase)) {
1027 this.t入力・パラメータ食い込みチェック("SUPRESSNOTEOFF_GUITAR", ref str, ref str2);
1028 this.bGUITAR演奏で直前のGUITARを消音する = !str2.ToLower().Equals("on");
1030 else if (str.StartsWith("SUPRESSNOTEOFF_BASS", StringComparison.OrdinalIgnoreCase)) {
1031 this.t入力・パラメータ食い込みチェック("SUPRESSNOTEOFF_BASS", ref str, ref str2);
1032 this.bBASS演奏で直前のBASSを消音する = !str2.ToLower().Equals("on");
1037 else if (strコマンド.StartsWith("GENRE", StringComparison.OrdinalIgnoreCase))
1039 this.t入力_パラメータ食い込みチェック("GENRE", ref strコマンド, ref strパラメータ);
1040 this.GENRE = strパラメータ;
1044 #region [ HIDDENLEVEL ]
1046 else if (strコマンド.StartsWith("HIDDENLEVEL", StringComparison.OrdinalIgnoreCase))
1048 this.t入力_パラメータ食い込みチェック("HIDDENLEVEL", ref strコマンド, ref strパラメータ);
1049 this.HIDDENLEVEL = strパラメータ.ToLower().Equals("on");
1053 #region [ STAGEFILE ]
1055 else if (strコマンド.StartsWith("STAGEFILE", StringComparison.OrdinalIgnoreCase))
1057 this.t入力_パラメータ食い込みチェック("STAGEFILE", ref strコマンド, ref strパラメータ);
1058 this.STAGEFILE = strパラメータ;
1064 else if (strコマンド.StartsWith("PREVIEW", StringComparison.OrdinalIgnoreCase))
1066 this.t入力_パラメータ食い込みチェック("PREVIEW", ref strコマンド, ref strパラメータ);
1067 this.PREVIEW = strパラメータ;
1071 #region [ PREIMAGE ]
1073 else if (strコマンド.StartsWith("PREIMAGE", StringComparison.OrdinalIgnoreCase))
1075 this.t入力_パラメータ食い込みチェック("PREIMAGE", ref strコマンド, ref strパラメータ);
1076 this.PREIMAGE = strパラメータ;
1080 #region [ PREMOVIE ]
1082 else if (strコマンド.StartsWith("PREMOVIE", StringComparison.OrdinalIgnoreCase))
1084 this.t入力_パラメータ食い込みチェック("PREMOVIE", ref strコマンド, ref strパラメータ);
1085 this.PREMOVIE = strパラメータ;
1089 #region [ USE 556 x 710 BGAAVI ]
1091 else if (strコマンド.StartsWith("USE556X710BGAAVI", StringComparison.OrdinalIgnoreCase))
1093 this.t入力_パラメータ食い込みチェック("USE556X710BGAAVI", ref strコマンド, ref strパラメータ);
1094 this.bUse556x710BGAAVI = strパラメータ == "1" ? true : false;
1097 #region [ BACKGROUND_GR ]
1099 else if (strコマンド.StartsWith("BACKGROUND_GR", StringComparison.OrdinalIgnoreCase))
1101 this.t入力_パラメータ食い込みチェック("BACKGROUND_GR", ref strコマンド, ref strパラメータ);
1102 this.BACKGROUND_GR = strパラメータ;
1106 #region [ BACKGROU}ND, WALL ]
1109 strコマンド.StartsWith("BACKGROUND", StringComparison.OrdinalIgnoreCase) ||
1110 strコマンド.StartsWith("WALL", StringComparison.OrdinalIgnoreCase))
1112 this.t入力_パラメータ食い込みチェック("BACKGROUND", ref strコマンド, ref strパラメータ);
1113 this.t入力_パラメータ食い込みチェック("WALL", ref strコマンド, ref strパラメータ);
1114 this.BACKGROUND = strパラメータ;
1120 else if (strコマンド.StartsWith("RANDOM", StringComparison.OrdinalIgnoreCase))
1122 this.t入力_パラメータ食い込みチェック("RANDOM", ref strコマンド, ref strパラメータ);
1125 if (!int.TryParse(strパラメータ, out n数値))
1128 this.n現在の乱数 = CDTXMania.Instance.Random.Next(n数値) + 1; // 1~数値 までの乱数を生成。
1132 #region [ SOUND_NOWLOADING ]
1134 else if (strコマンド.StartsWith("SOUND_NOWLOADING", StringComparison.OrdinalIgnoreCase))
1136 this.t入力_パラメータ食い込みチェック("SOUND_NOWLOADING", ref strコマンド, ref strパラメータ);
1137 this.SOUND_NOWLOADING = strパラメータ;
1143 else if (strコマンド.StartsWith("BPM", StringComparison.OrdinalIgnoreCase))
1145 this.t入力_行解析_BPM_BPMzz(strコマンド, strパラメータ, strコメント);
1149 #region [ DTXVPLAYSPEED ]
1151 else if (strコマンド.StartsWith("DTXVPLAYSPEED", StringComparison.OrdinalIgnoreCase))
1153 this.t入力_パラメータ食い込みチェック("DTXVPLAYSPEED", ref strコマンド, ref strパラメータ);
1155 double dtxvplayspeed = 0.0;
1156 if (TryParse(strパラメータ, out dtxvplayspeed) && dtxvplayspeed > 0.0)
1158 this.dbDTXVPlaySpeed = dtxvplayspeed;
1163 else if (!this.bヘッダのみ) // ヘッダのみの解析の場合、以下は無視。
1167 if (strコマンド.StartsWith("PANEL", StringComparison.OrdinalIgnoreCase))
1169 this.t入力_パラメータ食い込みチェック("PANEL", ref strコマンド, ref strパラメータ);
1171 int dummyResult; // #23885 2010.12.12 yyagi: not to confuse "#PANEL strings (panel)" and "#PANEL int (panpot of EL)"
1172 if (!int.TryParse(strパラメータ, out dummyResult))
1173 { // 数値じゃないならPANELとみなす
1174 this.PANEL = strパラメータ; //
1181 #region [ MIDIFILE ]
1183 else if (strコマンド.StartsWith("MIDIFILE", StringComparison.OrdinalIgnoreCase))
1185 this.t入力_パラメータ食い込みチェック("MIDIFILE", ref strコマンド, ref strパラメータ);
1186 this.MIDIFILE = strパラメータ;
1190 #region [ MIDINOTE ]
1192 else if (strコマンド.StartsWith("MIDINOTE", StringComparison.OrdinalIgnoreCase))
1194 this.t入力_パラメータ食い込みチェック("MIDINOTE", ref strコマンド, ref strパラメータ);
1195 this.MIDINOTE = strパラメータ.ToLower().Equals("on");
1199 #region [ BLACKCOLORKEY ]
1201 else if (strコマンド.StartsWith("BLACKCOLORKEY", StringComparison.OrdinalIgnoreCase))
1203 this.t入力_パラメータ食い込みチェック("BLACKCOLORKEY", ref strコマンド, ref strパラメータ);
1204 this.BLACKCOLORKEY = strパラメータ.ToLower().Equals("on");
1210 else if (strコマンド.StartsWith("BASEBPM", StringComparison.OrdinalIgnoreCase))
1212 this.t入力_パラメータ食い込みチェック("BASEBPM", ref strコマンド, ref strパラメータ);
1214 double basebpm = 0.0;
1215 //if( double.TryParse( str2, out num6 ) && ( num6 > 0.0 ) )
1216 if (TryParse(strパラメータ, out basebpm) && basebpm > 0.0) // #23880 2010.12.30 yyagi: alternative TryParse to permit both '.' and ',' for decimal point
1217 { // #24204 2011.01.21 yyagi: Fix the condition correctly
1218 this.BASEBPM = basebpm;
1223 #region [ SOUND_STAGEFAILED ]
1225 else if (strコマンド.StartsWith("SOUND_STAGEFAILED", StringComparison.OrdinalIgnoreCase))
1227 this.t入力_パラメータ食い込みチェック("SOUND_STAGEFAILED", ref strコマンド, ref strパラメータ);
1228 this.SOUND_STAGEFAILED = strパラメータ;
1232 #region [ SOUND_FULLCOMBO ]
1234 else if (strコマンド.StartsWith("SOUND_FULLCOMBO", StringComparison.OrdinalIgnoreCase))
1236 this.t入力_パラメータ食い込みチェック("SOUND_FULLCOMBO", ref strコマンド, ref strパラメータ);
1237 this.SOUND_FULLCOMBO = strパラメータ;
1241 #region [ SOUND_AUDIENCE ]
1243 else if (strコマンド.StartsWith("SOUND_AUDIENCE", StringComparison.OrdinalIgnoreCase))
1245 this.t入力_パラメータ食い込みチェック("SOUND_AUDIENCE", ref strコマンド, ref strパラメータ);
1246 this.SOUND_AUDIENCE = strパラメータ;
1253 else if (!this.t入力_行解析_WAVVOL_VOLUME(strコマンド, strパラメータ, strコメント) &&
1254 !this.t入力_行解析_WAVPAN_PAN(strコマンド, strパラメータ, strコメント) &&
1255 !this.t入力_行解析_WAV(strコマンド, strパラメータ, strコメント) &&
1256 !this.t入力_行解析_BMPTEX(strコマンド, strパラメータ, strコメント) &&
1257 !this.t入力_行解析_BMP(strコマンド, strパラメータ, strコメント) &&
1258 !this.t入力_行解析_BGAPAN(strコマンド, strパラメータ, strコメント) &&
1259 !this.t入力_行解析_BGA(strコマンド, strパラメータ, strコメント) &&
1260 !this.t入力_行解析_AVIPAN(strコマンド, strパラメータ, strコメント) &&
1261 !this.t入力_行解析_AVI_VIDEO(strコマンド, strパラメータ, strコメント) &&
1262 // !this.t入力_行解析_BPM_BPMzz( strコマンド, strパラメータ, strコメント ) && // bヘッダのみ==trueの場合でもチェックするよう変更
1263 !this.t入力_行解析_RESULTIMAGE(strコマンド, strパラメータ, strコメント) &&
1264 !this.t入力_行解析_RESULTMOVIE(strコマンド, strパラメータ, strコメント) &&
1265 !this.t入力_行解析_RESULTSOUND(strコマンド, strパラメータ, strコメント) &&
1266 !this.t入力_行解析_SIZE(strコマンド, strパラメータ, strコメント))
1268 this.t入力_行解析_チップ配置(strコマンド, strパラメータ, strコメント);
1271 Debug.Assert(true); // #23885 2010.12.12 yyagi: dummy line to exit parsing the line
1272 // 2011.8.17 from: "int xx=0;" から変更。毎回警告が出るので。
1275 //{ // Duration測定のため、bヘッダのみ==trueでも、チップ配置は行う
1276 // this.t入力・行解析・チップ配置( strコマンド, strパラメータ, strコメント );
1280 private bool t入力_行解析_AVI_VIDEO(string strコマンド, string strパラメータ, string strコメント)
1284 #region [ "AVI" or "VIDEO" で始まらないコマンドは無効。]
1286 if (strコマンド.StartsWith("AVI", StringComparison.OrdinalIgnoreCase))
1287 strコマンド = strコマンド.Substring(3); // strコマンド から先頭の"AVI"文字を除去。
1289 else if (strコマンド.StartsWith("VIDEO", StringComparison.OrdinalIgnoreCase))
1290 strコマンド = strコマンド.Substring(5); // strコマンド から先頭の"VIDEO"文字を除去。
1299 if (strコマンド.Length < 2)
1300 return false; // AVI番号 zz がないなら無効。
1302 #region [ AVI番号 zz を取得する。]
1304 int zz = C変換.n36進数2桁の文字列を数値に変換して返す(strコマンド.Substring(0, 2));
1305 if (zz < 0 || zz >= 36 * 36)
1307 Trace.TraceError("AVI(VIDEO)番号に 00~ZZ 以外の値または不正な文字列が指定されました。[{0}: {1}行]", this.strファイル名の絶対パス, this.n現在の行数);
1313 #region [ AVIリストに {zz, avi} の組を登録する。 ]
1315 var avi = new CAVI(zz, strパラメータ, strコメント, CDTXMania.Instance.ConfigIni.nPlaySpeed);
1317 if (this.listAVI.ContainsKey(zz)) // 既にリスト中に存在しているなら削除。後のものが有効。
1318 this.listAVI.Remove(zz);
1320 this.listAVI.Add(zz, avi);
1326 private bool t入力_行解析_AVIPAN(string strコマンド, string strパラメータ, string strコメント)
1330 #region [ "AVIPAN" で始まらないコマンドは無効。]
1332 if (!strコマンド.StartsWith("AVIPAN", StringComparison.OrdinalIgnoreCase))
1335 strコマンド = strコマンド.Substring(6); // strコマンド から先頭の"AVIPAN"文字を除去。
1341 if (strコマンド.Length < 2)
1342 return false; // AVIPAN番号 zz がないなら無効。
1344 #region [ AVIPAN番号 zz を取得する。]
1346 int zz = C変換.n36進数2桁の文字列を数値に変換して返す(strコマンド.Substring(0, 2));
1347 if (zz < 0 || zz >= 36 * 36)
1349 Trace.TraceError("AVIPAN番号に 00~ZZ 以外の値または不正な文字列が指定されました。[{0}: {1}行]", this.strファイル名の絶対パス, this.n現在の行数);
1355 var avipan = new CAVIPAN()
1360 // パラメータ引数(14個)を取得し、avipan に登録していく。
1362 string[] strParams = strパラメータ.Split(new char[] { ' ', ',', '(', ')', '[', ']', 'x', '|' }, StringSplitOptions.RemoveEmptyEntries);
1364 #region [ パラメータ引数は全14個ないと無効。]
1366 if (strParams.Length < 14)
1368 Trace.TraceError("AVIPAN: 引数が足りません。[{0}: {1}行]", this.strファイル名の絶対パス, this.n現在の行数);
1377 #region [ 1. AVI番号 ]
1379 if (string.IsNullOrEmpty(strParams[i]) || strParams[i].Length > 2)
1381 Trace.TraceError("AVIPAN: {2}番目の数(AVI番号)が異常です。[{0}: {1}行]", this.strファイル名の絶対パス, this.n現在の行数, i + 1);
1384 avipan.nAVI番号 = C変換.n36進数2桁の文字列を数値に変換して返す(strParams[i]);
1385 if (avipan.nAVI番号 < 1 || avipan.nAVI番号 >= 36 * 36)
1387 Trace.TraceError("AVIPAN: {2}番目の数(AVI番号)が異常です。[{0}: {1}行]", this.strファイル名の絶対パス, this.n現在の行数, i + 1);
1393 #region [ 2. 開始転送サイズ・幅 ]
1396 if (!int.TryParse(strParams[i], out n値))
1398 Trace.TraceError("AVIPAN: {2}番目の引数(開始転送サイズ・幅)が異常です。[{0}: {1}行]", this.strファイル名の絶対パス, this.n現在の行数, i + 1);
1401 avipan.sz開始サイズ.Width = n値;
1405 #region [ 3. 転送サイズ・高さ ]
1408 if (!int.TryParse(strParams[i], out n値))
1410 Trace.TraceError("AVIPAN: {2}番目の引数(開始転送サイズ・高さ)が異常です。[{0}: {1}行]", this.strファイル名の絶対パス, this.n現在の行数, i + 1);
1413 avipan.sz開始サイズ.Height = n値;
1417 #region [ 4. 終了転送サイズ・幅 ]
1420 if (!int.TryParse(strParams[i], out n値))
1422 Trace.TraceError("AVIPAN: {2}番目の引数(終了転送サイズ・幅)が異常です。[{0}: {1}行]", this.strファイル名の絶対パス, this.n現在の行数, i + 1);
1425 avipan.sz終了サイズ.Width = n値;
1429 #region [ 5. 終了転送サイズ・高さ ]
1432 if (!int.TryParse(strParams[i], out n値))
1434 Trace.TraceError("AVIPAN: {2}番目の引数(終了転送サイズ・高さ)が異常です。[{0}: {1}行]", this.strファイル名の絶対パス, this.n現在の行数, i + 1);
1437 avipan.sz終了サイズ.Height = n値;
1441 #region [ 6. 動画側開始位置・X ]
1444 if (!int.TryParse(strParams[i], out n値))
1446 Trace.TraceError("AVIPAN: {2}番目の引数(動画側開始位置・X)が異常です。[{0}: {1}行]", this.strファイル名の絶対パス, this.n現在の行数, i + 1);
1449 avipan.pt動画側開始位置.X = n値;
1453 #region [ 7. 動画側開始位置・Y ]
1456 if (!int.TryParse(strParams[i], out n値))
1458 Trace.TraceError("AVIPAN: {2}番目の引数(動画側開始位置・Y)が異常です。[{0}: {1}行]", this.strファイル名の絶対パス, this.n現在の行数, i + 1);
1461 avipan.pt動画側開始位置.Y = n値;
1465 #region [ 8. 動画側終了位置・X ]
1468 if (!int.TryParse(strParams[i], out n値))
1470 Trace.TraceError("AVIPAN: {2}番目の引数(動画側終了位置・X)が異常です。[{0}: {1}行]", this.strファイル名の絶対パス, this.n現在の行数, i + 1);
1473 avipan.pt動画側終了位置.X = n値;
1477 #region [ 9. 動画側終了位置・Y ]
1480 if (!int.TryParse(strParams[i], out n値))
1482 Trace.TraceError("AVIPAN: {2}番目の引数(動画側終了位置・Y)が異常です。[{0}: {1}行]", this.strファイル名の絶対パス, this.n現在の行数, i + 1);
1485 avipan.pt動画側終了位置.Y = n値;
1489 #region [ 10.表示側開始位置・X ]
1492 if (!int.TryParse(strParams[i], out n値))
1494 Trace.TraceError("AVIPAN: {2}番目の引数(表示側開始位置・X)が異常です。[{0}: {1}行]", this.strファイル名の絶対パス, this.n現在の行数, i + 1);
1497 avipan.pt表示側開始位置.X = n値;
1501 #region [ 11.表示側開始位置・Y ]
1504 if (!int.TryParse(strParams[i], out n値))
1506 Trace.TraceError("AVIPAN: {2}番目の引数(表示側開始位置・Y)が異常です。[{0}: {1}行]", this.strファイル名の絶対パス, this.n現在の行数, i + 1);
1509 avipan.pt表示側開始位置.Y = n値;
1513 #region [ 12.表示側終了位置・X ]
1516 if (!int.TryParse(strParams[i], out n値))
1518 Trace.TraceError("AVIPAN: {2}番目の引数(表示側終了位置・X)が異常です。[{0}: {1}行]", this.strファイル名の絶対パス, this.n現在の行数, i + 1);
1521 avipan.pt表示側終了位置.X = n値;
1525 #region [ 13.表示側終了位置・Y ]
1528 if (!int.TryParse(strParams[i], out n値))
1530 Trace.TraceError("AVIPAN: {2}番目の引数(表示側終了位置・Y)が異常です。[{0}: {1}行]", this.strファイル名の絶対パス, this.n現在の行数, i + 1);
1533 avipan.pt表示側終了位置.Y = n値;
1540 if (!int.TryParse(strParams[i], out n値))
1542 Trace.TraceError("AVIPAN: {2}番目の引数(移動時間)が異常です。[{0}: {1}行]", this.strファイル名の絶対パス, this.n現在の行数, i + 1);
1549 avipan.n移動時間ct = n値;
1554 #region [ AVIPANリストに {zz, avipan} の組を登録する。]
1556 if (this.listAVIPAN.ContainsKey(zz)) // 既にリスト中に存在しているなら削除。後のものが有効。
1557 this.listAVIPAN.Remove(zz);
1559 this.listAVIPAN.Add(zz, avipan);
1565 private bool t入力_行解析_BGA(string strコマンド, string strパラメータ, string strコメント)
1569 #region [ "BGA" で始まらないコマンドは無効。]
1571 if (!strコマンド.StartsWith("BGA", StringComparison.OrdinalIgnoreCase))
1574 strコマンド = strコマンド.Substring(3); // strコマンド から先頭の"BGA"文字を除去。
1580 if (strコマンド.Length < 2)
1581 return false; // BGA番号 zz がないなら無効。
1583 #region [ BGA番号 zz を取得する。]
1585 int zz = C変換.n36進数2桁の文字列を数値に変換して返す(strコマンド.Substring(0, 2));
1586 if (zz < 0 || zz >= 36 * 36)
1588 Trace.TraceError("BGA番号に 00~ZZ 以外の値または不正な文字列が指定されました。[{0}: {1}行]", this.strファイル名の絶対パス, this.n現在の行数);
1594 var bga = new CBGA()
1599 // パラメータ引数(7個)を取得し、bga に登録していく。
1601 string[] strParams = strパラメータ.Split(new char[] { ' ', ',', '(', ')', '[', ']', 'x', '|' }, StringSplitOptions.RemoveEmptyEntries);
1603 #region [ パラメータ引数は全7個ないと無効。]
1605 if (strParams.Length < 7)
1607 Trace.TraceError("BGA: 引数が足りません。[{0}: {1}行]", this.strファイル名の絶対パス, this.n現在の行数);
1618 if (string.IsNullOrEmpty(strParams[i]) || strParams[i].Length > 2)
1620 Trace.TraceError("BGA: {2}番目の数(BMP番号)が異常です。[{0}: {1}行]", this.strファイル名の絶対パス, this.n現在の行数, i + 1);
1623 bga.nBMP番号 = C変換.n36進数2桁の文字列を数値に変換して返す(strParams[i]);
1624 if (bga.nBMP番号 < 1 || bga.nBMP番号 >= 36 * 36)
1626 Trace.TraceError("BGA: {2}番目の数(BMP番号)が異常です。[{0}: {1}行]", this.strファイル名の絶対パス, this.n現在の行数, i + 1);
1632 #region [ 2.画像側位置1・X ]
1635 if (!int.TryParse(strParams[i], out n値))
1637 Trace.TraceError("BGA: {2}番目の引数(画像側位置1・X)が異常です。[{0}: {1}行]", this.strファイル名の絶対パス, this.n現在の行数, i + 1);
1640 bga.pt画像側左上座標.X = n値;
1644 #region [ 3.画像側位置1・Y ]
1647 if (!int.TryParse(strParams[i], out n値))
1649 Trace.TraceError("BGA: {2}番目の引数(画像側位置1・Y)が異常です。[{0}: {1}行]", this.strファイル名の絶対パス, this.n現在の行数, i + 1);
1652 bga.pt画像側左上座標.Y = n値;
1656 #region [ 4.画像側位置2・X ]
1659 if (!int.TryParse(strParams[i], out n値))
1661 Trace.TraceError("BGA: {2}番目の引数(画像側位置2・X)が異常です。[{0}: {1}行]", this.strファイル名の絶対パス, this.n現在の行数, i + 1);
1664 bga.pt画像側右下座標.X = n値;
1668 #region [ 5.画像側位置2・Y ]
1671 if (!int.TryParse(strParams[i], out n値))
1673 Trace.TraceError("BGA: {2}番目の引数(画像側座標2・Y)が異常です。[{0}: {1}行]", this.strファイル名の絶対パス, this.n現在の行数, i + 1);
1676 bga.pt画像側右下座標.Y = n値;
1680 #region [ 6.表示位置・X ]
1683 if (!int.TryParse(strParams[i], out n値))
1685 Trace.TraceError("BGA: {2}番目の引数(表示位置・X)が異常です。[{0}: {1}行]", this.strファイル名の絶対パス, this.n現在の行数, i + 1);
1692 #region [ 7.表示位置・Y ]
1695 if (!int.TryParse(strParams[i], out n値))
1697 Trace.TraceError("BGA: {2}番目の引数(表示位置・Y)が異常です。[{0}: {1}行]", this.strファイル名の絶対パス, this.n現在の行数, i + 1);
1705 #region [ 画像側座標の正規化とクリッピング。]
1707 if (bga.pt画像側左上座標.X > bga.pt画像側右下座標.X)
1709 n値 = bga.pt画像側左上座標.X;
1710 bga.pt画像側左上座標.X = bga.pt画像側右下座標.X;
1711 bga.pt画像側右下座標.X = n値;
1713 if (bga.pt画像側左上座標.Y > bga.pt画像側右下座標.Y)
1715 n値 = bga.pt画像側左上座標.Y;
1716 bga.pt画像側左上座標.Y = bga.pt画像側右下座標.Y;
1717 bga.pt画像側右下座標.Y = n値;
1721 #region [ BGAリストに {zz, bga} の組を登録する。]
1723 if (this.listBGA.ContainsKey(zz)) // 既にリスト中に存在しているなら削除。後のものが有効。
1724 this.listBGA.Remove(zz);
1726 this.listBGA.Add(zz, bga);
1732 private bool t入力_行解析_BGAPAN(string strコマンド, string strパラメータ, string strコメント)
1736 #region [ "BGAPAN" で始まらないコマンドは無効。]
1738 if (!strコマンド.StartsWith("BGAPAN", StringComparison.OrdinalIgnoreCase))
1741 strコマンド = strコマンド.Substring(6); // strコマンド から先頭の"BGAPAN"文字を除去。
1747 if (strコマンド.Length < 2)
1748 return false; // BGAPAN番号 zz がないなら無効。
1750 #region [ BGAPAN番号 zz を取得する。]
1752 int zz = C変換.n36進数2桁の文字列を数値に変換して返す(strコマンド.Substring(0, 2));
1753 if (zz < 0 || zz >= 36 * 36)
1755 Trace.TraceError("BGAPAN番号に 00~ZZ 以外の値または不正な文字列が指定されました。[{0}: {1}行]", this.strファイル名の絶対パス, this.n現在の行数);
1761 var bgapan = new CBGAPAN()
1766 // パラメータ引数(14個)を取得し、bgapan に登録していく。
1768 string[] strParams = strパラメータ.Split(new char[] { ' ', ',', '(', ')', '[', ']', 'x', '|' }, StringSplitOptions.RemoveEmptyEntries);
1770 #region [ パラメータ引数は全14個ないと無効。]
1772 if (strParams.Length < 14)
1774 Trace.TraceError("BGAPAN: 引数が足りません。[{0}: {1}行]", this.strファイル名の絶対パス, this.n現在の行数);
1783 #region [ 1. BMP番号 ]
1785 if (string.IsNullOrEmpty(strParams[i]) || strParams[i].Length > 2)
1787 Trace.TraceError("BGAPAN: {2}番目の数(BMP番号)が異常です。[{0}: {1}行]", this.strファイル名の絶対パス, this.n現在の行数, i + 1);
1790 bgapan.nBMP番号 = C変換.n36進数2桁の文字列を数値に変換して返す(strParams[i]);
1791 if (bgapan.nBMP番号 < 1 || bgapan.nBMP番号 >= 36 * 36)
1793 Trace.TraceError("BGAPAN: {2}番目の数(BMP番号)が異常です。[{0}: {1}行]", this.strファイル名の絶対パス, this.n現在の行数, i + 1);
1799 #region [ 2. 開始転送サイズ・幅 ]
1802 if (!int.TryParse(strParams[i], out n値))
1804 Trace.TraceError("BGAPAN: {2}番目の引数(開始転送サイズ・幅)が異常です。[{0}: {1}行]", this.strファイル名の絶対パス, this.n現在の行数, i + 1);
1807 bgapan.sz開始サイズ.Width = n値;
1811 #region [ 3. 開始転送サイズ・高さ ]
1814 if (!int.TryParse(strParams[i], out n値))
1816 Trace.TraceError("BGAPAN: {2}番目の引数(開始転送サイズ・高さ)が異常です。[{0}: {1}行]", this.strファイル名の絶対パス, this.n現在の行数, i + 1);
1819 bgapan.sz開始サイズ.Height = n値;
1823 #region [ 4. 終了転送サイズ・幅 ]
1826 if (!int.TryParse(strParams[i], out n値))
1828 Trace.TraceError("BGAPAN: {2}番目の引数(終了転送サイズ・幅)が異常です。[{0}: {1}行]", this.strファイル名の絶対パス, this.n現在の行数, i + 1);
1831 bgapan.sz終了サイズ.Width = n値;
1835 #region [ 5. 終了転送サイズ・高さ ]
1838 if (!int.TryParse(strParams[i], out n値))
1840 Trace.TraceError("BGAPAN: {2}番目の引数(終了転送サイズ・高さ)が異常です。[{0}: {1}行]", this.strファイル名の絶対パス, this.n現在の行数, i + 1);
1843 bgapan.sz終了サイズ.Height = n値;
1847 #region [ 6. 画像側開始位置・X ]
1850 if (!int.TryParse(strParams[i], out n値))
1852 Trace.TraceError("BGAPAN: {2}番目の引数(画像側開始位置・X)が異常です。[{0}: {1}行]", this.strファイル名の絶対パス, this.n現在の行数, i + 1);
1855 bgapan.pt画像側開始位置.X = n値;
1859 #region [ 7. 画像側開始位置・Y ]
1862 if (!int.TryParse(strParams[i], out n値))
1864 Trace.TraceError("BGAPAN: {2}番目の引数(画像側開始位置・Y)が異常です。[{0}: {1}行]", this.strファイル名の絶対パス, this.n現在の行数, i + 1);
1867 bgapan.pt画像側開始位置.Y = n値;
1871 #region [ 8. 画像側終了位置・X ]
1874 if (!int.TryParse(strParams[i], out n値))
1876 Trace.TraceError("BGAPAN: {2}番目の引数(画像側終了位置・X)が異常です。[{0}: {1}行]", this.strファイル名の絶対パス, this.n現在の行数, i + 1);
1879 bgapan.pt画像側終了位置.X = n値;
1883 #region [ 9. 画像側終了位置・Y ]
1886 if (!int.TryParse(strParams[i], out n値))
1888 Trace.TraceError("BGAPAN: {2}番目の引数(画像側終了位置・Y)が異常です。[{0}: {1}行]", this.strファイル名の絶対パス, this.n現在の行数, i + 1);
1891 bgapan.pt画像側終了位置.Y = n値;
1895 #region [ 10.表示側開始位置・X ]
1898 if (!int.TryParse(strParams[i], out n値))
1900 Trace.TraceError("BGAPAN: {2}番目の引数(表示側開始位置・X)が異常です。[{0}: {1}行]", this.strファイル名の絶対パス, this.n現在の行数, i + 1);
1903 bgapan.pt表示側開始位置.X = n値;
1907 #region [ 11.表示側開始位置・Y ]
1910 if (!int.TryParse(strParams[i], out n値))
1912 Trace.TraceError("BGAPAN: {2}番目の引数(表示側開始位置・Y)が異常です。[{0}: {1}行]", this.strファイル名の絶対パス, this.n現在の行数, i + 1);
1915 bgapan.pt表示側開始位置.Y = n値;
1919 #region [ 12.表示側終了位置・X ]
1922 if (!int.TryParse(strParams[i], out n値))
1924 Trace.TraceError("BGAPAN: {2}番目の引数(表示側終了位置・X)が異常です。[{0}: {1}行]", this.strファイル名の絶対パス, this.n現在の行数, i + 1);
1927 bgapan.pt表示側終了位置.X = n値;
1931 #region [ 13.表示側終了位置・Y ]
1934 if (!int.TryParse(strParams[i], out n値))
1936 Trace.TraceError("BGAPAN: {2}番目の引数(表示側終了位置・Y)が異常です。[{0}: {1}行]", this.strファイル名の絶対パス, this.n現在の行数, i + 1);
1939 bgapan.pt表示側終了位置.Y = n値;
1946 if (!int.TryParse(strParams[i], out n値))
1948 Trace.TraceError("BGAPAN: {2}番目の引数(移動時間)が異常です。[{0}: {1}行]", this.strファイル名の絶対パス, this.n現在の行数, i + 1);
1955 bgapan.n移動時間ct = n値;
1960 #region [ BGAPANリストに {zz, bgapan} の組を登録する。]
1962 if (this.listBGAPAN.ContainsKey(zz)) // 既にリスト中に存在しているなら削除。後のものが有効。
1963 this.listBGAPAN.Remove(zz);
1965 this.listBGAPAN.Add(zz, bgapan);
1971 private bool t入力_行解析_BMP(string strコマンド, string strパラメータ, string strコメント)
1975 #region [ "BMP" で始まらないコマンドは無効。]
1977 if (!strコマンド.StartsWith("BMP", StringComparison.OrdinalIgnoreCase))
1980 strコマンド = strコマンド.Substring(3); // strコマンド から先頭の"BMP"文字を除去。
1988 #region [ BMP番号 zz を取得する。]
1990 if (strコマンド.Length < 2)
1992 #region [ (A) "#BMP:" の場合 → zz = 00 ]
2000 #region [ (B) "#BMPzz:" の場合 → zz = 00 ~ ZZ ]
2002 zz = C変換.n36進数2桁の文字列を数値に変換して返す(strコマンド.Substring(0, 2));
2003 if (zz < 0 || zz >= 36 * 36)
2005 Trace.TraceError("BMP番号に 00~ZZ 以外の値または不正な文字列が指定されました。[{0}: {1}行]", this.strファイル名の絶対パス, this.n現在の行数);
2015 var bmp = new CBMP()
2018 strファイル名 = strパラメータ,
2022 #region [ BMPリストに {zz, bmp} の組を登録。]
2024 if (this.listBMP.ContainsKey(zz)) // 既にリスト中に存在しているなら削除。後のものが有効。
2025 this.listBMP.Remove(zz);
2027 this.listBMP.Add(zz, bmp);
2033 private bool t入力_行解析_BMPTEX(string strコマンド, string strパラメータ, string strコメント)
2037 #region [ "BMPTEX" で始まらないコマンドは無効。]
2039 if (!strコマンド.StartsWith("BMPTEX", StringComparison.OrdinalIgnoreCase))
2042 strコマンド = strコマンド.Substring(6); // strコマンド から先頭の"BMPTEX"文字を除去。
2048 if (strコマンド.Length < 2)
2049 return false; // BMPTEX番号 zz がないなら無効。
2051 #region [ BMPTEX番号 zz を取得する。]
2053 int zz = C変換.n36進数2桁の文字列を数値に変換して返す(strコマンド.Substring(0, 2));
2054 if (zz < 0 || zz >= 36 * 36)
2056 Trace.TraceError("BMPTEX番号に 00~ZZ 以外の値または不正な文字列が指定されました。[{0}: {1}]", this.strファイル名の絶対パス, this.n現在の行数);
2062 var bmptex = new CBMPTEX()
2065 strファイル名 = strパラメータ,
2069 #region [ BMPTEXリストに {zz, bmptex} の組を登録する。]
2071 if (this.listBMPTEX.ContainsKey(zz)) // 既にリスト中に存在しているなら削除。後のものが有効。
2072 this.listBMPTEX.Remove(zz);
2074 this.listBMPTEX.Add(zz, bmptex);
2080 private bool t入力_行解析_BPM_BPMzz(string strコマンド, string strパラメータ, string strコメント)
2084 #region [ "BPM" で始まらないコマンドは無効。]
2086 if (!strコマンド.StartsWith("BPM", StringComparison.OrdinalIgnoreCase))
2089 strコマンド = strコマンド.Substring(3); // strコマンド から先頭の"BPM"文字を除去。
2097 #region [ BPM番号 zz を取得する。]
2099 if (strコマンド.Length < 2)
2101 #region [ (A) "#BPM:" の場合 → zz = 00 ]
2109 #region [ (B) "#BPMzz:" の場合 → zz = 00 ~ ZZ ]
2111 zz = C変換.n36進数2桁の文字列を数値に変換して返す(strコマンド.Substring(0, 2));
2112 if (zz < 0 || zz >= 36 * 36)
2114 Trace.TraceError("BPM番号に 00~ZZ 以外の値または不正な文字列が指定されました。[{0}: {1}行]", this.strファイル名の絶対パス, this.n現在の行数);
2125 #region [ BPM値を取得する。]
2127 //if( !double.TryParse( strパラメータ, out result ) )
2128 if (!TryParse(strパラメータ, out dbBPM)) // #23880 2010.12.30 yyagi: alternative TryParse to permit both '.' and ',' for decimal point
2136 if (zz == 0) // "#BPM00:" と "#BPM:" は等価。
2137 this.BPM = dbBPM; // この曲の代表 BPM に格納する。
2139 #region [ BPMリストに {内部番号, zz, dbBPM} の組を登録。]
2145 n内部番号 = this.n内部番号BPM1to,
2152 #region [ BPM番号が zz であるBPM未設定のBPMチップがあれば、そのサイズを変更する。無限管理に対応。]
2154 if (this.n無限管理BPM[zz] == -zz) // 初期状態では n無限管理BPM[zz] = -zz である。この場合、#BPMzz がまだ出現していないことを意味する。
2156 foreach (CChip chip in listChip) // これまでに出てきたチップのうち、該当する(BPM値が未設定の)BPMチップの値を変更する(仕組み上、必ず後方参照となる)。
2158 chip.AdjustInfiniteManageIntInternalIndex(chip.bBPMチップである, zz, this.n内部番号BPM1to);
2161 this.n無限管理BPM[zz] = this.n内部番号BPM1to; // 次にこの BPM番号 zz を使うBPMチップが現れたら、このBPM値が格納されることになる。
2162 this.n内部番号BPM1to++; // 内部番号は単純増加連番。
2168 private bool t入力_行解析_RESULTIMAGE(string strコマンド, string strパラメータ, string strコメント)
2172 #region [ "RESULTIMAGE" で始まらないコマンドは無効。]
2174 if (!strコマンド.StartsWith("RESULTIMAGE", StringComparison.OrdinalIgnoreCase))
2177 strコマンド = strコマンド.Substring(11); // strコマンド から先頭の"RESULTIMAGE"文字を除去。
2182 // コマンドには "#RESULTIMAGE:" と "#RESULTIMAGE_SS~E" の2種類があり、パラメータの処理はそれぞれ異なる。
2184 if (strコマンド.Length < 2)
2186 #region [ (A) ランク指定がない場合("#RESULTIMAGE:") → 優先順位が設定されていないすべてのランクで同じパラメータを使用する。]
2188 for (int i = 0; i < 7; i++)
2190 if (this.nRESULTIMAGE用優先順位[i] == 0)
2191 this.RESULTIMAGE[i] = strパラメータ.Trim();
2198 #region [ (B) ランク指定がある場合("#RESULTIMAGE_SS~E:") → 優先順位に従ってパラメータを記録する。]
2200 switch (strコマンド.ToUpper())
2203 this.t入力_行解析_RESULTIMAGE_ファイルを設定する(0, strパラメータ);
2207 this.t入力_行解析_RESULTIMAGE_ファイルを設定する(1, strパラメータ);
2211 this.t入力_行解析_RESULTIMAGE_ファイルを設定する(2, strパラメータ);
2215 this.t入力_行解析_RESULTIMAGE_ファイルを設定する(3, strパラメータ);
2219 this.t入力_行解析_RESULTIMAGE_ファイルを設定する(4, strパラメータ);
2223 this.t入力_行解析_RESULTIMAGE_ファイルを設定する(5, strパラメータ);
2227 this.t入力_行解析_RESULTIMAGE_ファイルを設定する(6, strパラメータ);
2236 private void t入力_行解析_RESULTIMAGE_ファイルを設定する(int nランク0to6, string strファイル名)
2238 if (nランク0to6 < 0 || nランク0to6 > 6) // 値域チェック。
2241 // 指定されたランクから上位のすべてのランクについて、ファイル名を更新する。
2243 for (int i = nランク0to6; i >= 0; i--)
2245 int n優先順位 = 7 - nランク0to6;
2247 // 現状より優先順位の低い RESULTIMAGE[] に限り、ファイル名を更新できる。
2248 //(例:#RESULTMOVIE_D が #RESULTIMAGE_A より後に出現しても、#RESULTIMAGE_A で指定されたファイル名を上書きすることはできない。しかしその逆は可能。)
2250 if (this.nRESULTIMAGE用優先順位[i] < n優先順位)
2252 this.nRESULTIMAGE用優先順位[i] = n優先順位;
2253 this.RESULTIMAGE[i] = strファイル名;
2257 private bool t入力_行解析_RESULTMOVIE(string strコマンド, string strパラメータ, string strコメント)
2261 #region [ "RESULTMOVIE" で始まらないコマンドは無効。]
2263 if (!strコマンド.StartsWith("RESULTMOVIE", StringComparison.OrdinalIgnoreCase))
2266 strコマンド = strコマンド.Substring(11); // strコマンド から先頭の"RESULTMOVIE"文字を除去。
2271 // コマンドには "#RESULTMOVIE:" と "#RESULTMOVIE_SS~E" の2種類があり、パラメータの処理はそれぞれ異なる。
2273 if (strコマンド.Length < 2)
2275 #region [ (A) ランク指定がない場合("#RESULTMOVIE:") → 優先順位が設定されていないすべてのランクで同じパラメータを使用する。]
2277 for (int i = 0; i < 7; i++)
2279 if (this.nRESULTMOVIE用優先順位[i] == 0)
2280 this.RESULTMOVIE[i] = strパラメータ.Trim();
2287 #region [ (B) ランク指定がある場合("#RESULTMOVIE_SS~E:") → 優先順位に従ってパラメータを記録する。]
2289 switch (strコマンド.ToUpper())
2292 this.t入力_行解析_RESULTMOVIE_ファイルを設定する(0, strパラメータ);
2296 this.t入力_行解析_RESULTMOVIE_ファイルを設定する(1, strパラメータ);
2300 this.t入力_行解析_RESULTMOVIE_ファイルを設定する(2, strパラメータ);
2304 this.t入力_行解析_RESULTMOVIE_ファイルを設定する(3, strパラメータ);
2308 this.t入力_行解析_RESULTMOVIE_ファイルを設定する(4, strパラメータ);
2312 this.t入力_行解析_RESULTMOVIE_ファイルを設定する(5, strパラメータ);
2316 this.t入力_行解析_RESULTMOVIE_ファイルを設定する(6, strパラメータ);
2325 private void t入力_行解析_RESULTMOVIE_ファイルを設定する(int nランク0to6, string strファイル名)
2327 if (nランク0to6 < 0 || nランク0to6 > 6) // 値域チェック。
2330 // 指定されたランクから上位のすべてのランクについて、ファイル名を更新する。
2332 for (int i = nランク0to6; i >= 0; i--)
2334 int n優先順位 = 7 - nランク0to6;
2336 // 現状より優先順位の低い RESULTMOVIE[] に限り、ファイル名を更新できる。
2337 //(例:#RESULTMOVIE_D が #RESULTMOVIE_A より後に出現しても、#RESULTMOVIE_A で指定されたファイル名を上書きすることはできない。しかしその逆は可能。)
2339 if (this.nRESULTMOVIE用優先順位[i] < n優先順位)
2341 this.nRESULTMOVIE用優先順位[i] = n優先順位;
2342 this.RESULTMOVIE[i] = strファイル名;
2346 private bool t入力_行解析_RESULTSOUND(string strコマンド, string strパラメータ, string strコメント)
2350 #region [ "RESULTSOUND" で始まらないコマンドは無効。]
2352 if (!strコマンド.StartsWith("RESULTSOUND", StringComparison.OrdinalIgnoreCase))
2355 strコマンド = strコマンド.Substring(11); // strコマンド から先頭の"RESULTSOUND"文字を除去。
2360 // コマンドには "#RESULTSOUND:" と "#RESULTSOUND_SS~E" の2種類があり、パラメータの処理はそれぞれ異なる。
2362 if (strコマンド.Length < 2)
2364 #region [ (A) ランク指定がない場合("#RESULTSOUND:") → 優先順位が設定されていないすべてのランクで同じパラメータを使用する。]
2366 for (int i = 0; i < 7; i++)
2368 if (this.nRESULTSOUND用優先順位[i] == 0)
2369 this.RESULTSOUND[i] = strパラメータ.Trim();
2376 #region [ (B) ランク指定がある場合("#RESULTSOUND_SS~E:") → 優先順位に従ってパラメータを記録する。]
2378 switch (strコマンド.ToUpper())
2381 this.t入力_行解析_RESULTSOUND_ファイルを設定する(0, strパラメータ);
2385 this.t入力_行解析_RESULTSOUND_ファイルを設定する(1, strパラメータ);
2389 this.t入力_行解析_RESULTSOUND_ファイルを設定する(2, strパラメータ);
2393 this.t入力_行解析_RESULTSOUND_ファイルを設定する(3, strパラメータ);
2397 this.t入力_行解析_RESULTSOUND_ファイルを設定する(4, strパラメータ);
2401 this.t入力_行解析_RESULTSOUND_ファイルを設定する(5, strパラメータ);
2405 this.t入力_行解析_RESULTSOUND_ファイルを設定する(6, strパラメータ);
2414 private void t入力_行解析_RESULTSOUND_ファイルを設定する(int nランク0to6, string strファイル名)
2416 if (nランク0to6 < 0 || nランク0to6 > 6) // 値域チェック。
2419 // 指定されたランクから上位のすべてのランクについて、ファイル名を更新する。
2421 for (int i = nランク0to6; i >= 0; i--)
2423 int n優先順位 = 7 - nランク0to6;
2425 // 現状より優先順位の低い RESULTSOUND[] に限り、ファイル名を更新できる。
2426 //(例:#RESULTSOUND_D が #RESULTSOUND_A より後に出現しても、#RESULTSOUND_A で指定されたファイル名を上書きすることはできない。しかしその逆は可能。)
2428 if (this.nRESULTSOUND用優先順位[i] < n優先順位)
2430 this.nRESULTSOUND用優先順位[i] = n優先順位;
2431 this.RESULTSOUND[i] = strファイル名;
2435 private bool t入力_行解析_SIZE(string strコマンド, string strパラメータ, string strコメント)
2439 #region [ "SIZE" で始まらないコマンドや、その後ろに2文字(番号)が付随してないコマンドは無効。]
2441 if (!strコマンド.StartsWith("SIZE", StringComparison.OrdinalIgnoreCase))
2444 strコマンド = strコマンド.Substring(4); // strコマンド から先頭の"SIZE"文字を除去。
2446 if (strコマンド.Length < 2) // サイズ番号の指定がない場合は無効。
2451 #region [ nWAV番号(36進数2桁)を取得。]
2453 int nWAV番号 = C変換.n36進数2桁の文字列を数値に変換して返す(strコマンド.Substring(0, 2));
2455 if (nWAV番号 < 0 || nWAV番号 >= 36 * 36)
2457 Trace.TraceError("SIZEのWAV番号に 00~ZZ 以外の値または不正な文字列が指定されました。[{0}: {1}行]", this.strファイル名の絶対パス, this.n現在の行数);
2466 #region [ nサイズ値 を取得する。値は 0~100 に収める。]
2470 if (!int.TryParse(strパラメータ, out nサイズ値))
2471 return true; // int変換に失敗しても、この行自体の処理は終えたのでtrueを返す。
2473 nサイズ値 = Math.Min(Math.Max(nサイズ値, 0), 100); // 0未満は0、100超えは100に強制変換。
2477 #region [ nWAV番号で示されるサイズ未設定のWAVチップがあれば、そのサイズを変更する。無限管理に対応。]
2479 if (this.n無限管理SIZE[nWAV番号] == -nWAV番号) // 初期状態では n無限管理SIZE[xx] = -xx である。この場合、#SIZExx がまだ出現していないことを意味する。
2481 foreach (CWAV wav in this.listWAV.Values) // これまでに出てきたWAVチップのうち、該当する(サイズが未設定の)チップのサイズを変更する(仕組み上、必ず後方参照となる)。
2483 if (wav.nチップサイズ == -nWAV番号) // #SIZExx 行より前の行に出現した #WAVxx では、チップサイズは -xx に初期化されている。
2484 wav.nチップサイズ = nサイズ値;
2487 this.n無限管理SIZE[nWAV番号] = nサイズ値; // 次にこの nWAV番号を使うWAVチップが現れたら、負数の代わりに、このサイズ値が格納されることになる。
2493 private bool t入力_行解析_WAV(string strコマンド, string strパラメータ, string strコメント)
2497 #region [ "WAV" で始まらないコマンドは無効。]
2499 if (!strコマンド.StartsWith("WAV", StringComparison.OrdinalIgnoreCase))
2502 strコマンド = strコマンド.Substring(3); // strコマンド から先頭の"WAV"文字を除去。
2508 if (strコマンド.Length < 2)
2509 return false; // WAV番号 zz がないなら無効。
2511 #region [ WAV番号 zz を取得する。]
2513 int zz = C変換.n36進数2桁の文字列を数値に変換して返す(strコマンド.Substring(0, 2));
2514 if (zz < 0 || zz >= 36 * 36)
2516 Trace.TraceError("WAV番号に 00~ZZ 以外の値または不正な文字列が指定されました。[{0}: {1}行]", this.strファイル名の絶対パス, this.n現在の行数);
2522 var wav = new CWAV()
2524 n内部番号 = this.n内部番号WAV1to,
2526 nチップサイズ = this.n無限管理SIZE[zz],
2527 n位置 = this.n無限管理PAN[zz],
2528 n音量 = this.n無限管理VOL[zz],
2529 strファイル名 = strパラメータ,
2533 #region [ WAVリストに {内部番号, wav} の組を登録。]
2535 this.listWAV.Add(this.n内部番号WAV1to, wav);
2539 #region [ WAV番号が zz である内部番号未設定のWAVチップがあれば、その内部番号を変更する。無限管理対応。]
2541 if (this.n無限管理WAV[zz] == -zz) // 初期状態では n無限管理WAV[zz] = -zz である。この場合、#WAVzz がまだ出現していないことを意味する。
2543 foreach (CChip chip in listChip) // これまでに出てきたチップのうち、該当する(内部番号が未設定の)WAVチップの値を変更する(仕組み上、必ず後方参照となる)。
2545 chip.AdjustInfiniteManageIntInternalIndex(chip.bWAVを使うチャンネルである, zz, n内部番号WAV1to);
2548 this.n無限管理WAV[zz] = this.n内部番号WAV1to; // 次にこの WAV番号 zz を使うWAVチップが現れたら、この内部番号が格納されることになる。
2549 this.n内部番号WAV1to++; // 内部番号は単純増加連番。
2555 private bool t入力_行解析_WAVPAN_PAN(string strコマンド, string strパラメータ, string strコメント)
2559 #region [ "WAVPAN" or "PAN" で始まらないコマンドは無効。]
2561 if (strコマンド.StartsWith("WAVPAN", StringComparison.OrdinalIgnoreCase))
2562 strコマンド = strコマンド.Substring(6); // strコマンド から先頭の"WAVPAN"文字を除去。
2564 else if (strコマンド.StartsWith("PAN", StringComparison.OrdinalIgnoreCase))
2565 strコマンド = strコマンド.Substring(3); // strコマンド から先頭の"PAN"文字を除去。
2574 if (strコマンド.Length < 2)
2575 return false; // WAV番号 zz がないなら無効。
2577 #region [ WAV番号 zz を取得する。]
2579 int zz = C変換.n36進数2桁の文字列を数値に変換して返す(strコマンド.Substring(0, 2));
2580 if (zz < 0 || zz >= 36 * 36)
2582 Trace.TraceError("WAVPAN(PAN)のWAV番号に 00~ZZ 以外の値または不正な文字列が指定されました。[{0}: {1}行]", this.strファイル名の絶対パス, this.n現在の行数);
2588 #region [ WAV番号 zz を持つWAVチップの位置を変更する。無限定義対応。]
2591 if (int.TryParse(strパラメータ, out n位置))
2593 n位置 = Math.Min(Math.Max(n位置, -100), 100); // -100~+100 に丸める
2595 if (this.n無限管理PAN[zz] == (-10000 - zz)) // 初期状態では n無限管理PAN[zz] = -10000 - zz である。この場合、#WAVPANzz, #PANzz がまだ出現していないことを意味する。
2597 foreach (CWAV wav in this.listWAV.Values) // これまでに出てきたチップのうち、該当する(位置が未設定の)WAVチップの値を変更する(仕組み上、必ず後方参照となる)。
2599 if (wav.n位置 == (-10000 - zz)) // #WAVPANzz, #PANzz 行より前の行に出現した #WAVzz では、位置は -10000-zz に初期化されている。
2603 this.n無限管理PAN[zz] = n位置; // 次にこの WAV番号 zz を使うWAVチップが現れたら、この位置が格納されることになる。
2610 private bool t入力_行解析_WAVVOL_VOLUME(string strコマンド, string strパラメータ, string strコメント)
2614 #region [ "WAVCOL" or "VOLUME" で始まらないコマンドは無効。]
2616 if (strコマンド.StartsWith("WAVVOL", StringComparison.OrdinalIgnoreCase))
2617 strコマンド = strコマンド.Substring(6); // strコマンド から先頭の"WAVVOL"文字を除去。
2619 else if (strコマンド.StartsWith("VOLUME", StringComparison.OrdinalIgnoreCase))
2620 strコマンド = strコマンド.Substring(6); // strコマンド から先頭の"VOLUME"文字を除去。
2629 if (strコマンド.Length < 2)
2630 return false; // WAV番号 zz がないなら無効。
2632 #region [ WAV番号 zz を取得する。]
2634 int zz = C変換.n36進数2桁の文字列を数値に変換して返す(strコマンド.Substring(0, 2));
2635 if (zz < 0 || zz >= 36 * 36)
2637 Trace.TraceError("WAV番号に 00~ZZ 以外の値または不正な文字列が指定されました。[{0}: {1}行]", this.strファイル名の絶対パス, this.n現在の行数);
2643 #region [ WAV番号 zz を持つWAVチップの音量を変更する。無限定義対応。]
2646 if (int.TryParse(strパラメータ, out n音量))
2648 n音量 = Math.Min(Math.Max(n音量, 0), 100); // 0~100に丸める。
2650 if (this.n無限管理VOL[zz] == -zz) // 初期状態では n無限管理VOL[zz] = - zz である。この場合、#WAVVOLzz, #VOLUMEzz がまだ出現していないことを意味する。
2652 foreach (CWAV wav in this.listWAV.Values) // これまでに出てきたチップのうち、該当する(音量が未設定の)WAVチップの値を変更する(仕組み上、必ず後方参照となる)。
2654 if (wav.n音量 == -zz) // #WAVVOLzz, #VOLUMEzz 行より前の行に出現した #WAVzz では、音量は -zz に初期化されている。
2658 this.n無限管理VOL[zz] = n音量; // 次にこの WAV番号 zz を使うWAVチップが現れたら、この音量が格納されることになる。
2665 private bool t入力_行解析_チップ配置(string strコマンド, string strパラメータ, string strコメント)
2669 if (strコマンド.Length != 5) // コマンドは必ず5文字であること。
2672 #region [ n小節番号 を取得する。]
2674 int n小節番号 = C変換.n小節番号の文字列3桁を数値に変換して返す(strコマンド.Substring(0, 3));
2678 n小節番号++; // 先頭に空の1小節を設ける。
2682 #region [ nチャンネル番号 を取得する。]
2684 EChannel tmpチャンネル番号 = EChannel.Invalid;
2686 // ファイルフォーマットによって処理が異なる。
2688 if (this.e種別 == EDTX種別.GDA || this.e種別 == EDTX種別.G2D)
2690 #region [ (A) GDA, G2D の場合:チャンネル文字列をDTXのチャンネル番号へ置き換える。]
2692 string strチャンネル文字列 = strコマンド.Substring(3, 2);
2694 foreach (STGDAPARAM param in this.stGDAParam)
2696 if (strチャンネル文字列.Equals(param.strGDAのチャンネル文字列, StringComparison.OrdinalIgnoreCase))
2698 tmpチャンネル番号 = param.eDTXのチャンネル番号;
2702 if (tmpチャンネル番号 == EChannel.Invalid)
2703 return false; // 置き換え失敗
2709 #region [ (B) その他の場合:チャンネル番号は16進数2桁。]
2711 tmpチャンネル番号 = (EChannel)C変換.n16進数2桁の文字列を数値に変換して返す(strコマンド.Substring(3, 2));
2723 #region [ 小節長変更(Ch.02)は他のチャンネルとはパラメータが特殊なので、先にとっとと終わらせる。 ]
2725 if (tmpチャンネル番号 == EChannel.BarLength)
2728 double db小節長倍率 = 1.0;
2729 //if( !double.TryParse( strパラメータ, out result ) )
2730 if (!this.TryParse(strパラメータ, out db小節長倍率)) // #23880 2010.12.30 yyagi: alternative TryParse to permit both '.' and ',' for decimal point
2732 Trace.TraceError("小節長倍率に不正な値を指定しました。[{0}: {1}行]", this.strファイル名の絶対パス, this.n現在の行数);
2736 // 小節長倍率チップを一番先頭に配置する。
2737 this.listChip.Insert(0, new CChip(n小節番号 * 384, db小節長倍率, tmpチャンネル番号));
2739 return true; // 配置終了。
2745 if (string.IsNullOrEmpty(strパラメータ)) // パラメータはnullまたは空文字列ではないこと。
2748 #region [ strパラメータ にオブジェクト記述を格納し、その n文字数 をカウントする。]
2752 var sb = new StringBuilder(strパラメータ.Length);
2754 // strパラメータを先頭から1文字ずつ見ながら正規化(無効文字('_')を飛ばしたり不正な文字でエラーを出したり)し、sb へ格納する。
2756 CharEnumerator ce = strパラメータ.GetEnumerator();
2757 while (ce.MoveNext())
2759 if (ce.Current == '_') // '_' は無視。
2762 if (C変換.str36進数文字.IndexOf(ce.Current) < 0) // オブジェクト記述は36進数文字であること。
2764 Trace.TraceError("不正なオブジェクト指定があります。[{0}: {1}行]", this.strファイル名の絶対パス, this.n現在の行数);
2768 sb.Append(ce.Current);
2772 strパラメータ = sb.ToString(); // 正規化された文字列になりました。
2774 if ((n文字数 % 2) != 0) // パラメータの文字数が奇数の場合、最後の1文字を無視する。
2780 // (4) パラメータをオブジェクト数値に分解して配置する。
2782 for (int i = 0; i < (n文字数 / 2); i++) // 2文字で1オブジェクト数値
2784 #region [ nオブジェクト数値 を1つ取得する。'00' なら無視。]
2788 if (tmpチャンネル番号 == EChannel.BPM)
2791 nオブジェクト数値 = C変換.n16進数2桁の文字列を数値に変換して返す(strパラメータ.Substring(i * 2, 2));
2795 // その他のチャンネルは36進数2桁。
2796 nオブジェクト数値 = C変換.n36進数2桁の文字列を数値に変換して返す(strパラメータ.Substring(i * 2, 2));
2799 if (nオブジェクト数値 == 0x00)
2804 // オブジェクト数値に対応するチップを生成。
2805 var chip = new CChip((n小節番号 * 384) + ((384 * i) / (n文字数 / 2)), nオブジェクト数値, nオブジェクト数値, tmpチャンネル番号);
2808 chip.DecideInstrumentPart();
2811 this.bチップがある.Drums |= chip.bDrums可視チップ;
2812 this.bチップがある.HHOpen |= chip[EChannel.HiHatOpen];
2813 this.bチップがある.Ride |= chip[EChannel.RideCymbal];
2814 this.bチップがある.LeftCymbal |= chip[EChannel.LeftCymbal];
2815 this.bチップがある.LeftPedal |= chip[EChannel.LeftPedal];
2816 this.bチップがある.LeftBassDrum |= chip[EChannel.LeftBassDrum];
2817 this.bチップがある.Guitar |= chip.bGuitar可視チップ;
2818 this.bチップがある.OpenGuitar |= chip[EChannel.Guitar_Open];
2819 this.bチップがある.Bass |= chip.bBass可視チップ;
2820 this.bチップがある.OpenBass |= chip[EChannel.Bass_Open];
2821 this.bチップがある.BGA |= chip.bBGALayer;
2822 this.bチップがある.Movie |= chip.bMovie;
2825 if (chip[EChannel.MovieFull] || CDTXMania.Instance.ConfigIni.bForceScalingAVI)
2827 this.bMovieをFullscreen再生する = true;
2832 chip.ConvertNoChip();
2834 // 無限管理オブジェクトインデックスの割当。(もしそのチップが対象であれば)
2835 chip.AssignInfiniteManageWAV(this.n無限管理WAV[nオブジェクト数値]);
2836 chip.AssignInfiniteManageBPM(this.n無限管理BPM[nオブジェクト数値]);
2837 chip.AdjustPlayPositionForFillin(nオブジェクト数値);
2840 this.listChip.Add(chip);