Exemple #1
0
                // 初期化。
                public static void 状態をリセットする()
                {
                    スコア    = null;
                    データ種別  = データ種別.DTX;
                    Random = new Random((int)(Stopwatch.GetTimestamp() % int.MaxValue));

                    行番号 = 0;

                    コマンド     = "";
                    コマンドzzなし = "";
                    zz16進数   = -1;
                    zz36進数   = -1;
                    パラメータ    = "";
                    コメント     = "";

                    小節番号    = 0;
                    チャンネル番号 = 0;

                    チップ種別    = チップ種別.Unknown;
                    小節解像度    = 384; // DTX の小節解像度は 384 固定
                    オブジェクト総数 = 0;
                    オブジェクト番号 = 0;

                    PAN定義マップ    = new Dictionary <int, int>();
                    VOLUME定義マップ = new Dictionary <int, int>();
                    BGMWAVリスト   = new List <int>();

                    BASEBPM  = 0.0;
                    BPM定義マップ = new Dictionary <int, double>();
                    BPM参照マップ = new Dictionary <チップ, int>();

                    小節長倍率マップ = new SortedDictionary <int, double>();
                }
Exemple #2
0
            /// <summary>
            ///		ファイルから指定された種別のデータを読み込み、スコアを生成して返す。
            ///		読み込みに失敗した場合は、何らかの例外を発出する。
            /// </summary>
            public static スコア ファイルから生成する(string ファイルの絶対パス, データ種別 データ種別 = データ種別.拡張子から判定, bool ヘッダだけ = false)
            {
                if (データ種別 == データ種別.拡張子から判定)
                {
                    #region " ファイルパスの拡張子からデータ種別を自動判別する。"
                    //----------------
                    var 拡張子toデータ種別マップ = new Dictionary <string, データ種別>()
                    {
                        { ".dtx", データ種別.DTX },
                        { ".gda", データ種別.GDA },
                        { ".g2d", データ種別.G2D },
                        { ".bms", データ種別.BMS },
                        { ".bme", データ種別.BME },
                    };

                    string ファイルの拡張子 = Path.GetExtension(ファイルの絶対パス).ToLower();

                    // マップから、拡張子に対応するデータ種別を取得する。
                    if (!(拡張子toデータ種別マップ.TryGetValue(ファイルの拡張子, out データ種別 確定したデータ種別)))
                    {
                        // マップにない拡張子はすべて DTX とみなす。
                        確定したデータ種別 = データ種別.DTX;
                    }

                    データ種別 = 確定したデータ種別;
                    //----------------
                    #endregion
                }

                string 全入力文字列 = null;

                // ファイルの内容を一気読み。
                using (var sr = new StreamReader(ファイルの絶対パス, Encoding.GetEncoding(932 /*Shift-JIS*/)))       // DTX互換ファイルは Shift-JIS
                    全入力文字列 = sr.ReadToEnd();

                // 読み込んだ内容でスコアを生成する。
                var score = 文字列から生成する(全入力文字列, データ種別, ヘッダだけ);

                // ファイルから読み込んだ場合のみ、このメンバが有効。
                score.譜面ファイルの絶対パス = ファイルの絶対パス;

                return(score);
            }
