Esempio n. 1
0
        protected IEnumerable <(int Tick, string Data)> SplitData(BarIndexCalculator c, int lineIndex, int barIndex, string data)
        {
            data = Regex.Replace(data, @"\s+", "");
            if (data.Length % 2 != 0)
            {
                DiagnosticCollector.ReportWarning($"データ定義の文字列長が2の倍数ではありません。終端部分は無視されます。(行: {lineIndex + 1})");
            }
            int headTick = c.GetTickFromBarIndex(barIndex);
            int barTick  = (int)(c.GetBarBeatsFromBarIndex(barIndex) * TicksPerBeat);
            var list     = Enumerable.Range(0, data.Length / 2).Select(p => data.Substring(p * 2, 2)).ToList();

            return(list.Select((p, i) => (headTick + (int)((double)barTick * i / list.Count), p)));
        }
Esempio n. 2
0
        public SusScoreData Parse(TextReader reader)
        {
            var shortNotesData = new List <LineData <Match> >();
            var longNotesData  = new List <LineData <Match> >();
            var bpmData        = new List <LineData <Match> >();

            bool matchAction(Match m, Action <Match> act)
            {
                if (m.Success)
                {
                    act(m);
                }
                return(m.Success);
            }

            int lineIndex = -1;

            while (reader.Peek() >= 0)
            {
                string line = reader.ReadLine();
                lineIndex++;

                if (matchAction(SusCommandPattern.Match(line), m => ProcessCommand(lineIndex, m.Groups["name"].Value, m.Groups["value"].Value)))
                {
                    continue;
                }

                if (matchAction(BpmDefinitionPattern.Match(line), m => StoreBpmDefinition(lineIndex, m.Groups["key"].Value, double.Parse(m.Groups["value"].Value))))
                {
                    continue;
                }

                if (matchAction(BpmCommandPattern.Match(line), m => bpmData.Add(new LineData <Match>(lineIndex, CurrentBarIndexOffset, m))))
                {
                    continue;
                }

                if (matchAction(SusNotePattern.Match(line), m => (m.Groups["longKey"].Success ? longNotesData : shortNotesData).Add(new LineData <Match>(lineIndex, CurrentBarIndexOffset, m))))
                {
                    continue;
                }

                if (matchAction(TimeSignatureCommandPattern.Match(line), m => StoreTimeSignatureDefinition(lineIndex, int.Parse(m.Groups["barIndex"].Value) + CurrentBarIndexOffset, double.Parse(m.Groups["value"].Value))))
                {
                    continue;
                }
            }

            if (!TimeSignatureDefinitions.ContainsKey(0))
            {
                TimeSignatureDefinitions.Add(0, 4.0);
                DiagnosticCollector.ReportInformation("初期拍子定義が存在しないため、4/4拍子に設定します。");
            }

            var barIndexCalculator = new BarIndexCalculator(TicksPerBeat, TimeSignatureDefinitions);

            var bpmDic = bpmData.SelectMany(p => SplitData(barIndexCalculator, p.LineIndex, int.Parse(p.Value.Groups["barIndex"].Value) + p.BarIndexOffset, p.Value.Groups["data"].Value).Select(q => new { LineIndex = p.LineIndex, Definition = q }))
                         .Where(p =>
            {
                if (p.Definition.Data == "00")
                {
                    return(false);
                }
                if (!BpmDefinitions.ContainsKey(p.Definition.Data.ToLower()))
                {
                    DiagnosticCollector.ReportWarning($"BPM定義番号{p.Definition.Data}は宣言されていません。このBPM変更は無視されます。(行: {p.LineIndex + 1})");
                    return(false);
                }
                return(true);
            })
                         .ToDictionary(p => p.Definition.Tick, p => BpmDefinitions[p.Definition.Data.ToLower()]);

            if (!bpmDic.ContainsKey(0))
            {
                bpmDic.Add(0, 120);
                DiagnosticCollector.ReportInformation("初期BPM定義が存在しないため、120に設定します。");
            }

            // データ種別と位置
            var shortNotes = shortNotesData.GroupBy(p => p.Value.Groups["type"].Value[0]).ToDictionary(p => p.Key, p => p.SelectMany(q =>
            {
                return(SplitData(barIndexCalculator, q.LineIndex, int.Parse(q.Value.Groups["barIndex"].Value) + q.BarIndexOffset, q.Value.Groups["data"].Value)
                       .Where(r => Regex.IsMatch(r.Data, "[1-9][1-9a-g]", RegexOptions.IgnoreCase))
                       .Select(r => new NoteDefinition()
                {
                    LineIndex = q.LineIndex, Type = r.Data[0], Position = new NotePosition()
                    {
                        Tick = r.Tick, LaneIndex = ConvertHex(q.Value.Groups["laneIndex"].Value[0]), Width = ConvertHex(r.Data[1])
                    }
                }));
            }).ToList());

            // ロング種別 -> ロングノーツリスト -> 構成点リスト
            var longNotes = longNotesData.GroupBy(p => p.Value.Groups["type"].Value[0]).ToDictionary(p => p.Key, p =>
            {
                return(p.GroupBy(q => q.Value.Groups["longKey"].Value.ToUpper()).Select(q => q.SelectMany(r =>
                {
                    return SplitData(barIndexCalculator, r.LineIndex, int.Parse(r.Value.Groups["barIndex"].Value) + r.BarIndexOffset, r.Value.Groups["data"].Value)
                    .Where(s => Regex.IsMatch(s.Data, "[1-5][1-9a-g]", RegexOptions.IgnoreCase))
                    .Select(s => new NoteDefinition()
                    {
                        LineIndex = r.LineIndex, Type = s.Data[0], Position = new NotePosition()
                        {
                            Tick = s.Tick, LaneIndex = ConvertHex(r.Value.Groups["laneIndex"].Value[0]), Width = ConvertHex(s.Data[1])
                        }
                    });
                }))
                       .SelectMany(q => p.Key == '2' ? q.GroupBy(r => r.Position.LaneIndex).SelectMany(r => FlatSplitLongNotes(r, '1', '2')) : FlatSplitLongNotes(q, '1', '2'))
                       .ToList());
            });

            foreach (char c in new[] { '1', '5' })
            {
                FillKey(shortNotes, c, new List <NoteDefinition>());
            }

            foreach (char c in new[] { '2', '3', '4', })
            {
                FillKey(longNotes, c, new List <List <NoteDefinition> >());
            }


            return(new SusScoreData()
            {
                TicksPerBeat = this.TicksPerBeat,
                BpmDefinitions = bpmDic,
                TimeSignatures = TimeSignatureDefinitions.ToDictionary(p => barIndexCalculator.GetTickFromBarIndex(p.Key), p => p.Value),
                Title = this.Title,
                ArtistName = this.ArtistName,
                DesignerName = this.DesignerName,
                ShortNotes = shortNotes,
                LongNotes = longNotes
            });
        }