Exemple #3
0
            /// <summary>
            ///     指定されたデータ種別のテキストデータを含んだ1つの文字列から、スコアを生成して返す。
            ///		読み込みに失敗した場合は、何らかの例外を発出する。
            /// </summary>
            public static スコア 文字列から生成する(string 全入力文字列, データ種別 データ種別 = データ種別.DTX, bool ヘッダだけ = false)
            {
                if (データ種別 == データ種別.拡張子から判定)
                {
                    throw new Exception("文字列から生成する場合には、拡張子からの自動判定は行えません。");
                }

                現在の.状態をリセットする();
                現在の.スコア             = new スコア();
                現在の.スコア.譜面ファイルの絶対パス = null;    // ファイルから読み込んだ場合のみ、このメンバが有効。
                現在の.データ種別           = データ種別;

                全入力文字列 = 全入力文字列.Replace('\t', ' ');     // TAB は空白に置換しておく。


                // 読み込み

                using (var sr = new StringReader(全入力文字列))
                {
                    #region " すべての行について解析する。"
                    //----------------
                    string 行;

                    for (現在の.行番号 = 1; (行 = sr.ReadLine()) != null; 現在の.行番号++)
                    {
                        // 行を分割する。

                        if (!_行をコマンドとパラメータとコメントに分解する(行, out 現在の.コマンド, out 現在の.コマンドzzなし, out 現在の.zz16進数, out 現在の.zz36進数, out 現在の.パラメータ, out 現在の.コメント))
                        {
                            //Trace.TraceWarning( $"書式が不正です。無視します。[{現在の.行番号}行]" );
                            continue;
                        }

                        if (string.IsNullOrEmpty(現在の.コマンド))
                        {
                            continue;
                        }


                        // コマンド別に解析する。

                        // zzを含めたコマンドがzzを含まないコマンドと一致する場合は、前者のほうが優先。
                        if (_コマンドtoアクションマップ.TryGetValue(現在の.コマンド.ToLower(), out var アクション) ||
                            _コマンドtoアクションマップ.TryGetValue(現在の.コマンドzzなし.ToLower(), out アクション))
                        {
                            if (!ヘッダだけ || アクション.ヘッダである)
                            {
                                アクション.解析アクション();
                            }
                        }
                        else
                        {
                            // マップにあるコマンドに該当がなければ、オブジェクト配置として解析する。
                            if (!ヘッダだけ)
                            {
                                _コマンド_オブジェクト記述();
                            }
                        }
                    }
                    //----------------
                    #endregion
                }


                // 後処理

                if (!ヘッダだけ)
                {
                    #region " チップリストの先頭に #BPM チップを追加する。"
                    //----------------
                    {
                        if (!(現在の.BPM定義マップ.TryGetValue(0, out double BPM値)))
                        {
                            BPM値 = スコア.初期BPM;   // '#BPM:' が定義されてないなら初期BPMを使う
                        }
                        現在の.スコア.チップリスト.Add(
                            new チップ()
                        {
                            BPM   = BPM値,
                            チップ種別 = チップ種別.BPM,
                            小節番号  = 0,
                            小節解像度 = 現在の.小節解像度,
                            小節内位置 = 0,
                            音量    = チップ.最大音量,
                            可視    = false,
                        });
                    }
                    //----------------
                    #endregion

                    #region " 拍線を追加する。"
                    //-----------------
                    {
                        // 小節線を先に追加すると小節が1つ増えてしまうので、拍線から先に追加する。

                        int 最大小節番号 = 現在の.スコア.最大小節番号を返す();      // 最大小節番号はチップ数に依存して変化するので、次の for 文には組み込まないこと。

                        for (int i = 0; i <= 最大小節番号; i++)
                        {
                            double 小節長倍率 = 現在の.スコア.小節長倍率を取得する(i);

                            for (int n = 1; n * 0.25 < 小節長倍率; n++)
                            {
                                現在の.スコア.チップリスト.Add(
                                    new チップ()
                                {
                                    小節番号  = i,
                                    チップ種別 = チップ種別.拍線,
                                    小節内位置 = (int)((n * 0.25) * 100),
                                    小節解像度 = (int)(小節長倍率 * 100),
                                });
                            }
                        }
                    }
                    //-----------------
                    #endregion

                    #region " 小節線を追加する。"
                    //-----------------
                    {
                        int 最大小節番号 = 現在の.スコア.最大小節番号を返す();

                        for (int i = 0; i <= 最大小節番号 + 1; i++)
                        {
                            現在の.スコア.チップリスト.Add(
                                new チップ()
                            {
                                小節番号  = i,
                                チップ種別 = チップ種別.小節線,
                                小節内位置 = 0,
                                小節解像度 = 1,
                            });
                        }
                    }
                    //-----------------
                    #endregion

                    #region " 小節長倍率マップをもとに、スコアの小節長倍率リストを構築する。"
                    //----------------
                    {
                        double 現在の倍率  = 1.0;
                        int    最大小節番号 = 現在の.スコア.最大小節番号を返す();

                        for (int i = 0; i <= 最大小節番号; i++)       // すべての小節に対して設定。(SST仕様)
                        {
                            if (現在の.小節長倍率マップ.ContainsKey(i))
                            {
                                現在の倍率 = 現在の.小節長倍率マップ[i];   // 指定された倍率は、それが指定された小節以降の小節にも適用する。(DTX仕様)
                            }
                            現在の.スコア.小節長倍率を設定する(i, 現在の倍率);
                        }
                    }
                    //----------------
                    #endregion

                    #region " BPMチップの値を引き当てる。"
                    //----------------
                    foreach (var kvp in 現在の.BPM参照マップ)
                    {
                        // BPMチャンネルから作成された BPMチップには、BASEBPM を加算する。
                        // #BASEBPM が複数宣言されていた場合は、最後の値が使用される。
                        if (現在の.BPM定義マップ.TryGetValue(kvp.Value, out double bpm))
                        {
                            // (A) 参照している #BGMzz が定義されている場合
                            kvp.Key.BPM = 現在の.BASEBPM + bpm;
                        }
                        else
                        {
                            Trace.TraceWarning($"定義されていない #BPM が参照されています。");

                            if (0.0 < 現在の.BASEBPM)
                            {
                                // (B) 参照している #BPMzz が未宣言、かつ、BASEBPM が有効である場合
                                kvp.Key.BPM = 現在の.BASEBPM;  // BASEBPM のみ適用
                            }
                            else
                            {
                                // (C) 参照している #BPMzz が未宣言、かつ、BASEBPM が無効である場合
                                kvp.Key.チップ種別 = チップ種別.Unknown;  // このチップは無効
                            }
                        }
                    }

                    // 引き当てが終わったら、マップが持つチップへの参照を解放する。
                    現在の.BPM参照マップ.Clear();
                    //----------------
                    #endregion

                    #region " WAVチップのPAN値, VOLUME値を引き当てる。"
                    //----------------
                    foreach (var chip in 現在の.スコア.チップリスト)
                    {
                        // このクラスで実装しているチャンネルで、
                        var query = _DTXチャンネルプロパティマップ.Where((kvp) => (kvp.Value.チップ種別 == chip.チップ種別));

                        if (1 == query.Count())
                        {
                            var kvp = query.Single();   // タプル型なので SingleOrDefault() は使えない。

                            // WAV を使うチャンネルで、
                            if (kvp.Value.WAVを使う)
                            {
                                // PAN の指定があるなら、
                                if (現在の.PAN定義マップ.ContainsKey(chip.チップサブID))
                                {
                                    // それをチップに設定する。
                                    chip.左右位置 = 現在の.PAN定義マップ[chip.チップサブID];
                                }

                                // VOLUME の指定があるなら、
                                if (現在の.VOLUME定義マップ.ContainsKey(chip.チップサブID))
                                {
                                    // それをチップに設定する。
                                    var DTX音量 = Math.Min(Math.Max(現在の.VOLUME定義マップ[chip.チップサブID], 0), 100);          // 無音:0 ~ 100:原音

                                    chip.音量 =
                                        (100 == DTX音量) ? チップ.最大音量 :
                                        (int)(DTX音量 * チップ.最大音量 / 100.0) + 1;
                                }
                            }
                        }
                    }
                    //----------------
                    #endregion

                    #region " BGMWAV を WAVリストに反映する。"
                    //----------------
                    foreach (int WAV番号 in 現在の.BGMWAVリスト)
                    {
                        if (現在の.スコア.WAVリスト.ContainsKey(WAV番号))
                        {
                            現在の.スコア.WAVリスト[WAV番号].BGMである = true;    // BGMである
                        }
                    }
                    //----------------
                    #endregion

                    スコア._スコア読み込み時の後処理を行う(現在の.スコア);
                }

                return(現在の.スコア);
            }